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) + 8;       /* 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                          */
 376                         rt = ip_rt_route(ip, NULL, NULL);
 377                         if (!rt)
 378                                 break;
 379                         if (rt->rt_gateway != source)
 380                                 break;
 381                         printk("redirect from %s\n", in_ntoa(source));
 382                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 383                                 ip, 0, icmph->un.gateway, dev,0, 0);
 384                         break;
 385                 case ICMP_REDIR_NETTOS:
 386                 case ICMP_REDIR_HOSTTOS:
 387                         printk("ICMP: cannot handle TOS redirects yet!\n");
 388                         break;
 389                 default:
 390                         break;
 391         }
 392         
 393         /*
 394          *      Discard the original packet
 395          */
 396          
 397         kfree_skb(skb, FREE_READ);
 398 }
 399 
 400 
 401 /*
 402  *      Handle ICMP_ECHO ("ping") requests. 
 403  */
 404  
 405 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 406           unsigned long saddr, unsigned long daddr, int len,
 407           struct options *opt)
 408 {
 409         struct icmphdr *icmphr;
 410         struct sk_buff *skb2;
 411         struct device *ndev=NULL;
 412         int size, offset;
 413 
 414         icmp_statistics.IcmpOutEchoReps++;
 415         icmp_statistics.IcmpOutMsgs++;
 416         
 417         size = dev->hard_header_len + 64 + len;
 418         skb2 = alloc_skb(size, GFP_ATOMIC);
 419 
 420         if (skb2 == NULL) 
 421         {
 422                 icmp_statistics.IcmpOutErrors++;
 423                 kfree_skb(skb, FREE_READ);
 424                 return;
 425         }
 426         skb2->free = 1;
 427 
 428         /* Build Layer 2-3 headers for message back to source */
 429         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 430                 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 431         if (offset < 0) 
 432         {
 433                 icmp_statistics.IcmpOutErrors++;
 434                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 435                 kfree_skb(skb2,FREE_WRITE);
 436                 kfree_skb(skb, FREE_READ);
 437                 return;
 438         }
 439 
 440         /*
 441          *      Re-adjust length according to actual IP header size. 
 442          */
 443          
 444         skb2->len = offset + len;
 445 
 446         /*
 447          *      Build ICMP_ECHO Response message. 
 448          */
 449         icmphr = (struct icmphdr *) (skb2->data + offset);
 450         memcpy((char *) icmphr, (char *) icmph, len);
 451         icmphr->type = ICMP_ECHOREPLY;
 452         icmphr->code = 0;
 453         icmphr->checksum = 0;
 454         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 455 
 456         /*
 457          *      Ship it out - free it when done 
 458          */
 459         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 460 
 461         /*
 462          *      Free the received frame
 463          */
 464          
 465         kfree_skb(skb, FREE_READ);
 466 }
 467 
 468 /*
 469  *      Handle ICMP Timestamp requests. 
 470  */
 471  
 472 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 473           unsigned long saddr, unsigned long daddr, int len,
 474           struct options *opt)
 475 {
 476         struct icmphdr *icmphr;
 477         struct sk_buff *skb2;
 478         int size, offset;
 479         unsigned long *timeptr, midtime;
 480         struct device *ndev=NULL;
 481 
 482         if (len != 20)
 483         {
 484                 printk(
 485                   "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
 486                   len);
 487                 icmp_statistics.IcmpInErrors++;         
 488 #if 1
 489                 /* correct answers are possible for everything >= 12 */
 490                 if (len < 12)
 491 #endif
 492                         return;
 493         }
 494 
 495         size = dev->hard_header_len + 84;
 496 
 497         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 498         {
 499                 skb->sk = NULL;
 500                 kfree_skb(skb, FREE_READ);
 501                 icmp_statistics.IcmpOutErrors++;                
 502                 return;
 503         }
 504         skb2->free = 1;
 505  
 506 /*
 507  *      Build Layer 2-3 headers for message back to source 
 508  */
 509  
 510         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 511                                 skb->ip_hdr->tos, 255);
 512         if (offset < 0) 
 513         {
 514                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 515                 kfree_skb(skb2, FREE_WRITE);
 516                 kfree_skb(skb, FREE_READ);
 517                 icmp_statistics.IcmpOutErrors++;
 518                 return;
 519         }
 520  
 521         /*
 522          *      Re-adjust length according to actual IP header size. 
 523          */
 524         skb2->len = offset + 20;
 525  
 526         /*
 527          *      Build ICMP_TIMESTAMP Response message. 
 528          */
 529 
 530         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 531         memcpy((char *) icmphr, (char *) icmph, 12);
 532         icmphr->type = ICMP_TIMESTAMPREPLY;
 533         icmphr->code = icmphr->checksum = 0;
 534 
 535         /* fill in the current time as ms since midnight UT: */
 536         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 537         timeptr = (unsigned long *) (icmphr + 1);
 538         /*
 539          *      the originate timestamp (timeptr [0]) is still in the copy: 
 540          */
 541         timeptr [1] = timeptr [2] = htonl(midtime);
 542 
 543         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
 544 
 545         /*
 546          *      Ship it out - free it when done 
 547          */
 548 
 549         ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
 550         icmp_statistics.IcmpOutTimestampReps++;
 551         kfree_skb(skb, FREE_READ);
 552 }
 553  
 554  
 555 
 556 
 557 /*
 558  *      Handle the ICMP INFORMATION REQUEST. 
 559  */
 560  
 561 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 562           unsigned long saddr, unsigned long daddr, int len,
 563           struct options *opt)
 564 {
 565         /* Obsolete */
 566         kfree_skb(skb, FREE_READ);
 567 }
 568 
 569 
 570 /* 
 571  *      Handle ICMP_ADDRESS_MASK requests. 
 572  */
 573  
 574 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 575           unsigned long saddr, unsigned long daddr, int len,
 576           struct options *opt)
 577 {
 578         struct icmphdr *icmphr;
 579         struct sk_buff *skb2;
 580         int size, offset;
 581         struct device *ndev=NULL;
 582 
 583         icmp_statistics.IcmpOutMsgs++;
 584         icmp_statistics.IcmpOutAddrMaskReps++;
 585         
 586         size = dev->hard_header_len + 64 + len;
 587         skb2 = alloc_skb(size, GFP_ATOMIC);
 588         if (skb2 == NULL) 
 589         {
 590                 icmp_statistics.IcmpOutErrors++;
 591                 kfree_skb(skb, FREE_READ);
 592                 return;
 593         }
 594         skb2->free = 1;
 595         
 596         /* 
 597          *      Build Layer 2-3 headers for message back to source 
 598          */
 599 
 600         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 601                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 602         if (offset < 0) 
 603         {
 604                 icmp_statistics.IcmpOutErrors++;
 605                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 606                 kfree_skb(skb2,FREE_WRITE);
 607                 kfree_skb(skb, FREE_READ);
 608                 return;
 609         }
 610 
 611         /*
 612          *      Re-adjust length according to actual IP header size. 
 613          */
 614 
 615         skb2->len = offset + len;
 616 
 617         /*
 618          *      Build ICMP ADDRESS MASK Response message. 
 619          */
 620 
 621         icmphr = (struct icmphdr *) (skb2->data + offset);
 622         icmphr->type = ICMP_ADDRESSREPLY;
 623         icmphr->code = 0;
 624         icmphr->checksum = 0;
 625         icmphr->un.echo.id = icmph->un.echo.id;
 626         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 627         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 628 
 629         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 630 
 631         /* Ship it out - free it when done */
 632         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 633 
 634         skb->sk = NULL;
 635         kfree_skb(skb, FREE_READ);
 636 }
 637 
 638 
 639 /* 
 640  *      Deal with incoming ICMP packets. 
 641  */
 642  
 643 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 644          unsigned long daddr, unsigned short len,
 645          unsigned long saddr, int redo, struct inet_protocol *protocol)
 646 {
 647         struct icmphdr *icmph;
 648         unsigned char *buff;
 649 
 650         /*
 651          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 652          *      to pass on that information.
 653          */
 654         
 655         icmp_statistics.IcmpInMsgs++;
 656          
 657         
 658         /*
 659          *      Grab the packet as an icmp object
 660          */
 661 
 662         buff = skb1->h.raw;
 663         icmph = (struct icmphdr *) buff;
 664 
 665         /*
 666          *      Validate the packet first 
 667          */
 668 
 669         if (ip_compute_csum((unsigned char *) icmph, len)) 
 670         {
 671                 /* Failed checksum! */
 672                 icmp_statistics.IcmpInErrors++;
 673                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 674                 kfree_skb(skb1, FREE_READ);
 675                 return(0);
 676         }
 677 
 678         /*
 679          *      Parse the ICMP message 
 680          */
 681 
 682         if (ip_chk_addr(daddr) != IS_MYADDR)
 683         {
 684                 if (icmph->type != ICMP_ECHO) 
 685                 {
 686                         icmp_statistics.IcmpInErrors++;
 687                         kfree_skb(skb1, FREE_READ);
 688                         return(0);
 689                 }
 690                 daddr=dev->pa_addr;
 691         }
 692 
 693         switch(icmph->type) 
 694         {
 695                 case ICMP_TIME_EXCEEDED:
 696                         icmp_statistics.IcmpInTimeExcds++;
 697                         icmp_unreach(icmph, skb1);
 698                         return 0;
 699                 case ICMP_DEST_UNREACH:
 700                         icmp_statistics.IcmpInDestUnreachs++;
 701                         icmp_unreach(icmph, skb1);
 702                         return 0;
 703                 case ICMP_SOURCE_QUENCH:
 704                         icmp_statistics.IcmpInSrcQuenchs++;
 705                         icmp_unreach(icmph, skb1);
 706                         return(0);
 707                 case ICMP_REDIRECT:
 708                         icmp_statistics.IcmpInRedirects++;
 709                         icmp_redirect(icmph, skb1, dev, saddr);
 710                         return(0);
 711                 case ICMP_ECHO: 
 712                         icmp_statistics.IcmpInEchos++;
 713                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 714                         return 0;
 715                 case ICMP_ECHOREPLY:
 716                         icmp_statistics.IcmpInEchoReps++;
 717                         kfree_skb(skb1, FREE_READ);
 718                         return(0);
 719                 case ICMP_TIMESTAMP:
 720                         icmp_statistics.IcmpInTimestamps++;
 721                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 722                         return 0;
 723                 case ICMP_TIMESTAMPREPLY:
 724                         icmp_statistics.IcmpInTimestampReps++;
 725                         kfree_skb(skb1,FREE_READ);
 726                         return 0;
 727                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 728                 case ICMP_INFO_REQUEST:
 729                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 730                         return 0;
 731                 case ICMP_INFO_REPLY:
 732                         skb1->sk = NULL;
 733                         kfree_skb(skb1, FREE_READ);
 734                         return(0);
 735                 case ICMP_ADDRESS:
 736                         icmp_statistics.IcmpInAddrMasks++;
 737                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 738                         return 0;
 739                 case ICMP_ADDRESSREPLY:
 740                         /*
 741                          *      We ought to set our netmask on receiving this, but 
 742                          *      experience shows its a waste of effort.
 743                          */
 744                         icmp_statistics.IcmpInAddrMaskReps++;
 745                         kfree_skb(skb1, FREE_READ);
 746                         return(0);
 747                 default:
 748                         icmp_statistics.IcmpInErrors++;
 749                         kfree_skb(skb1, FREE_READ);
 750                         return(0);
 751         }
 752   /*NOTREACHED*/
 753         kfree_skb(skb1, FREE_READ);
 754         return(-1);
 755 }
 756 
 757 
 758 /*
 759  *      Perform any ICMP-related I/O control requests. 
 760  *      [to vanish soon]
 761  */
 762  
 763 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 764 {
 765         switch(cmd) 
 766         {
 767                 default:
 768                         return(-EINVAL);
 769         }
 770         return(0);
 771 }

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