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

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