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 
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 317         struct device *dev, unsigned long source)
 318 {
 319         struct rtable *rt;
 320         struct iphdr *iph;
 321         unsigned long ip;
 322 
 323         /*
 324          *      Get the copied header of the packet that caused the redirect
 325          */
 326          
 327         iph = (struct iphdr *) (icmph + 1);
 328         ip = iph->daddr;
 329 
 330         switch(icmph->code & 7) 
 331         {
 332                 case ICMP_REDIR_NET:
 333                         /*
 334                          *      This causes a problem with subnetted networks. What we should do
 335                          *      is use ICMP_ADDRESS to get the subnet mask of the problem route
 336                          *      and set both. But we don't..
 337                          */
 338 #ifdef not_a_good_idea
 339                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 340                                 ip, 0, icmph->un.gateway, dev);
 341                         break;
 342 #endif
 343                 case ICMP_REDIR_HOST:
 344                         /*
 345                          *      Add better route to host.
 346                          *      But first check that the redirect
 347                          *      comes from the old gateway..
 348                          */
 349                         rt = ip_rt_route(ip, NULL, NULL);
 350                         if (!rt)
 351                                 break;
 352                         if (rt->rt_gateway != source)
 353                                 break;
 354                         printk("redirect from %08lx\n", source);
 355                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 356                                 ip, 0, icmph->un.gateway, dev);
 357                         break;
 358                 case ICMP_REDIR_NETTOS:
 359                 case ICMP_REDIR_HOSTTOS:
 360                         printk("ICMP: cannot handle TOS redirects yet!\n");
 361                         break;
 362                 default:
 363                         DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
 364                                                 (icmph->code & 7)));
 365                 break;
 366         }
 367         
 368         /*
 369          *      Discard the original packet
 370          */
 371          
 372         kfree_skb(skb, FREE_READ);
 373 }
 374 
 375 
 376 /*
 377  *      Handle ICMP_ECHO ("ping") requests. 
 378  */
 379  
 380 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 381           unsigned long saddr, unsigned long daddr, int len,
 382           struct options *opt)
 383 {
 384         struct icmphdr *icmphr;
 385         struct sk_buff *skb2;
 386         struct device *ndev=NULL;
 387         int size, offset;
 388 
 389         icmp_statistics.IcmpOutEchoReps++;
 390         icmp_statistics.IcmpOutMsgs++;
 391         
 392         size = dev->hard_header_len + 64 + len;
 393         skb2 = alloc_skb(size, GFP_ATOMIC);
 394 
 395         if (skb2 == NULL) 
 396         {
 397                 icmp_statistics.IcmpOutErrors++;
 398                 kfree_skb(skb, FREE_READ);
 399                 return;
 400         }
 401         skb2->free = 1;
 402 
 403         /* Build Layer 2-3 headers for message back to source */
 404         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 405                 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 406         if (offset < 0) 
 407         {
 408                 icmp_statistics.IcmpOutErrors++;
 409                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 410                 kfree_skb(skb2,FREE_WRITE);
 411                 kfree_skb(skb, FREE_READ);
 412                 return;
 413         }
 414 
 415         /*
 416          *      Re-adjust length according to actual IP header size. 
 417          */
 418          
 419         skb2->len = offset + len;
 420 
 421         /*
 422          *      Build ICMP_ECHO Response message. 
 423          */
 424         icmphr = (struct icmphdr *) (skb2->data + offset);
 425         memcpy((char *) icmphr, (char *) icmph, len);
 426         icmphr->type = ICMP_ECHOREPLY;
 427         icmphr->code = 0;
 428         icmphr->checksum = 0;
 429         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 430 
 431         /*
 432          *      Ship it out - free it when done 
 433          */
 434         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 435 
 436         /*
 437          *      Free the received frame
 438          */
 439          
 440         kfree_skb(skb, FREE_READ);
 441 }
 442 
 443 /*
 444  *      Handle ICMP Timestamp requests. 
 445  */
 446  
 447 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 448           unsigned long saddr, unsigned long daddr, int len,
 449           struct options *opt)
 450 {
 451         struct icmphdr *icmphr;
 452         struct sk_buff *skb2;
 453         int size, offset;
 454         unsigned long *timeptr, midtime;
 455         extern struct timeval xtime;                    /* kernel/time.c */
 456         struct device *ndev=NULL;
 457  
 458         size = dev->hard_header_len + 64 + len;
 459 
 460         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 461         {
 462                 skb->sk = NULL;
 463                 kfree_skb(skb, FREE_READ);
 464                 icmp_statistics.IcmpOutErrors++;                
 465                 return;
 466         }
 467         skb2->free = 1;
 468  
 469 /*
 470  *      Build Layer 2-3 headers for message back to source 
 471  */
 472  
 473         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 474                                 skb->ip_hdr->tos, 255);
 475         if (offset < 0) 
 476         {
 477                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 478                 kfree_skb(skb2, FREE_WRITE);
 479                 kfree_skb(skb, FREE_READ);
 480                 icmp_statistics.IcmpOutErrors++;
 481                 return;
 482         }
 483  
 484         /*
 485          *      Re-adjust length according to actual IP header size. 
 486          */
 487         skb2->len = offset + len;
 488  
 489         /*
 490          *      Build ICMP_TIMESTAMP Response message. 
 491          */
 492 
 493         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 494         memcpy((char *) icmphr, (char *) icmph, len);
 495         icmphr->type = ICMP_TIMESTAMPREPLY;
 496         icmphr->code = icmphr->checksum = 0;
 497 
 498         /* fill in the current time as ms since midnight UT: */
 499         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 500         timeptr = (unsigned long *) (icmphr + 1);
 501         /*
 502          *      the originate timestamp (timeptr [0]) is still in the copy: 
 503          */
 504         timeptr [1] = timeptr [2] = htonl(midtime);
 505 
 506         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len);
 507 
 508         /*
 509          *      Ship it out - free it when done 
 510          */
 511 
 512         ip_queue_xmit((struct sock *) NULL, dev, skb2, 1);
 513         icmp_statistics.IcmpOutTimestampReps++;
 514         kfree_skb(skb, FREE_READ);
 515 }
 516  
 517  
 518 
 519 
 520 /*
 521  *      Handle the ICMP INFORMATION REQUEST. 
 522  */
 523  
 524 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 525           unsigned long saddr, unsigned long daddr, int len,
 526           struct options *opt)
 527 {
 528         /* Obsolete */
 529         kfree_skb(skb, FREE_READ);
 530 }
 531 
 532 
 533 /* 
 534  *      Handle ICMP_ADRESS_MASK requests. 
 535  */
 536  
 537 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 538           unsigned long saddr, unsigned long daddr, int len,
 539           struct options *opt)
 540 {
 541         struct icmphdr *icmphr;
 542         struct sk_buff *skb2;
 543         int size, offset;
 544         struct device *ndev=NULL;
 545 
 546         icmp_statistics.IcmpOutMsgs++;
 547         icmp_statistics.IcmpOutAddrMaskReps++;
 548         
 549         size = dev->hard_header_len + 64 + len;
 550         skb2 = alloc_skb(size, GFP_ATOMIC);
 551         if (skb2 == NULL) 
 552         {
 553                 icmp_statistics.IcmpOutErrors++;
 554                 kfree_skb(skb, FREE_READ);
 555                 return;
 556         }
 557         skb2->free = 1;
 558         
 559         /* 
 560          *      Build Layer 2-3 headers for message back to source 
 561          */
 562 
 563         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 564                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 565         if (offset < 0) 
 566         {
 567                 icmp_statistics.IcmpOutErrors++;
 568                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 569                 kfree_skb(skb2,FREE_WRITE);
 570                 kfree_skb(skb, FREE_READ);
 571                 return;
 572         }
 573 
 574         /*
 575          *      Re-adjust length according to actual IP header size. 
 576          */
 577 
 578         skb2->len = offset + len;
 579 
 580         /*
 581          *      Build ICMP ADDRESS MASK Response message. 
 582          */
 583 
 584         icmphr = (struct icmphdr *) (skb2->data + offset);
 585         icmphr->type = ICMP_ADDRESSREPLY;
 586         icmphr->code = 0;
 587         icmphr->checksum = 0;
 588         icmphr->un.echo.id = icmph->un.echo.id;
 589         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 590         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 591 
 592         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 593 
 594         /* Ship it out - free it when done */
 595         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 596 
 597         skb->sk = NULL;
 598         kfree_skb(skb, FREE_READ);
 599 }
 600 
 601 
 602 /* 
 603  *      Deal with incoming ICMP packets. 
 604  */
 605  
 606 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 607          unsigned long daddr, unsigned short len,
 608          unsigned long saddr, int redo, struct inet_protocol *protocol)
 609 {
 610         struct icmphdr *icmph;
 611         unsigned char *buff;
 612 
 613         /*
 614          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 615          *      to pass on that information.
 616          */
 617         
 618         icmp_statistics.IcmpInMsgs++;
 619          
 620         if (ip_chk_addr(daddr) == IS_BROADCAST) 
 621         {
 622                 DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
 623                                                         in_ntoa(saddr)));
 624                 icmp_statistics.IcmpInErrors++;
 625                 kfree_skb(skb1, FREE_READ);
 626                 return(0);
 627         }
 628         
 629         /*
 630          *      Grab the packet as an icmp object
 631          */
 632 
 633         buff = skb1->h.raw;
 634         icmph = (struct icmphdr *) buff;
 635 
 636         /*
 637          *      Validate the packet first 
 638          */
 639 
 640         if (ip_compute_csum((unsigned char *) icmph, len)) 
 641         {
 642                 /* Failed checksum! */
 643                 icmp_statistics.IcmpInErrors++;
 644                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 645                 kfree_skb(skb1, FREE_READ);
 646                 return(0);
 647         }
 648         print_icmp(icmph);
 649 
 650         /*
 651          *      Parse the ICMP message 
 652          */
 653 
 654         switch(icmph->type) 
 655         {
 656                 case ICMP_TIME_EXCEEDED:
 657                         icmp_statistics.IcmpInTimeExcds++;
 658                         icmp_unreach(icmph, skb1);
 659                         return 0;
 660                 case ICMP_DEST_UNREACH:
 661                         icmp_statistics.IcmpInDestUnreachs++;
 662                         icmp_unreach(icmph, skb1);
 663                         return 0;
 664                 case ICMP_SOURCE_QUENCH:
 665                         icmp_statistics.IcmpInSrcQuenchs++;
 666                         icmp_unreach(icmph, skb1);
 667                         return(0);
 668                 case ICMP_REDIRECT:
 669                         icmp_statistics.IcmpInRedirects++;
 670                         icmp_redirect(icmph, skb1, dev, saddr);
 671                         return(0);
 672                 case ICMP_ECHO: 
 673                         icmp_statistics.IcmpInEchos++;
 674                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 675                         return 0;
 676                 case ICMP_ECHOREPLY:
 677                         icmp_statistics.IcmpInEchoReps++;
 678                         kfree_skb(skb1, FREE_READ);
 679                         return(0);
 680                 case ICMP_TIMESTAMP:
 681                         icmp_statistics.IcmpInTimestamps++;
 682                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 683                         return 0;
 684                 case ICMP_TIMESTAMPREPLY:
 685                         icmp_statistics.IcmpInTimestampReps++;
 686                         kfree_skb(skb1,FREE_READ);
 687                         return 0;
 688                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 689                 case ICMP_INFO_REQUEST:
 690                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 691                         return 0;
 692                 case ICMP_INFO_REPLY:
 693                         skb1->sk = NULL;
 694                         kfree_skb(skb1, FREE_READ);
 695                         return(0);
 696                 case ICMP_ADDRESS:
 697                         icmp_statistics.IcmpInAddrMasks++;
 698                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 699                         return 0;
 700                 case ICMP_ADDRESSREPLY:
 701                         /*
 702                          *      We ought to set our netmask on receiving this, but 
 703                          *      experience shows its a waste of effort.
 704                          */
 705                         icmp_statistics.IcmpInAddrMaskReps++;
 706                         kfree_skb(skb1, FREE_READ);
 707                         return(0);
 708                 default:
 709                         icmp_statistics.IcmpInErrors++;
 710                         DPRINTF((DBG_ICMP,
 711                                 "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
 712                                                         in_ntoa(saddr), icmph->type));
 713                         kfree_skb(skb1, FREE_READ);
 714                         return(0);
 715         }
 716   /*NOTREACHED*/
 717         kfree_skb(skb1, FREE_READ);
 718         return(-1);
 719 }
 720 
 721 
 722 /*
 723  *      Perform any ICMP-related I/O control requests. 
 724  *      [to vanish soon]
 725  */
 726  
 727 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729         switch(cmd) 
 730         {
 731                 case DDIOCSDBG:
 732                         return(dbg_ioctl((void *) arg, DBG_ICMP));
 733                 default:
 734                         return(-EINVAL);
 735         }
 736         return(0);
 737 }

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