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

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