root/net/inet/icmp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. icmp_send
  2. icmp_unreach
  3. icmp_redirect
  4. icmp_echo
  5. icmp_timestamp
  6. icmp_info
  7. icmp_address
  8. icmp_rcv
  9. icmp_ioctl

   1 /*
   2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3  *              operating system.  INET is implemented using the  BSD Socket
   4  *              interface as the means of communication with the user level.
   5  *
   6  *              Internet Control Message Protocol (ICMP)
   7  *
   8  * Version:     @(#)icmp.c      1.0.11  06/02/93
   9  *
  10  * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
  11  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  12  *              Mark Evans, <evansmp@uhura.aston.ac.uk>
  13  *              Alan Cox, <gw4pts@gw4pts.ampr.org>
  14  *
  15  * Fixes:       
  16  *              Alan Cox        :       Generic queue usage.
  17  *              Gerhard Koerting:       ICMP addressing corrected
  18  *              Alan Cox        :       Use tos/ttl settings
  19  *              Alan Cox        :       Protocol violations
  20  *              Alan Cox        :       SNMP Statistics         
  21  *              Alan Cox        :       Routing errors
  22  *              Alan Cox        :       Changes for newer routing code
  23  *              Alan Cox        :       Removed old debugging junk
  24  *              Alan Cox        :       Fixed the ICMP error status of net/host unreachable
  25  *      Gerhard Koerting        :       Fixed broadcast ping properly
  26  *              Ulrich Kunitz   :       Fixed ICMP timestamp reply
  27  *              A.N.Kuznetsov   :       Multihoming fixes.
  28  *              Laco Rusnak     :       Multihoming fixes.
  29  *              Alan Cox        :       Tightened up icmp_send().
  30  *
  31  * 
  32  *
  33  *              This program is free software; you can redistribute it and/or
  34  *              modify it under the terms of the GNU General Public License
  35  *              as published by the Free Software Foundation; either version
  36  *              2 of the License, or (at your option) any later version.
  37  */
  38 #include <linux/types.h>
  39 #include <linux/sched.h>
  40 #include <linux/kernel.h>
  41 #include <linux/fcntl.h>
  42 #include <linux/socket.h>
  43 #include <linux/in.h>
  44 #include <linux/inet.h>
  45 #include <linux/netdevice.h>
  46 #include <linux/string.h>
  47 #include "snmp.h"
  48 #include "ip.h"
  49 #include "route.h"
  50 #include "protocol.h"
  51 #include "icmp.h"
  52 #include "tcp.h"
  53 #include "snmp.h"
  54 #include <linux/skbuff.h>
  55 #include "sock.h"
  56 #include <linux/errno.h>
  57 #include <linux/timer.h>
  58 #include <asm/system.h>
  59 #include <asm/segment.h>
  60 
  61 
  62 #define min(a,b)        ((a)<(b)?(a):(b))
  63 
  64 
  65 /*
  66  *      Statistics
  67  */
  68  
  69 struct icmp_mib icmp_statistics={0,};
  70 
  71 
  72 /* An array of errno for error messages from dest unreach. */
  73 struct icmp_err icmp_err_convert[] = {
  74   { ENETUNREACH,        0 },    /*      ICMP_NET_UNREACH        */
  75   { EHOSTUNREACH,       0 },    /*      ICMP_HOST_UNREACH       */
  76   { ENOPROTOOPT,        1 },    /*      ICMP_PROT_UNREACH       */
  77   { ECONNREFUSED,       1 },    /*      ICMP_PORT_UNREACH       */
  78   { EOPNOTSUPP,         0 },    /*      ICMP_FRAG_NEEDED        */
  79   { EOPNOTSUPP,         0 },    /*      ICMP_SR_FAILED          */
  80   { ENETUNREACH,        1 },    /*      ICMP_NET_UNKNOWN        */
  81   { EHOSTDOWN,          1 },    /*      ICMP_HOST_UNKNOWN       */
  82   { ENONET,             1 },    /*      ICMP_HOST_ISOLATED      */
  83   { ENETUNREACH,        1 },    /*      ICMP_NET_ANO            */
  84   { EHOSTUNREACH,       1 },    /*      ICMP_HOST_ANO           */
  85   { EOPNOTSUPP,         0 },    /*      ICMP_NET_UNR_TOS        */
  86   { EOPNOTSUPP,         0 }     /*      ICMP_HOST_UNR_TOS       */
  87 };
  88 
  89 
  90 /*
  91  *      Send an ICMP message in response to a situation
  92  *
  93  *      Fixme: Fragment handling is wrong really.
  94  */
  95  
  96 void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98         struct sk_buff *skb;
  99         struct iphdr *iph;
 100         int offset;
 101         struct icmphdr *icmph;
 102         int len;
 103         struct device *ndev=NULL;       /* Make this =dev to force replies on the same interface */
 104         unsigned long our_addr;
 105         int atype;
 106         
 107         /*
 108          *      Find the original IP header.
 109          */
 110          
 111         iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
 112         
 113         /*
 114          *      No replies to MAC multicast
 115          */
 116          
 117         if(skb_in->pkt_type!=PACKET_HOST)
 118                 return;
 119                 
 120         /*
 121          *      No replies to IP multicasting
 122          */
 123          
 124         atype=ip_chk_addr(iph->daddr);
 125         if(atype==IS_BROADCAST || IN_MULTICAST(iph->daddr))
 126                 return;
 127 
 128         /*
 129          *      Only reply to first fragment.
 130          */
 131          
 132         if(ntohs(iph->frag_off)&IP_OFFSET)
 133                 return;
 134                         
 135         /*
 136          *      We must NEVER NEVER send an ICMP error to an ICMP error message
 137          */
 138          
 139         if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
 140         {
 141                 if(iph->protocol==IPPROTO_ICMP)
 142                         return;
 143 
 144         }
 145         icmp_statistics.IcmpOutMsgs++;
 146         
 147         /*
 148          *      This needs a tidy.      
 149          */
 150                 
 151         switch(type)
 152         {
 153                 case ICMP_DEST_UNREACH:
 154                         icmp_statistics.IcmpOutDestUnreachs++;
 155                         break;
 156                 case ICMP_SOURCE_QUENCH:
 157                         icmp_statistics.IcmpOutSrcQuenchs++;
 158                         break;
 159                 case ICMP_REDIRECT:
 160                         icmp_statistics.IcmpOutRedirects++;
 161                         break;
 162                 case ICMP_ECHO:
 163                         icmp_statistics.IcmpOutEchos++;
 164                         break;
 165                 case ICMP_ECHOREPLY:
 166                         icmp_statistics.IcmpOutEchoReps++;
 167                         break;
 168                 case ICMP_TIME_EXCEEDED:
 169                         icmp_statistics.IcmpOutTimeExcds++;
 170                         break;
 171                 case ICMP_PARAMETERPROB:
 172                         icmp_statistics.IcmpOutParmProbs++;
 173                         break;
 174                 case ICMP_TIMESTAMP:
 175                         icmp_statistics.IcmpOutTimestamps++;
 176                         break;
 177                 case ICMP_TIMESTAMPREPLY:
 178                         icmp_statistics.IcmpOutTimestampReps++;
 179                         break;
 180                 case ICMP_ADDRESS:
 181                         icmp_statistics.IcmpOutAddrMasks++;
 182                         break;
 183                 case ICMP_ADDRESSREPLY:
 184                         icmp_statistics.IcmpOutAddrMaskReps++;
 185                         break;
 186         }               
 187         /*
 188          *      Get some memory for the reply. 
 189          */
 190          
 191         len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
 192                 sizeof(struct iphdr) + 8;       /* amount of header to return */
 193            
 194         skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
 195         if (skb == NULL) 
 196         {
 197                 icmp_statistics.IcmpOutErrors++;
 198                 return;
 199         }
 200         skb->free = 1;
 201 
 202         /*
 203          *      Build Layer 2-3 headers for message back to source. 
 204          */
 205 
 206         our_addr = dev->pa_addr;
 207         if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
 208                 our_addr = iph->daddr;
 209         offset = ip_build_header(skb, our_addr, iph->saddr,
 210                            &ndev, IPPROTO_ICMP, NULL, len,
 211                            skb_in->ip_hdr->tos,255);
 212         if (offset < 0) 
 213         {
 214                 icmp_statistics.IcmpOutErrors++;
 215                 skb->sk = NULL;
 216                 kfree_skb(skb, FREE_READ);
 217                 return;
 218         }
 219 
 220         /* 
 221          *      Re-adjust length according to actual IP header size. 
 222          */
 223 
 224         skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
 225         
 226         /*
 227          *      Fill in the frame
 228          */
 229          
 230         icmph = (struct icmphdr *) (skb->data + offset);
 231         icmph->type = type;
 232         icmph->code = code;
 233         icmph->checksum = 0;
 234         icmph->un.gateway = 0;
 235         memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
 236 
 237         icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 238                          sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 239 
 240         /*
 241          *      Send it and free it once sent.
 242          */
 243         ip_queue_xmit(NULL, ndev, skb, 1);
 244 }
 245 
 246 
 247 /* 
 248  *      Handle ICMP_UNREACH and ICMP_QUENCH. 
 249  */
 250  
 251 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253         struct inet_protocol *ipprot;
 254         struct iphdr *iph;
 255         unsigned char hash;
 256         int err;
 257 
 258         err = (icmph->type << 8) | icmph->code;
 259         iph = (struct iphdr *) (icmph + 1);
 260         
 261         switch(icmph->code & 7) 
 262         {
 263                 case ICMP_NET_UNREACH:
 264                         break;
 265                 case ICMP_HOST_UNREACH:
 266                         break;
 267                 case ICMP_PROT_UNREACH:
 268                         printk("ICMP: %s:%d: protocol unreachable.\n",
 269                                 in_ntoa(iph->daddr), ntohs(iph->protocol));
 270                         break;
 271                 case ICMP_PORT_UNREACH:
 272                         break;
 273                 case ICMP_FRAG_NEEDED:
 274                         printk("ICMP: %s: fragmentation needed and DF set.\n",
 275                                                                 in_ntoa(iph->daddr));
 276                         break;
 277                 case ICMP_SR_FAILED:
 278                         printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
 279                         break;
 280                 default:
 281                         break;
 282         }
 283 
 284         /*
 285          *      Get the protocol(s). 
 286          */
 287          
 288         hash = iph->protocol & (MAX_INET_PROTOS -1);
 289 
 290         /*
 291          *      This can't change while we are doing it. 
 292          */
 293          
 294         ipprot = (struct inet_protocol *) inet_protos[hash];
 295         while(ipprot != NULL) 
 296         {
 297                 struct inet_protocol *nextip;
 298 
 299                 nextip = (struct inet_protocol *) ipprot->next;
 300         
 301                 /* 
 302                  *      Pass it off to everyone who wants it. 
 303                  */
 304                 if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 305                 {
 306                         ipprot->err_handler(err, (unsigned char *)(icmph + 1),
 307                                             iph->daddr, iph->saddr, ipprot);
 308                 }
 309 
 310                 ipprot = nextip;
 311         }
 312         kfree_skb(skb, FREE_READ);
 313 }
 314 
 315 
 316 /*
 317  *      Handle ICMP_REDIRECT. 
 318  */
 319 
 320 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
     /* [previous][next][first][last][top][bottom][index][help] */
 321         struct device *dev, unsigned long source)
 322 {
 323         struct rtable *rt;
 324         struct iphdr *iph;
 325         unsigned long ip;
 326 
 327         /*
 328          *      Get the copied header of the packet that caused the redirect
 329          */
 330          
 331         iph = (struct iphdr *) (icmph + 1);
 332         ip = iph->daddr;
 333 
 334         switch(icmph->code & 7) 
 335         {
 336                 case ICMP_REDIR_NET:
 337                         /*
 338                          *      This causes a problem with subnetted networks. What we should do
 339                          *      is use ICMP_ADDRESS to get the subnet mask of the problem route
 340                          *      and set both. But we don't..
 341                          */
 342 #ifdef not_a_good_idea
 343                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 344                                 ip, 0, icmph->un.gateway, dev,0, 0);
 345                         break;
 346 #endif
 347                 case ICMP_REDIR_HOST:
 348                         /*
 349                          *      Add better route to host.
 350                          *      But first check that the redirect
 351                          *      comes from the old gateway..
 352                          */
 353                         rt = ip_rt_route(ip, NULL, NULL);
 354                         if (!rt)
 355                                 break;
 356                         if (rt->rt_gateway != source)
 357                                 break;
 358                         printk("redirect from %s\n", in_ntoa(source));
 359                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 360                                 ip, 0, icmph->un.gateway, dev,0, 0);
 361                         break;
 362                 case ICMP_REDIR_NETTOS:
 363                 case ICMP_REDIR_HOSTTOS:
 364                         printk("ICMP: cannot handle TOS redirects yet!\n");
 365                         break;
 366                 default:
 367                         break;
 368         }
 369         
 370         /*
 371          *      Discard the original packet
 372          */
 373          
 374         kfree_skb(skb, FREE_READ);
 375 }
 376 
 377 
 378 /*
 379  *      Handle ICMP_ECHO ("ping") requests. 
 380  */
 381  
 382 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 383           unsigned long saddr, unsigned long daddr, int len,
 384           struct options *opt)
 385 {
 386         struct icmphdr *icmphr;
 387         struct sk_buff *skb2;
 388         struct device *ndev=NULL;
 389         int size, offset;
 390 
 391         icmp_statistics.IcmpOutEchoReps++;
 392         icmp_statistics.IcmpOutMsgs++;
 393         
 394         size = dev->hard_header_len + 64 + len;
 395         skb2 = alloc_skb(size, GFP_ATOMIC);
 396 
 397         if (skb2 == NULL) 
 398         {
 399                 icmp_statistics.IcmpOutErrors++;
 400                 kfree_skb(skb, FREE_READ);
 401                 return;
 402         }
 403         skb2->free = 1;
 404 
 405         /* Build Layer 2-3 headers for message back to source */
 406         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 407                 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 408         if (offset < 0) 
 409         {
 410                 icmp_statistics.IcmpOutErrors++;
 411                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 412                 kfree_skb(skb2,FREE_WRITE);
 413                 kfree_skb(skb, FREE_READ);
 414                 return;
 415         }
 416 
 417         /*
 418          *      Re-adjust length according to actual IP header size. 
 419          */
 420          
 421         skb2->len = offset + len;
 422 
 423         /*
 424          *      Build ICMP_ECHO Response message. 
 425          */
 426         icmphr = (struct icmphdr *) (skb2->data + offset);
 427         memcpy((char *) icmphr, (char *) icmph, len);
 428         icmphr->type = ICMP_ECHOREPLY;
 429         icmphr->code = 0;
 430         icmphr->checksum = 0;
 431         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 432 
 433         /*
 434          *      Ship it out - free it when done 
 435          */
 436         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 437 
 438         /*
 439          *      Free the received frame
 440          */
 441          
 442         kfree_skb(skb, FREE_READ);
 443 }
 444 
 445 /*
 446  *      Handle ICMP Timestamp requests. 
 447  */
 448  
 449 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 450           unsigned long saddr, unsigned long daddr, int len,
 451           struct options *opt)
 452 {
 453         struct icmphdr *icmphr;
 454         struct sk_buff *skb2;
 455         int size, offset;
 456         unsigned long *timeptr, midtime;
 457         struct device *ndev=NULL;
 458 
 459         if (len != 20)
 460         {
 461                 printk(
 462                   "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
 463                   len);
 464                 icmp_statistics.IcmpInErrors++;         
 465 #if 1
 466                 /* correct answers are possible for everything >= 12 */
 467                 if (len < 12)
 468 #endif
 469                         return;
 470         }
 471 
 472         size = dev->hard_header_len + 84;
 473 
 474         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 475         {
 476                 skb->sk = NULL;
 477                 kfree_skb(skb, FREE_READ);
 478                 icmp_statistics.IcmpOutErrors++;                
 479                 return;
 480         }
 481         skb2->free = 1;
 482  
 483 /*
 484  *      Build Layer 2-3 headers for message back to source 
 485  */
 486  
 487         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 488                                 skb->ip_hdr->tos, 255);
 489         if (offset < 0) 
 490         {
 491                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 492                 kfree_skb(skb2, FREE_WRITE);
 493                 kfree_skb(skb, FREE_READ);
 494                 icmp_statistics.IcmpOutErrors++;
 495                 return;
 496         }
 497  
 498         /*
 499          *      Re-adjust length according to actual IP header size. 
 500          */
 501         skb2->len = offset + 20;
 502  
 503         /*
 504          *      Build ICMP_TIMESTAMP Response message. 
 505          */
 506 
 507         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 508         memcpy((char *) icmphr, (char *) icmph, 12);
 509         icmphr->type = ICMP_TIMESTAMPREPLY;
 510         icmphr->code = icmphr->checksum = 0;
 511 
 512         /* fill in the current time as ms since midnight UT: */
 513         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 514         timeptr = (unsigned long *) (icmphr + 1);
 515         /*
 516          *      the originate timestamp (timeptr [0]) is still in the copy: 
 517          */
 518         timeptr [1] = timeptr [2] = htonl(midtime);
 519 
 520         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
 521 
 522         /*
 523          *      Ship it out - free it when done 
 524          */
 525 
 526         ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
 527         icmp_statistics.IcmpOutTimestampReps++;
 528         kfree_skb(skb, FREE_READ);
 529 }
 530  
 531  
 532 
 533 
 534 /*
 535  *      Handle the ICMP INFORMATION REQUEST. 
 536  */
 537  
 538 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 539           unsigned long saddr, unsigned long daddr, int len,
 540           struct options *opt)
 541 {
 542         /* Obsolete */
 543         kfree_skb(skb, FREE_READ);
 544 }
 545 
 546 
 547 /* 
 548  *      Handle ICMP_ADDRESS_MASK requests. 
 549  */
 550  
 551 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 552           unsigned long saddr, unsigned long daddr, int len,
 553           struct options *opt)
 554 {
 555         struct icmphdr *icmphr;
 556         struct sk_buff *skb2;
 557         int size, offset;
 558         struct device *ndev=NULL;
 559 
 560         icmp_statistics.IcmpOutMsgs++;
 561         icmp_statistics.IcmpOutAddrMaskReps++;
 562         
 563         size = dev->hard_header_len + 64 + len;
 564         skb2 = alloc_skb(size, GFP_ATOMIC);
 565         if (skb2 == NULL) 
 566         {
 567                 icmp_statistics.IcmpOutErrors++;
 568                 kfree_skb(skb, FREE_READ);
 569                 return;
 570         }
 571         skb2->free = 1;
 572         
 573         /* 
 574          *      Build Layer 2-3 headers for message back to source 
 575          */
 576 
 577         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 578                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 579         if (offset < 0) 
 580         {
 581                 icmp_statistics.IcmpOutErrors++;
 582                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 583                 kfree_skb(skb2,FREE_WRITE);
 584                 kfree_skb(skb, FREE_READ);
 585                 return;
 586         }
 587 
 588         /*
 589          *      Re-adjust length according to actual IP header size. 
 590          */
 591 
 592         skb2->len = offset + len;
 593 
 594         /*
 595          *      Build ICMP ADDRESS MASK Response message. 
 596          */
 597 
 598         icmphr = (struct icmphdr *) (skb2->data + offset);
 599         icmphr->type = ICMP_ADDRESSREPLY;
 600         icmphr->code = 0;
 601         icmphr->checksum = 0;
 602         icmphr->un.echo.id = icmph->un.echo.id;
 603         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 604         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 605 
 606         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 607 
 608         /* Ship it out - free it when done */
 609         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 610 
 611         skb->sk = NULL;
 612         kfree_skb(skb, FREE_READ);
 613 }
 614 
 615 
 616 /* 
 617  *      Deal with incoming ICMP packets. 
 618  */
 619  
 620 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 621          unsigned long daddr, unsigned short len,
 622          unsigned long saddr, int redo, struct inet_protocol *protocol)
 623 {
 624         struct icmphdr *icmph;
 625         unsigned char *buff;
 626 
 627         /*
 628          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 629          *      to pass on that information.
 630          */
 631         
 632         icmp_statistics.IcmpInMsgs++;
 633          
 634         
 635         /*
 636          *      Grab the packet as an icmp object
 637          */
 638 
 639         buff = skb1->h.raw;
 640         icmph = (struct icmphdr *) buff;
 641 
 642         /*
 643          *      Validate the packet first 
 644          */
 645 
 646         if (ip_compute_csum((unsigned char *) icmph, len)) 
 647         {
 648                 /* Failed checksum! */
 649                 icmp_statistics.IcmpInErrors++;
 650                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 651                 kfree_skb(skb1, FREE_READ);
 652                 return(0);
 653         }
 654 
 655         /*
 656          *      Parse the ICMP message 
 657          */
 658 
 659         if (ip_chk_addr(daddr) == IS_BROADCAST)
 660         {
 661                 if (icmph->type != ICMP_ECHO) 
 662                 {
 663                         icmp_statistics.IcmpInErrors++;
 664                         kfree_skb(skb1, FREE_READ);
 665                         return(0);
 666                 }
 667                 daddr=dev->pa_addr;
 668         }
 669 
 670         switch(icmph->type) 
 671         {
 672                 case ICMP_TIME_EXCEEDED:
 673                         icmp_statistics.IcmpInTimeExcds++;
 674                         icmp_unreach(icmph, skb1);
 675                         return 0;
 676                 case ICMP_DEST_UNREACH:
 677                         icmp_statistics.IcmpInDestUnreachs++;
 678                         icmp_unreach(icmph, skb1);
 679                         return 0;
 680                 case ICMP_SOURCE_QUENCH:
 681                         icmp_statistics.IcmpInSrcQuenchs++;
 682                         icmp_unreach(icmph, skb1);
 683                         return(0);
 684                 case ICMP_REDIRECT:
 685                         icmp_statistics.IcmpInRedirects++;
 686                         icmp_redirect(icmph, skb1, dev, saddr);
 687                         return(0);
 688                 case ICMP_ECHO: 
 689                         icmp_statistics.IcmpInEchos++;
 690                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 691                         return 0;
 692                 case ICMP_ECHOREPLY:
 693                         icmp_statistics.IcmpInEchoReps++;
 694                         kfree_skb(skb1, FREE_READ);
 695                         return(0);
 696                 case ICMP_TIMESTAMP:
 697                         icmp_statistics.IcmpInTimestamps++;
 698                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 699                         return 0;
 700                 case ICMP_TIMESTAMPREPLY:
 701                         icmp_statistics.IcmpInTimestampReps++;
 702                         kfree_skb(skb1,FREE_READ);
 703                         return 0;
 704                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 705                 case ICMP_INFO_REQUEST:
 706                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 707                         return 0;
 708                 case ICMP_INFO_REPLY:
 709                         skb1->sk = NULL;
 710                         kfree_skb(skb1, FREE_READ);
 711                         return(0);
 712                 case ICMP_ADDRESS:
 713                         icmp_statistics.IcmpInAddrMasks++;
 714                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 715                         return 0;
 716                 case ICMP_ADDRESSREPLY:
 717                         /*
 718                          *      We ought to set our netmask on receiving this, but 
 719                          *      experience shows its a waste of effort.
 720                          */
 721                         icmp_statistics.IcmpInAddrMaskReps++;
 722                         kfree_skb(skb1, FREE_READ);
 723                         return(0);
 724                 default:
 725                         icmp_statistics.IcmpInErrors++;
 726                         kfree_skb(skb1, FREE_READ);
 727                         return(0);
 728         }
 729   /*NOTREACHED*/
 730         kfree_skb(skb1, FREE_READ);
 731         return(-1);
 732 }
 733 
 734 
 735 /*
 736  *      Perform any ICMP-related I/O control requests. 
 737  *      [to vanish soon]
 738  */
 739  
 740 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 741 {
 742         switch(cmd) 
 743         {
 744                 default:
 745                         return(-EINVAL);
 746         }
 747         return(0);
 748 }

/* [previous][next][first][last][top][bottom][index][help] */