root/net/inet/icmp.c

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

DEFINITIONS

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

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