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         { unsigned long our_addr = dev->pa_addr;
 180         if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
 181                 our_addr = iph->daddr;
 182         offset = ip_build_header(skb, our_addr, iph->saddr,
 183                            &ndev, IPPROTO_ICMP, NULL, len,
 184                            skb_in->ip_hdr->tos,255);
 185         }
 186 
 187         if (offset < 0) 
 188         {
 189                 icmp_statistics.IcmpOutErrors++;
 190                 skb->sk = NULL;
 191                 kfree_skb(skb, FREE_READ);
 192                 return;
 193         }
 194 
 195         /* 
 196          *      Re-adjust length according to actual IP header size. 
 197          */
 198 
 199         skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
 200         
 201         /*
 202          *      Fill in the frame
 203          */
 204          
 205         icmph = (struct icmphdr *) (skb->data + offset);
 206         icmph->type = type;
 207         icmph->code = code;
 208         icmph->checksum = 0;
 209         icmph->un.gateway = 0;
 210         memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
 211 
 212         icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 213                          sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 214 
 215         /*
 216          *      Send it and free it once sent.
 217          */
 218         ip_queue_xmit(NULL, ndev, skb, 1);
 219 }
 220 
 221 
 222 /* 
 223  *      Handle ICMP_UNREACH and ICMP_QUENCH. 
 224  */
 225  
 226 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         struct inet_protocol *ipprot;
 229         struct iphdr *iph;
 230         unsigned char hash;
 231         int err;
 232 
 233         err = (icmph->type << 8) | icmph->code;
 234         iph = (struct iphdr *) (icmph + 1);
 235         
 236         switch(icmph->code & 7) 
 237         {
 238                 case ICMP_NET_UNREACH:
 239                         break;
 240                 case ICMP_HOST_UNREACH:
 241                         break;
 242                 case ICMP_PROT_UNREACH:
 243                         printk("ICMP: %s:%d: protocol unreachable.\n",
 244                                 in_ntoa(iph->daddr), ntohs(iph->protocol));
 245                         break;
 246                 case ICMP_PORT_UNREACH:
 247                         break;
 248                 case ICMP_FRAG_NEEDED:
 249                         printk("ICMP: %s: fragmentation needed and DF set.\n",
 250                                                                 in_ntoa(iph->daddr));
 251                         break;
 252                 case ICMP_SR_FAILED:
 253                         printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
 254                         break;
 255                 default:
 256                         break;
 257         }
 258 
 259         /*
 260          *      Get the protocol(s). 
 261          */
 262          
 263         hash = iph->protocol & (MAX_INET_PROTOS -1);
 264 
 265         /*
 266          *      This can't change while we are doing it. 
 267          */
 268          
 269         ipprot = (struct inet_protocol *) inet_protos[hash];
 270         while(ipprot != NULL) 
 271         {
 272                 struct inet_protocol *nextip;
 273 
 274                 nextip = (struct inet_protocol *) ipprot->next;
 275         
 276                 /* 
 277                  *      Pass it off to everyone who wants it. 
 278                  */
 279                 if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 280                 {
 281                         ipprot->err_handler(err, (unsigned char *)(icmph + 1),
 282                                             iph->daddr, iph->saddr, ipprot);
 283                 }
 284 
 285                 ipprot = nextip;
 286         }
 287         kfree_skb(skb, FREE_READ);
 288 }
 289 
 290 
 291 /*
 292  *      Handle ICMP_REDIRECT. 
 293  */
 294 
 295 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
     /* [previous][next][first][last][top][bottom][index][help] */
 296         struct device *dev, unsigned long source)
 297 {
 298         struct rtable *rt;
 299         struct iphdr *iph;
 300         unsigned long ip;
 301 
 302         /*
 303          *      Get the copied header of the packet that caused the redirect
 304          */
 305          
 306         iph = (struct iphdr *) (icmph + 1);
 307         ip = iph->daddr;
 308 
 309         switch(icmph->code & 7) 
 310         {
 311                 case ICMP_REDIR_NET:
 312                         /*
 313                          *      This causes a problem with subnetted networks. What we should do
 314                          *      is use ICMP_ADDRESS to get the subnet mask of the problem route
 315                          *      and set both. But we don't..
 316                          */
 317 #ifdef not_a_good_idea
 318                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 319                                 ip, 0, icmph->un.gateway, dev,0, 0);
 320                         break;
 321 #endif
 322                 case ICMP_REDIR_HOST:
 323                         /*
 324                          *      Add better route to host.
 325                          *      But first check that the redirect
 326                          *      comes from the old gateway..
 327                          */
 328                         rt = ip_rt_route(ip, NULL, NULL);
 329                         if (!rt)
 330                                 break;
 331                         if (rt->rt_gateway != source)
 332                                 break;
 333                         printk("redirect from %s\n", in_ntoa(source));
 334                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 335                                 ip, 0, icmph->un.gateway, dev,0, 0);
 336                         break;
 337                 case ICMP_REDIR_NETTOS:
 338                 case ICMP_REDIR_HOSTTOS:
 339                         printk("ICMP: cannot handle TOS redirects yet!\n");
 340                         break;
 341                 default:
 342                         break;
 343         }
 344         
 345         /*
 346          *      Discard the original packet
 347          */
 348          
 349         kfree_skb(skb, FREE_READ);
 350 }
 351 
 352 
 353 /*
 354  *      Handle ICMP_ECHO ("ping") requests. 
 355  */
 356  
 357 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 358           unsigned long saddr, unsigned long daddr, int len,
 359           struct options *opt)
 360 {
 361         struct icmphdr *icmphr;
 362         struct sk_buff *skb2;
 363         struct device *ndev=NULL;
 364         int size, offset;
 365 
 366         icmp_statistics.IcmpOutEchoReps++;
 367         icmp_statistics.IcmpOutMsgs++;
 368         
 369         size = dev->hard_header_len + 64 + len;
 370         skb2 = alloc_skb(size, GFP_ATOMIC);
 371 
 372         if (skb2 == NULL) 
 373         {
 374                 icmp_statistics.IcmpOutErrors++;
 375                 kfree_skb(skb, FREE_READ);
 376                 return;
 377         }
 378         skb2->free = 1;
 379 
 380         /* Build Layer 2-3 headers for message back to source */
 381         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 382                 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 383         if (offset < 0) 
 384         {
 385                 icmp_statistics.IcmpOutErrors++;
 386                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 387                 kfree_skb(skb2,FREE_WRITE);
 388                 kfree_skb(skb, FREE_READ);
 389                 return;
 390         }
 391 
 392         /*
 393          *      Re-adjust length according to actual IP header size. 
 394          */
 395          
 396         skb2->len = offset + len;
 397 
 398         /*
 399          *      Build ICMP_ECHO Response message. 
 400          */
 401         icmphr = (struct icmphdr *) (skb2->data + offset);
 402         memcpy((char *) icmphr, (char *) icmph, len);
 403         icmphr->type = ICMP_ECHOREPLY;
 404         icmphr->code = 0;
 405         icmphr->checksum = 0;
 406         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 407 
 408         /*
 409          *      Ship it out - free it when done 
 410          */
 411         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 412 
 413         /*
 414          *      Free the received frame
 415          */
 416          
 417         kfree_skb(skb, FREE_READ);
 418 }
 419 
 420 /*
 421  *      Handle ICMP Timestamp requests. 
 422  */
 423  
 424 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 425           unsigned long saddr, unsigned long daddr, int len,
 426           struct options *opt)
 427 {
 428         struct icmphdr *icmphr;
 429         struct sk_buff *skb2;
 430         int size, offset;
 431         unsigned long *timeptr, midtime;
 432         struct device *ndev=NULL;
 433 
 434         if (len != 20)
 435         {
 436                 printk(
 437                   "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
 438                   len);
 439                 icmp_statistics.IcmpInErrors++;         
 440 #if 1
 441                 /* correct answers are possible for everything >= 12 */
 442                 if (len < 12)
 443 #endif
 444                         return;
 445         }
 446 
 447         size = dev->hard_header_len + 84;
 448 
 449         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 450         {
 451                 skb->sk = NULL;
 452                 kfree_skb(skb, FREE_READ);
 453                 icmp_statistics.IcmpOutErrors++;                
 454                 return;
 455         }
 456         skb2->free = 1;
 457  
 458 /*
 459  *      Build Layer 2-3 headers for message back to source 
 460  */
 461  
 462         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 463                                 skb->ip_hdr->tos, 255);
 464         if (offset < 0) 
 465         {
 466                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 467                 kfree_skb(skb2, FREE_WRITE);
 468                 kfree_skb(skb, FREE_READ);
 469                 icmp_statistics.IcmpOutErrors++;
 470                 return;
 471         }
 472  
 473         /*
 474          *      Re-adjust length according to actual IP header size. 
 475          */
 476         skb2->len = offset + 20;
 477  
 478         /*
 479          *      Build ICMP_TIMESTAMP Response message. 
 480          */
 481 
 482         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 483         memcpy((char *) icmphr, (char *) icmph, 12);
 484         icmphr->type = ICMP_TIMESTAMPREPLY;
 485         icmphr->code = icmphr->checksum = 0;
 486 
 487         /* fill in the current time as ms since midnight UT: */
 488         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 489         timeptr = (unsigned long *) (icmphr + 1);
 490         /*
 491          *      the originate timestamp (timeptr [0]) is still in the copy: 
 492          */
 493         timeptr [1] = timeptr [2] = htonl(midtime);
 494 
 495         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
 496 
 497         /*
 498          *      Ship it out - free it when done 
 499          */
 500 
 501         ip_queue_xmit((struct sock *) NULL, dev, skb2, 1);
 502         icmp_statistics.IcmpOutTimestampReps++;
 503         kfree_skb(skb, FREE_READ);
 504 }
 505  
 506  
 507 
 508 
 509 /*
 510  *      Handle the ICMP INFORMATION REQUEST. 
 511  */
 512  
 513 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 514           unsigned long saddr, unsigned long daddr, int len,
 515           struct options *opt)
 516 {
 517         /* Obsolete */
 518         kfree_skb(skb, FREE_READ);
 519 }
 520 
 521 
 522 /* 
 523  *      Handle ICMP_ADDRESS_MASK requests. 
 524  */
 525  
 526 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 527           unsigned long saddr, unsigned long daddr, int len,
 528           struct options *opt)
 529 {
 530         struct icmphdr *icmphr;
 531         struct sk_buff *skb2;
 532         int size, offset;
 533         struct device *ndev=NULL;
 534 
 535         icmp_statistics.IcmpOutMsgs++;
 536         icmp_statistics.IcmpOutAddrMaskReps++;
 537         
 538         size = dev->hard_header_len + 64 + len;
 539         skb2 = alloc_skb(size, GFP_ATOMIC);
 540         if (skb2 == NULL) 
 541         {
 542                 icmp_statistics.IcmpOutErrors++;
 543                 kfree_skb(skb, FREE_READ);
 544                 return;
 545         }
 546         skb2->free = 1;
 547         
 548         /* 
 549          *      Build Layer 2-3 headers for message back to source 
 550          */
 551 
 552         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 553                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 554         if (offset < 0) 
 555         {
 556                 icmp_statistics.IcmpOutErrors++;
 557                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 558                 kfree_skb(skb2,FREE_WRITE);
 559                 kfree_skb(skb, FREE_READ);
 560                 return;
 561         }
 562 
 563         /*
 564          *      Re-adjust length according to actual IP header size. 
 565          */
 566 
 567         skb2->len = offset + len;
 568 
 569         /*
 570          *      Build ICMP ADDRESS MASK Response message. 
 571          */
 572 
 573         icmphr = (struct icmphdr *) (skb2->data + offset);
 574         icmphr->type = ICMP_ADDRESSREPLY;
 575         icmphr->code = 0;
 576         icmphr->checksum = 0;
 577         icmphr->un.echo.id = icmph->un.echo.id;
 578         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 579         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 580 
 581         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 582 
 583         /* Ship it out - free it when done */
 584         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 585 
 586         skb->sk = NULL;
 587         kfree_skb(skb, FREE_READ);
 588 }
 589 
 590 
 591 /* 
 592  *      Deal with incoming ICMP packets. 
 593  */
 594  
 595 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 596          unsigned long daddr, unsigned short len,
 597          unsigned long saddr, int redo, struct inet_protocol *protocol)
 598 {
 599         struct icmphdr *icmph;
 600         unsigned char *buff;
 601 
 602         /*
 603          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 604          *      to pass on that information.
 605          */
 606         
 607         icmp_statistics.IcmpInMsgs++;
 608          
 609         
 610         /*
 611          *      Grab the packet as an icmp object
 612          */
 613 
 614         buff = skb1->h.raw;
 615         icmph = (struct icmphdr *) buff;
 616 
 617         /*
 618          *      Validate the packet first 
 619          */
 620 
 621         if (ip_compute_csum((unsigned char *) icmph, len)) 
 622         {
 623                 /* Failed checksum! */
 624                 icmp_statistics.IcmpInErrors++;
 625                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 626                 kfree_skb(skb1, FREE_READ);
 627                 return(0);
 628         }
 629 
 630         /*
 631          *      Parse the ICMP message 
 632          */
 633 
 634         if (ip_chk_addr(daddr) == IS_BROADCAST)
 635         {
 636                 if (icmph->type != ICMP_ECHO) 
 637                 {
 638                         icmp_statistics.IcmpInErrors++;
 639                         kfree_skb(skb1, FREE_READ);
 640                         return(0);
 641                 }
 642                 daddr=dev->pa_addr;
 643         }
 644 
 645         switch(icmph->type) 
 646         {
 647                 case ICMP_TIME_EXCEEDED:
 648                         icmp_statistics.IcmpInTimeExcds++;
 649                         icmp_unreach(icmph, skb1);
 650                         return 0;
 651                 case ICMP_DEST_UNREACH:
 652                         icmp_statistics.IcmpInDestUnreachs++;
 653                         icmp_unreach(icmph, skb1);
 654                         return 0;
 655                 case ICMP_SOURCE_QUENCH:
 656                         icmp_statistics.IcmpInSrcQuenchs++;
 657                         icmp_unreach(icmph, skb1);
 658                         return(0);
 659                 case ICMP_REDIRECT:
 660                         icmp_statistics.IcmpInRedirects++;
 661                         icmp_redirect(icmph, skb1, dev, saddr);
 662                         return(0);
 663                 case ICMP_ECHO: 
 664                         icmp_statistics.IcmpInEchos++;
 665                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 666                         return 0;
 667                 case ICMP_ECHOREPLY:
 668                         icmp_statistics.IcmpInEchoReps++;
 669                         kfree_skb(skb1, FREE_READ);
 670                         return(0);
 671                 case ICMP_TIMESTAMP:
 672                         icmp_statistics.IcmpInTimestamps++;
 673                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 674                         return 0;
 675                 case ICMP_TIMESTAMPREPLY:
 676                         icmp_statistics.IcmpInTimestampReps++;
 677                         kfree_skb(skb1,FREE_READ);
 678                         return 0;
 679                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 680                 case ICMP_INFO_REQUEST:
 681                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 682                         return 0;
 683                 case ICMP_INFO_REPLY:
 684                         skb1->sk = NULL;
 685                         kfree_skb(skb1, FREE_READ);
 686                         return(0);
 687                 case ICMP_ADDRESS:
 688                         icmp_statistics.IcmpInAddrMasks++;
 689                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 690                         return 0;
 691                 case ICMP_ADDRESSREPLY:
 692                         /*
 693                          *      We ought to set our netmask on receiving this, but 
 694                          *      experience shows its a waste of effort.
 695                          */
 696                         icmp_statistics.IcmpInAddrMaskReps++;
 697                         kfree_skb(skb1, FREE_READ);
 698                         return(0);
 699                 default:
 700                         icmp_statistics.IcmpInErrors++;
 701                         kfree_skb(skb1, FREE_READ);
 702                         return(0);
 703         }
 704   /*NOTREACHED*/
 705         kfree_skb(skb1, FREE_READ);
 706         return(-1);
 707 }
 708 
 709 
 710 /*
 711  *      Perform any ICMP-related I/O control requests. 
 712  *      [to vanish soon]
 713  */
 714  
 715 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 716 {
 717         switch(cmd) 
 718         {
 719                 default:
 720                         return(-EINVAL);
 721         }
 722         return(0);
 723 }

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