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

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