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

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