home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / net / inet / icmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-06  |  17.6 KB  |  775 lines

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