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

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