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  *              Mike Shaver     :       RFC1122 checks.
  38  * 
  39  *
  40  *              This program is free software; you can redistribute it and/or
  41  *              modify it under the terms of the GNU General Public License
  42  *              as published by the Free Software Foundation; either version
  43  *              2 of the License, or (at your option) any later version.
  44  */
  45 
  46 /* RFC1122 Status: (boy, are there a lot of rules for ICMP)
  47    3.2.2 (Generic ICMP stuff)
  48      MUST discard messages of unknown type. (OK)
  49      MUST copy at least the first 8 bytes from the offending packet
  50        when sending ICMP errors. (OK)
  51      MUST pass received ICMP errors up to protocol level. (OK)
  52      SHOULD send ICMP errors with TOS == 0. (OK)
  53      MUST NOT send ICMP errors in reply to:
  54        ICMP errors (OK)
  55        Broadcast/multicast datagrams (OK)
  56        MAC broadcasts (OK)
  57        Non-initial fragments (OK)
  58        Datagram with a source address that isn't a single host. (OK)
  59   3.2.2.1 (Destination Unreachable)
  60     All the rules govern the IP layer, and are dealt with in ip.c, not here.
  61   3.2.2.2 (Redirect)
  62     Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
  63     MUST update routing table in response to host or network redirects. 
  64       (host OK, network NOT YET) [Intentionally -- AC]
  65     SHOULD drop redirects if they're not from directly connected gateway
  66       (OK -- we drop it if it's not from our old gateway, which is close
  67        enough)
  68   3.2.2.3 (Source Quench)
  69     MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
  70     Other requirements are dealt with at the transport layer.
  71   3.2.2.4 (Time Exceeded)
  72     MUST pass TIME_EXCEEDED to transport layer (OK)
  73     Other requirements dealt with at IP (generating TIME_EXCEEDED).
  74   3.2.2.5 (Parameter Problem)
  75     SHOULD generate these, but it doesn't say for what.  So we're OK. =)
  76     MUST pass received PARAMPROBLEM to transport layer (NOT YET)
  77         [Solaris 2.X seems to assert EPROTO when this occurs] -- AC
  78   3.2.2.6 (Echo Request/Reply)
  79     MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
  80     MAY discard broadcast ECHO_REQUESTs. (We don't, but that's OK.)
  81     MUST reply using same source address as the request was sent to.
  82       We're OK for unicast ECHOs, and it doesn't say anything about
  83       how to handle broadcast ones, since it's optional.
  84     MUST copy data from REQUEST to REPLY (OK)
  85       unless it would require illegal fragmentation (MUST) (NOT YET)
  86     MUST pass REPLYs to transport/user layer (OK)
  87     MUST use any provided source route (reversed) for REPLY. (NOT YET)
  88  3.2.2.7 (Information Request/Reply)
  89    MUST NOT implement this. (I guess that means silently discard...?) (OK)
  90  3.2.2.8 (Timestamp Request/Reply)
  91    MAY implement (OK)
  92    SHOULD be in-kernel for "minimum variability" (OK)
  93    MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
  94    MUST reply using same source address as the request was sent to. (OK)
  95    MUST reverse source route, as per ECHO (NOT YET)
  96    MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK)
  97    MUST update clock for timestamp at least 15 times/sec (OK)
  98    MUST be "correct within a few minutes" (OK)
  99  3.2.2.9 (Address Mask Request/Reply)
 100    MAY implement (OK)
 101    MUST send a broadcast REQUEST if using this system to set netmask
 102      (OK... we don't use it)
 103    MUST discard received REPLYs if not using this system (OK)
 104    MUST NOT send replies unless specifically made agent for this sort
 105      of thing. (NOT YET)
 106 */
 107 
 108 #include <linux/types.h>
 109 #include <linux/sched.h>
 110 #include <linux/kernel.h>
 111 #include <linux/fcntl.h>
 112 #include <linux/socket.h>
 113 #include <linux/in.h>
 114 #include <linux/inet.h>
 115 #include <linux/netdevice.h>
 116 #include <linux/string.h>
 117 #include <net/snmp.h>
 118 #include <net/ip.h>
 119 #include <net/route.h>
 120 #include <net/protocol.h>
 121 #include <net/icmp.h>
 122 #include <net/tcp.h>
 123 #include <net/snmp.h>
 124 #include <linux/skbuff.h>
 125 #include <net/sock.h>
 126 #include <linux/errno.h>
 127 #include <linux/timer.h>
 128 #include <asm/system.h>
 129 #include <asm/segment.h>
 130 #include <net/checksum.h>
 131 
 132 
 133 #define min(a,b)        ((a)<(b)?(a):(b))
 134 
 135 
 136 /*
 137  *      Statistics
 138  */
 139  
 140 struct icmp_mib icmp_statistics={0,};
 141 
 142 
 143 /* An array of errno for error messages from dest unreach. */
 144 struct icmp_err icmp_err_convert[] = {
 145   { ENETUNREACH,        0 },    /*      ICMP_NET_UNREACH        */
 146   { EHOSTUNREACH,       0 },    /*      ICMP_HOST_UNREACH       */
 147   { ENOPROTOOPT,        1 },    /*      ICMP_PROT_UNREACH       */
 148   { ECONNREFUSED,       1 },    /*      ICMP_PORT_UNREACH       */
 149   { EOPNOTSUPP,         0 },    /*      ICMP_FRAG_NEEDED        */
 150   { EOPNOTSUPP,         0 },    /*      ICMP_SR_FAILED          */
 151   { ENETUNREACH,        1 },    /*      ICMP_NET_UNKNOWN        */
 152   { EHOSTDOWN,          1 },    /*      ICMP_HOST_UNKNOWN       */
 153   { ENONET,             1 },    /*      ICMP_HOST_ISOLATED      */
 154   { ENETUNREACH,        1 },    /*      ICMP_NET_ANO            */
 155   { EHOSTUNREACH,       1 },    /*      ICMP_HOST_ANO           */
 156   { EOPNOTSUPP,         0 },    /*      ICMP_NET_UNR_TOS        */
 157   { EOPNOTSUPP,         0 }     /*      ICMP_HOST_UNR_TOS       */
 158 };
 159 
 160 
 161 /*
 162  *      Send an ICMP message in response to a situation
 163  */
 164  
 165 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] */
 166 {
 167         struct sk_buff *skb;
 168         struct iphdr *iph;
 169         int offset;
 170         struct icmphdr *icmph;
 171         int len;
 172         struct device *ndev=NULL;       /* Make this =dev to force replies on the same interface */
 173         unsigned long our_addr;
 174         int atype;
 175         
 176         /*
 177          *      Find the original IP header.
 178          */
 179          
 180         iph = (struct iphdr *) skb_in->data;
 181         
 182         /*
 183          *      No replies to MAC multicast
 184          */
 185          
 186         if(skb_in->pkt_type!=PACKET_HOST)
 187                 return;
 188                 
 189         /*
 190          *      No replies to IP multicasting
 191          */
 192          
 193         atype=ip_chk_addr(iph->daddr);
 194         if(atype==IS_BROADCAST || atype==IS_MULTICAST)
 195                 return;
 196 
 197         /*
 198          *      Only reply to first fragment.
 199          */
 200          
 201         if(ntohs(iph->frag_off)&IP_OFFSET)
 202                 return;
 203                         
 204         /*
 205          *      We must NEVER NEVER send an ICMP error to an ICMP error message
 206          */
 207          
 208         if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
 209         {
 210 
 211                 /*
 212                  *      Is the original packet an ICMP packet?
 213                  */
 214 
 215                 if(iph->protocol==IPPROTO_ICMP)
 216                 {
 217                         icmph = (struct icmphdr *) ((char *) iph +
 218                                                     4 * iph->ihl);
 219                         /*
 220                          *      Check for ICMP error packets (Must never reply to
 221                          *      an ICMP error).
 222                          */
 223         
 224                         if (icmph->type == ICMP_DEST_UNREACH ||
 225                                 icmph->type == ICMP_SOURCE_QUENCH ||
 226                                 icmph->type == ICMP_REDIRECT ||
 227                                 icmph->type == ICMP_TIME_EXCEEDED ||
 228                                 icmph->type == ICMP_PARAMETERPROB)
 229                                 return;
 230                 }
 231         }
 232         icmp_statistics.IcmpOutMsgs++;
 233         
 234         /*
 235          *      This needs a tidy.      
 236          */
 237                 
 238         switch(type)
 239         {
 240                 case ICMP_DEST_UNREACH:
 241                         icmp_statistics.IcmpOutDestUnreachs++;
 242                         break;
 243                 case ICMP_SOURCE_QUENCH:
 244                         icmp_statistics.IcmpOutSrcQuenchs++;
 245                         break;
 246                 case ICMP_REDIRECT:
 247                 /* RFC1122: (3.2.2.2) Sorta bad.  SHOULDN'T send */
 248                 /* ICMP_REDIRECTs unless we're a gateway. -- MS */
 249                 /* We don't .. this path isnt invoked -- AC */
 250                         icmp_statistics.IcmpOutRedirects++;
 251                         break;
 252                 case ICMP_ECHO:
 253                         icmp_statistics.IcmpOutEchos++;
 254                         break;
 255                 case ICMP_ECHOREPLY:
 256                         icmp_statistics.IcmpOutEchoReps++;
 257                         break;
 258                 case ICMP_TIME_EXCEEDED:
 259                         icmp_statistics.IcmpOutTimeExcds++;
 260                         break;
 261                 case ICMP_PARAMETERPROB:
 262                         icmp_statistics.IcmpOutParmProbs++;
 263                         break;
 264                 case ICMP_TIMESTAMP:
 265                         icmp_statistics.IcmpOutTimestamps++;
 266                         break;
 267                 case ICMP_TIMESTAMPREPLY:
 268                         icmp_statistics.IcmpOutTimestampReps++;
 269                         break;
 270                 case ICMP_ADDRESS:
 271                         icmp_statistics.IcmpOutAddrMasks++;
 272                         break;
 273                 case ICMP_ADDRESSREPLY:
 274                         icmp_statistics.IcmpOutAddrMaskReps++;
 275                         break;
 276         }               
 277         /*
 278          *      Get some memory for the reply. 
 279          */
 280          
 281         len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
 282                 sizeof(struct iphdr) + 32;      /* amount of header to return */
 283            
 284         skb = (struct sk_buff *) alloc_skb(len+15, GFP_ATOMIC);
 285         if (skb == NULL) 
 286         {
 287                 icmp_statistics.IcmpOutErrors++;
 288                 return;
 289         }
 290         skb->free = 1;
 291 
 292         /*
 293          *      Build Layer 2-3 headers for message back to source. 
 294          */
 295 
 296         our_addr = dev->pa_addr;
 297 
 298         /* RFC1122: (3.2.2).  MUST NOT send ICMP in reply to */
 299         /* packet with a source IP address that doesn't define a single */
 300         /* host. -- MS.  Checked higher up -- AC */
 301 
 302         if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
 303                 our_addr = iph->daddr;
 304         offset = ip_build_header(skb, our_addr, iph->saddr,
 305                            &ndev, IPPROTO_ICMP, NULL, len,
 306                            skb_in->ip_hdr->tos,255);
 307         if (offset < 0) 
 308         {
 309                 icmp_statistics.IcmpOutErrors++;
 310                 skb->sk = NULL;
 311                 kfree_skb(skb, FREE_READ);
 312                 return;
 313         }
 314 
 315         /* 
 316          *      Re-adjust length according to actual IP header size. 
 317          */
 318 
 319         skb_put(skb,sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 320         
 321         /*
 322          *      Fill in the frame
 323          */
 324          
 325         /* RFC1122: SHOULD send with TOS == 0, and I guess this does. */
 326         /* Perhaps it should be explicit? -- MS */
 327 
 328         icmph = (struct icmphdr *) (skb->data + offset);
 329         icmph->type = type;
 330         icmph->code = code;
 331         icmph->checksum = 0;
 332         icmph->un.gateway = info;       /* This might not be meant for 
 333                                            this form of the union but it will
 334                                            be right anyway */
 335 
 336         /* RFC1122: OK. Copies the minimum 8 bytes unchanged from the offending */
 337         /* packet (MUST) as per 3.2.2. -- MS */
 338         memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
 339 
 340         icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 341                          sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 342 
 343         /*
 344          *      Send it and free it once sent.
 345          */
 346         ip_queue_xmit(NULL, ndev, skb, 1);
 347 }
 348 
 349 
 350 /* 
 351  *      Handle ICMP_UNREACH and ICMP_QUENCH. 
 352  */
 353  
 354 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356         struct inet_protocol *ipprot;
 357         struct iphdr *iph;
 358         unsigned char hash;
 359         int err;
 360 
 361         err = (icmph->type << 8) | icmph->code;
 362         iph = (struct iphdr *) (icmph + 1);
 363         
 364         switch(icmph->code & 7) 
 365         {
 366                 case ICMP_NET_UNREACH:
 367                         break;
 368                 case ICMP_HOST_UNREACH:
 369                         break;
 370                 case ICMP_PROT_UNREACH:
 371 #ifdef CONFIG_NET_DEBUG
 372                         printk("ICMP: %s:%d: protocol unreachable.\n",
 373                                 in_ntoa(iph->daddr), ntohs(iph->protocol));
 374 #endif
 375                         break;
 376                 case ICMP_PORT_UNREACH:
 377                         break;
 378                 case ICMP_FRAG_NEEDED:
 379 #ifdef CONFIG_NET_DEBUG
 380                         printk("ICMP: %s: fragmentation needed and DF set.\n",
 381                                                                 in_ntoa(iph->daddr));
 382 #endif
 383                         break;
 384                 case ICMP_SR_FAILED:
 385 #ifdef CONFIG_NET_DEBUG
 386                         printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
 387 #endif
 388                         break;
 389                 default:
 390                         break;
 391         }
 392 
 393         /*
 394          *      Get the protocol(s). 
 395          */
 396          
 397         hash = iph->protocol & (MAX_INET_PROTOS -1);
 398 
 399         /*
 400          *      This can't change while we are doing it. 
 401          */
 402          
 403         ipprot = (struct inet_protocol *) inet_protos[hash];
 404         while(ipprot != NULL) 
 405         {
 406                 struct inet_protocol *nextip;
 407 
 408                 nextip = (struct inet_protocol *) ipprot->next;
 409         
 410                 /* 
 411                  *      Pass it off to everyone who wants it. 
 412                  */
 413 
 414                 /* RFC1122: OK. Passes appropriate ICMP errors to the */
 415                 /* appropriate protocol layer (MUST), as per 3.2.2. */
 416 
 417                 if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 418                 {
 419                         ipprot->err_handler(err, (unsigned char *)(icmph + 1),
 420                                             iph->daddr, iph->saddr, ipprot);
 421                 }
 422 
 423                 ipprot = nextip;
 424         }
 425         kfree_skb(skb, FREE_READ);
 426 }
 427 
 428 
 429 /*
 430  *      Handle ICMP_REDIRECT. 
 431  */
 432 
 433 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
     /* [previous][next][first][last][top][bottom][index][help] */
 434         struct device *dev, unsigned long source)
 435 {
 436 #ifndef CONFIG_IP_FORWARD
 437         struct rtable *rt;
 438 #endif
 439         struct iphdr *iph;
 440         unsigned long ip;
 441 
 442         /*
 443          *      Get the copied header of the packet that caused the redirect
 444          */
 445          
 446         iph = (struct iphdr *) (icmph + 1);
 447         ip = iph->daddr;
 448 
 449 #ifdef CONFIG_IP_FORWARD
 450         /*
 451          *      We are a router. Routers should not respond to ICMP_REDIRECT messages.
 452          */
 453         printk("icmp: ICMP redirect from %s on %s ignored.\n", in_ntoa(source), dev->name);
 454 #else   
 455         switch(icmph->code & 7) 
 456         {
 457                 case ICMP_REDIR_NET:
 458                         /*
 459                          *      This causes a problem with subnetted networks. What we should do
 460                          *      is use ICMP_ADDRESS to get the subnet mask of the problem route
 461                          *      and set both. But we don't..
 462                          */
 463 #ifdef not_a_good_idea
 464                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 465                                 ip, 0, icmph->un.gateway, dev,0, 0, 0);
 466 #endif
 467                         break;
 468                 case ICMP_REDIR_HOST:
 469                         /*
 470                          *      Add better route to host.
 471                          *      But first check that the redirect
 472                          *      comes from the old gateway..
 473                          *      And make sure it's an ok host address
 474                          *      (not some confused thing sending our
 475                          *      address)
 476                          */
 477                         rt = ip_rt_route(ip, NULL, NULL);
 478                         if (!rt)
 479                                 break;
 480                         if (rt->rt_gateway != source || 
 481                                 ((icmph->un.gateway^dev->pa_addr)&dev->pa_mask) ||
 482                                 ip_chk_addr(icmph->un.gateway))
 483                                 break;
 484                         printk("ICMP redirect from %s\n", in_ntoa(source));
 485                         ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 486                                 ip, 0, icmph->un.gateway, dev,0, 0, 0, 0);
 487                         break;
 488                 case ICMP_REDIR_NETTOS:
 489                 case ICMP_REDIR_HOSTTOS:
 490                         printk("ICMP: cannot handle TOS redirects yet!\n");
 491                         break;
 492                 default:
 493                         break;
 494         }
 495 #endif          
 496         /*
 497          *      Discard the original packet
 498          */
 499          
 500         kfree_skb(skb, FREE_READ);
 501 }
 502 
 503 
 504 /*
 505  *      Handle ICMP_ECHO ("ping") requests. 
 506  */
 507  
 508 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 509           unsigned long saddr, unsigned long daddr, int len,
 510           struct options *opt)
 511 {
 512         struct icmphdr *icmphr;
 513         struct sk_buff *skb2;
 514         struct device *ndev=NULL;
 515         int size, offset;
 516 
 517         icmp_statistics.IcmpOutEchoReps++;
 518         icmp_statistics.IcmpOutMsgs++;
 519         
 520         size = dev->hard_header_len + 64 + len + 15;
 521         skb2 = alloc_skb(size, GFP_ATOMIC);
 522 
 523         if (skb2 == NULL) 
 524         {
 525                 icmp_statistics.IcmpOutErrors++;
 526                 kfree_skb(skb, FREE_READ);
 527                 return;
 528         }
 529         skb2->free = 1;
 530 
 531         /* Build Layer 2-3 headers for message back to source */
 532         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 533                 IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 534         if (offset < 0) 
 535         {
 536                 icmp_statistics.IcmpOutErrors++;
 537                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 538                 kfree_skb(skb2,FREE_WRITE);
 539                 kfree_skb(skb, FREE_READ);
 540                 return;
 541         }
 542 
 543         /*
 544          *      Re-adjust length according to actual IP header size. 
 545          */
 546          
 547         skb_put(skb2,len);
 548 
 549         /*
 550          *      Build ICMP_ECHO Response message. 
 551          */
 552         icmphr = (struct icmphdr *) (skb2->data + offset);
 553         memcpy((char *) icmphr, (char *) icmph, len);
 554 
 555         /* Are we copying the data from the ECHO datagram? */
 556         /* We're supposed to, and it looks like we are. -- MS */
 557         /* We're also supposed to truncate it if it would force */
 558         /* illegal fragmentation. *sigh*  */
 559 
 560         icmphr->type = ICMP_ECHOREPLY;
 561         icmphr->code = 0;
 562         icmphr->checksum = 0;
 563         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 564 
 565         /*
 566          *      Ship it out - free it when done 
 567          */
 568         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 569 
 570         /*
 571          *      Free the received frame
 572          */
 573          
 574         kfree_skb(skb, FREE_READ);
 575 }
 576 
 577 /*
 578  *      Handle ICMP Timestamp requests. 
 579  */
 580  
 581 static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 582           unsigned long saddr, unsigned long daddr, int len,
 583           struct options *opt)
 584 {
 585         struct icmphdr *icmphr;
 586         struct sk_buff *skb2;
 587         int size, offset;
 588         unsigned long *timeptr, midtime;
 589         struct device *ndev=NULL;
 590 
 591         if (len < 12)
 592         {
 593                 printk(
 594                   "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
 595                   len);
 596                 icmp_statistics.IcmpInErrors++;         
 597                 /* correct answers are possible for everything >= 12 */
 598         }
 599 
 600         size = dev->hard_header_len + 84 + 15;
 601 
 602         if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
 603         {
 604                 skb->sk = NULL;
 605                 kfree_skb(skb, FREE_READ);
 606                 icmp_statistics.IcmpOutErrors++;                
 607                 return;
 608         }
 609         skb2->free = 1;
 610  
 611 /*
 612  *      Build Layer 2-3 headers for message back to source 
 613  */
 614  
 615         offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
 616                                 skb->ip_hdr->tos, 255);
 617         if (offset < 0) 
 618         {
 619                 printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
 620                 kfree_skb(skb2, FREE_WRITE);
 621                 kfree_skb(skb, FREE_READ);
 622                 icmp_statistics.IcmpOutErrors++;
 623                 return;
 624         }
 625  
 626         /*
 627          *      Re-adjust length according to actual IP header size. 
 628          */
 629         skb_put(skb2,20);
 630  
 631         /*
 632          *      Build ICMP_TIMESTAMP Response message. 
 633          */
 634 
 635         icmphr = (struct icmphdr *) (skb2->data + offset);
 636         memcpy((char *) icmphr, (char *) icmph, 12);
 637         icmphr->type = ICMP_TIMESTAMPREPLY;
 638         icmphr->code = icmphr->checksum = 0;
 639 
 640         /* fill in the current time as ms since midnight UT: */
 641         midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
 642         timeptr = (unsigned long *) (icmphr + 1);
 643         /*
 644          *      the originate timestamp (timeptr [0]) is still in the copy: 
 645          */
 646         timeptr [1] = timeptr [2] = htonl(midtime);
 647 
 648         icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
 649 
 650         /*
 651          *      Ship it out - free it when done 
 652          */
 653 
 654         ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
 655         icmp_statistics.IcmpOutTimestampReps++;
 656         kfree_skb(skb, FREE_READ);
 657 }
 658  
 659  
 660 
 661 
 662 /*
 663  *      Handle the ICMP INFORMATION REQUEST. 
 664  */
 665  
 666 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 667           unsigned long saddr, unsigned long daddr, int len,
 668           struct options *opt)
 669 {
 670         /* Obsolete */
 671         kfree_skb(skb, FREE_READ);
 672 }
 673 
 674 
 675 /* 
 676  *      Handle ICMP_ADDRESS_MASK requests. 
 677  */
 678 
 679 /* RFC1122 (3.2.2.9).  A host MUST only send replies to */
 680 /* ADDRESS_MASK requests if it's been configured as an address mask */
 681 /* agent.  Receiving a request doesn't constitute implicit permission to */
 682 /* act as one. Of course, implementing this correctly requires (SHOULD) */
 683 /* a way to turn the functionality on and off.  Another one for sysctl(), */
 684 /* I guess. -- MS */
 685 /* Botched with a CONFIG option for now - Linus add scts sysctl please.. */
 686  
 687 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 688           unsigned long saddr, unsigned long daddr, int len,
 689           struct options *opt)
 690 {
 691 #ifdef CONFIG_IP_ADDR_AGENT
 692         struct icmphdr *icmphr;
 693         struct sk_buff *skb2;
 694         int size, offset;
 695         struct device *ndev=NULL;
 696 
 697         icmp_statistics.IcmpOutMsgs++;
 698         icmp_statistics.IcmpOutAddrMaskReps++;
 699         
 700         size = dev->hard_header_len + 64 + len + 15;
 701         skb2 = alloc_skb(size, GFP_ATOMIC);
 702         if (skb2 == NULL) 
 703         {
 704                 icmp_statistics.IcmpOutErrors++;
 705                 kfree_skb(skb, FREE_READ);
 706                 return;
 707         }
 708         skb2->free = 1;
 709         
 710         /* 
 711          *      Build Layer 2-3 headers for message back to source 
 712          */
 713 
 714         offset = ip_build_header(skb2, daddr, saddr, &ndev,
 715                         IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 716         if (offset < 0) 
 717         {
 718                 icmp_statistics.IcmpOutErrors++;
 719                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 720                 kfree_skb(skb2,FREE_WRITE);
 721                 kfree_skb(skb, FREE_READ);
 722                 return;
 723         }
 724 
 725         /*
 726          *      Re-adjust length according to actual IP header size. 
 727          */
 728 
 729         skb_put(skb2,len);
 730 
 731         /*
 732          *      Build ICMP ADDRESS MASK Response message. 
 733          */
 734 
 735         icmphr = (struct icmphdr *) (skb2->data + offset);
 736         icmphr->type = ICMP_ADDRESSREPLY;
 737         icmphr->code = 0;
 738         icmphr->checksum = 0;
 739         icmphr->un.echo.id = icmph->un.echo.id;
 740         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 741         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 742 
 743         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 744 
 745         /* Ship it out - free it when done */
 746         ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
 747 #endif
 748         skb->sk = NULL;
 749         kfree_skb(skb, FREE_READ);
 750 }
 751 
 752 
 753 /* 
 754  *      Deal with incoming ICMP packets. 
 755  */
 756  
 757 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 758          unsigned long daddr, unsigned short len,
 759          unsigned long saddr, int redo, struct inet_protocol *protocol)
 760 {
 761         struct icmphdr *icmph;
 762         unsigned char *buff;
 763 
 764         /*
 765          *      Drop broadcast packets. IP has done a broadcast check and ought one day
 766          *      to pass on that information.
 767          */
 768         
 769         icmp_statistics.IcmpInMsgs++;
 770          
 771         
 772         /*
 773          *      Grab the packet as an icmp object
 774          */
 775 
 776         buff = skb1->h.raw;
 777         icmph = (struct icmphdr *) buff;
 778 
 779         /*
 780          *      Validate the packet first 
 781          */
 782 
 783         if (ip_compute_csum((unsigned char *) icmph, len)) 
 784         {
 785                 /* Failed checksum! */
 786                 icmp_statistics.IcmpInErrors++;
 787                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 788                 kfree_skb(skb1, FREE_READ);
 789                 return(0);
 790         }
 791 
 792         /*
 793          *      Parse the ICMP message 
 794          */
 795 
 796         if (ip_chk_addr(daddr) != IS_MYADDR)
 797         {
 798                 if (icmph->type != ICMP_ECHO) 
 799                 /* RFC1122: We're allowed to reply to ICMP_TIMESTAMP */
 800                 /* requests in the same manner as ICMP_ECHO (optionally */
 801                 /* drop those to a bcast/mcast), so perhaps we should be */
 802                 /* consistent? -- MS */
 803 
 804                 {
 805                         icmp_statistics.IcmpInErrors++;
 806                         kfree_skb(skb1, FREE_READ);
 807                         return(0);
 808                 }
 809                 daddr=dev->pa_addr;
 810         }
 811 
 812         switch(icmph->type) 
 813         {
 814                 case ICMP_TIME_EXCEEDED:
 815                         icmp_statistics.IcmpInTimeExcds++;
 816                         icmp_unreach(icmph, skb1);
 817                         return 0;
 818                 case ICMP_DEST_UNREACH:
 819                         icmp_statistics.IcmpInDestUnreachs++;
 820                         icmp_unreach(icmph, skb1);
 821                         return 0;
 822                 case ICMP_SOURCE_QUENCH:
 823                         icmp_statistics.IcmpInSrcQuenchs++;
 824                         icmp_unreach(icmph, skb1);
 825                         return(0);
 826                 case ICMP_REDIRECT:
 827                         icmp_statistics.IcmpInRedirects++;
 828                         icmp_redirect(icmph, skb1, dev, saddr);
 829                         return(0);
 830                 case ICMP_ECHO: 
 831                         icmp_statistics.IcmpInEchos++;
 832                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 833                         return 0;
 834                 case ICMP_ECHOREPLY:
 835                         icmp_statistics.IcmpInEchoReps++;
 836                         kfree_skb(skb1, FREE_READ);
 837                         return(0);
 838                 case ICMP_TIMESTAMP:
 839                         icmp_statistics.IcmpInTimestamps++;
 840                         icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
 841                         return 0;
 842                 case ICMP_TIMESTAMPREPLY:
 843                 /* RFC1122: MUST pass TIMESTAMPREPLY messages up to app layer, */
 844                 /* just as with ECHOREPLY.  You have to use raw to get that */
 845                 /* functionality, just as with ECHOREPLY. Close enough. -- MS */
 846                         icmp_statistics.IcmpInTimestampReps++;
 847                         kfree_skb(skb1,FREE_READ);
 848                         return 0;
 849                 /* INFO is obsolete and doesn't even feature in the SNMP stats */
 850                 case ICMP_INFO_REQUEST:
 851                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 852                         return 0;
 853                 case ICMP_INFO_REPLY:
 854                         skb1->sk = NULL;
 855                         kfree_skb(skb1, FREE_READ);
 856                         return(0);
 857                 case ICMP_ADDRESS:
 858                         icmp_statistics.IcmpInAddrMasks++;
 859                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 860                         return 0;
 861                 case ICMP_ADDRESSREPLY:
 862                         /*
 863                          *      We ought to set our netmask on receiving this, but 
 864                          *      experience shows it's a waste of effort.
 865                          */
 866                         icmp_statistics.IcmpInAddrMaskReps++;
 867                         kfree_skb(skb1, FREE_READ);
 868                         return(0);
 869                 default:
 870                         /* RFC1122: OK.  Silently discarding weird ICMP (MUST), */
 871                         /* as per 3.2.2. -- MS */
 872                         icmp_statistics.IcmpInErrors++;
 873                         kfree_skb(skb1, FREE_READ);
 874                         return(0);
 875         }
 876   /*NOTREACHED*/
 877         kfree_skb(skb1, FREE_READ);
 878         return(-1);
 879 }
 880 
 881 
 882 /*
 883  *      Perform any ICMP-related I/O control requests. 
 884  *      [to vanish soon]
 885  */
 886  
 887 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 888 {
 889         switch(cmd) 
 890         {
 891                 default:
 892                         return(-EINVAL);
 893         }
 894         return(0);
 895 }

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