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 %s\n", in_ntoa(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         struct device *ndev=NULL;
 427  
 428         size = dev->hard_header_len + 64 + len;
 429 
 430         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 431         {
 432                 skb->sk = NULL;
 433                 kfree_skb(skb, FREE_READ);
 434                 icmp_statistics.IcmpOutErrors++;                
 435                 return;
 436         }
 437         skb2->free = 1;
 438  
 439 /*
 440  *      Build Layer 2-3 headers for message back to source 
 441  */
 442  
 443         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 444                                 skb->ip_hdr->tos, 255);
 445         if (offset < 0) 
 446         {
 447                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 448                 kfree_skb(skb2, FREE_WRITE);
 449                 kfree_skb(skb, FREE_READ);
 450                 icmp_statistics.IcmpOutErrors++;
 451                 return;
 452         }
 453  
 454         /*
 455          *      Re-adjust length according to actual IP header size. 
 456          */
 457         skb2->len = offset + len;
 458  
 459         /*
 460          *      Build ICMP_TIMESTAMP Response message. 
 461          */
 462 
 463         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 464         memcpy((char *) icmphr, (char *) icmph, len);
 465         icmphr->type = ICMP_TIMESTAMPREPLY;
 466         icmphr->code = icmphr->checksum = 0;
 467 
 468         /* fill in the current time as ms since midnight UT: */
 469         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 470         timeptr = (unsigned long *) (icmphr + 1);
 471         /*
 472          *      the originate timestamp (timeptr [0]) is still in the copy: 
 473          */
 474         timeptr [1] = timeptr [2] = htonl(midtime);
 475 
 476         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len);
 477 
 478         /*
 479          *      Ship it out - free it when done 
 480          */
 481 
 482         ip_queue_xmit((struct sock *) NULL, dev, skb2, 1);
 483         icmp_statistics.IcmpOutTimestampReps++;
 484         kfree_skb(skb, FREE_READ);
 485 }
 486  
 487  
 488 
 489 
 490 /*
 491  *      Handle the ICMP INFORMATION REQUEST. 
 492  */
 493  
 494 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 495           unsigned long saddr, unsigned long daddr, int len,
 496           struct options *opt)
 497 {
 498         /* Obsolete */
 499         kfree_skb(skb, FREE_READ);
 500 }
 501 
 502 
 503 /* 
 504  *      Handle ICMP_ADDRESS_MASK requests. 
 505  */
 506  
 507 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 508           unsigned long saddr, unsigned long daddr, int len,
 509           struct options *opt)
 510 {
 511         struct icmphdr *icmphr;
 512         struct sk_buff *skb2;
 513         int size, offset;
 514         struct device *ndev=NULL;
 515 
 516         icmp_statistics.IcmpOutMsgs++;
 517         icmp_statistics.IcmpOutAddrMaskReps++;
 518         
 519         size = dev->hard_header_len + 64 + len;
 520         skb2 = alloc_skb(size, GFP_ATOMIC);
 521         if (skb2 == NULL) 
 522         {
 523                 icmp_statistics.IcmpOutErrors++;
 524                 kfree_skb(skb, FREE_READ);
 525                 return;
 526         }
 527         skb2->free = 1;
 528         
 529         /* 
 530          *      Build Layer 2-3 headers for message back to source 
 531          */
 532 
 533         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 534                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 535         if (offset < 0) 
 536         {
 537                 icmp_statistics.IcmpOutErrors++;
 538                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 539                 kfree_skb(skb2,FREE_WRITE);
 540                 kfree_skb(skb, FREE_READ);
 541                 return;
 542         }
 543 
 544         /*
 545          *      Re-adjust length according to actual IP header size. 
 546          */
 547 
 548         skb2->len = offset + len;
 549 
 550         /*
 551          *      Build ICMP ADDRESS MASK Response message. 
 552          */
 553 
 554         icmphr = (struct icmphdr *) (skb2->data + offset);
 555         icmphr->type = ICMP_ADDRESSREPLY;
 556         icmphr->code = 0;
 557         icmphr->checksum = 0;
 558         icmphr->un.echo.id = icmph->un.echo.id;
 559         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 560         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 561 
 562         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 563 
 564         /* Ship it out - free it when done */
 565         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 566 
 567         skb->sk = NULL;
 568         kfree_skb(skb, FREE_READ);
 569 }
 570 
 571 
 572 /* 
 573  *      Deal with incoming ICMP packets. 
 574  */
 575  
 576 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 577          unsigned long daddr, unsigned short len,
 578          unsigned long saddr, int redo, struct inet_protocol *protocol)
 579 {
 580         struct icmphdr *icmph;
 581         unsigned char *buff;
 582 
 583         /*
 584          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 585          *      to pass on that information.
 586          */
 587         
 588         icmp_statistics.IcmpInMsgs++;
 589          
 590         
 591         /*
 592          *      Grab the packet as an icmp object
 593          */
 594 
 595         buff = skb1->h.raw;
 596         icmph = (struct icmphdr *) buff;
 597 
 598         /*
 599          *      Validate the packet first 
 600          */
 601 
 602         if (ip_compute_csum((unsigned char *) icmph, len)) 
 603         {
 604                 /* Failed checksum! */
 605                 icmp_statistics.IcmpInErrors++;
 606                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 607                 kfree_skb(skb1, FREE_READ);
 608                 return(0);
 609         }
 610 
 611         /*
 612          *      Parse the ICMP message 
 613          */
 614 
 615         if (ip_chk_addr(daddr) == IS_BROADCAST)
 616         {
 617                 if (icmph->type != ICMP_ECHO) 
 618                 {
 619                         icmp_statistics.IcmpInErrors++;
 620                         kfree_skb(skb1, FREE_READ);
 621                         return(0);
 622                 }
 623                 daddr=dev->pa_addr;
 624         }
 625 
 626         switch(icmph->type) 
 627         {
 628                 case ICMP_TIME_EXCEEDED:
 629                         icmp_statistics.IcmpInTimeExcds++;
 630                         icmp_unreach(icmph, skb1);
 631                         return 0;
 632                 case ICMP_DEST_UNREACH:
 633                         icmp_statistics.IcmpInDestUnreachs++;
 634                         icmp_unreach(icmph, skb1);
 635                         return 0;
 636                 case ICMP_SOURCE_QUENCH:
 637                         icmp_statistics.IcmpInSrcQuenchs++;
 638                         icmp_unreach(icmph, skb1);
 639                         return(0);
 640                 case ICMP_REDIRECT:
 641                         icmp_statistics.IcmpInRedirects++;
 642                         icmp_redirect(icmph, skb1, dev, saddr);
 643                         return(0);
 644                 case ICMP_ECHO: 
 645                         icmp_statistics.IcmpInEchos++;
 646                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 647                         return 0;
 648                 case ICMP_ECHOREPLY:
 649                         icmp_statistics.IcmpInEchoReps++;
 650                         kfree_skb(skb1, FREE_READ);
 651                         return(0);
 652                 case ICMP_TIMESTAMP:
 653                         icmp_statistics.IcmpInTimestamps++;
 654                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 655                         return 0;
 656                 case ICMP_TIMESTAMPREPLY:
 657                         icmp_statistics.IcmpInTimestampReps++;
 658                         kfree_skb(skb1,FREE_READ);
 659                         return 0;
 660                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 661                 case ICMP_INFO_REQUEST:
 662                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 663                         return 0;
 664                 case ICMP_INFO_REPLY:
 665                         skb1->sk = NULL;
 666                         kfree_skb(skb1, FREE_READ);
 667                         return(0);
 668                 case ICMP_ADDRESS:
 669                         icmp_statistics.IcmpInAddrMasks++;
 670                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 671                         return 0;
 672                 case ICMP_ADDRESSREPLY:
 673                         /*
 674                          *      We ought to set our netmask on receiving this, but 
 675                          *      experience shows its a waste of effort.
 676                          */
 677                         icmp_statistics.IcmpInAddrMaskReps++;
 678                         kfree_skb(skb1, FREE_READ);
 679                         return(0);
 680                 default:
 681                         icmp_statistics.IcmpInErrors++;
 682                         kfree_skb(skb1, FREE_READ);
 683                         return(0);
 684         }
 685   /*NOTREACHED*/
 686         kfree_skb(skb1, FREE_READ);
 687         return(-1);
 688 }
 689 
 690 
 691 /*
 692  *      Perform any ICMP-related I/O control requests. 
 693  *      [to vanish soon]
 694  */
 695  
 696 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 697 {
 698         switch(cmd) 
 699         {
 700                 default:
 701                         return(-EINVAL);
 702         }
 703         return(0);
 704 }

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