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

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