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

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