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

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