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

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