home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / net / inet / icmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-01  |  11.5 KB  |  444 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.  *
  14.  * Fixes:    
  15.  *        Alan Cox    :    Generic queue usage.
  16.  *        Gerhard Koerting:    ICMP addressing corrected
  17.  *        Alan Cox    :    Use tos/ttl settings
  18.  *
  19.  *
  20.  *        This program is free software; you can redistribute it and/or
  21.  *        modify it under the terms of the GNU General Public License
  22.  *        as published by the Free Software Foundation; either version
  23.  *        2 of the License, or (at your option) any later version.
  24.  */
  25. #include <linux/types.h>
  26. #include <linux/sched.h>
  27. #include <linux/kernel.h>
  28. #include <linux/fcntl.h>
  29. #include <linux/socket.h>
  30. #include <linux/in.h>
  31. #include "inet.h"
  32. #include "dev.h"
  33. #include "ip.h"
  34. #include "route.h"
  35. #include "protocol.h"
  36. #include "icmp.h"
  37. #include "tcp.h"
  38. #include "skbuff.h"
  39. #include "sock.h"
  40. #include <linux/errno.h>
  41. #include <linux/timer.h>
  42. #include <asm/system.h>
  43. #include <asm/segment.h>
  44.  
  45.  
  46. #define min(a,b)    ((a)<(b)?(a):(b))
  47.  
  48.  
  49. /* An array of errno for error messages from dest unreach. */
  50. struct icmp_err icmp_err_convert[] = {
  51.   { ENETUNREACH,    1 },    /*    ICMP_NET_UNREACH    */
  52.   { EHOSTUNREACH,    1 },    /*    ICMP_HOST_UNREACH    */
  53.   { ENOPROTOOPT,    1 },    /*    ICMP_PROT_UNREACH    */
  54.   { ECONNREFUSED,    1 },    /*    ICMP_PORT_UNREACH    */
  55.   { EOPNOTSUPP,        0 },    /*    ICMP_FRAG_NEEDED    */
  56.   { EOPNOTSUPP,        0 },    /*    ICMP_SR_FAILED        */
  57.   { ENETUNREACH,    1 },    /*     ICMP_NET_UNKNOWN    */
  58.   { EHOSTDOWN,        1 },    /*    ICMP_HOST_UNKNOWN    */
  59.   { ENONET,        1 },    /*    ICMP_HOST_ISOLATED    */
  60.   { ENETUNREACH,    1 },    /*    ICMP_NET_ANO        */
  61.   { EHOSTUNREACH,    1 },    /*    ICMP_HOST_ANO        */
  62.   { EOPNOTSUPP,        0 },    /*    ICMP_NET_UNR_TOS    */
  63.   { EOPNOTSUPP,        0 }    /*    ICMP_HOST_UNR_TOS    */
  64. };
  65.  
  66.  
  67. /* Display the contents of an ICMP header. */
  68. static void
  69. print_icmp(struct icmphdr *icmph)
  70. {
  71.   if (inet_debug != DBG_ICMP) return;
  72.  
  73.   printk("ICMP: type = %d, code = %d, checksum = %X\n",
  74.             icmph->type, icmph->code, icmph->checksum);
  75.   printk("      gateway = %s\n", in_ntoa(icmph->un.gateway));
  76. }
  77.  
  78.  
  79. /* Send an ICMP message. */
  80. void
  81. icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
  82. {
  83.   struct sk_buff *skb;
  84.   struct iphdr *iph;
  85.   int offset;
  86.   struct icmphdr *icmph;
  87.   int len;
  88.  
  89.   DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
  90.                            skb_in, type, code, dev));
  91.  
  92.   /* Get some memory for the reply. */
  93.   len = sizeof(struct sk_buff) + dev->hard_header_len +
  94.     sizeof(struct iphdr) + sizeof(struct icmphdr) +
  95.     sizeof(struct iphdr) + 8;    /* amount of header to return */
  96.        
  97.   skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
  98.   if (skb == NULL) 
  99.       return;
  100.  
  101.   skb->sk = NULL;
  102.   skb->mem_addr = skb;
  103.   skb->mem_len = len;
  104.   len -= sizeof(struct sk_buff);
  105.  
  106.   /* Find the IP header. */
  107.   iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
  108.  
  109.   /* Build Layer 2-3 headers for message back to source. */
  110.   offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
  111.                &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
  112.   if (offset < 0) {
  113.     skb->sk = NULL;
  114.     kfree_skb(skb, FREE_READ);
  115.     return;
  116.   }
  117.  
  118.   /* Re-adjust length according to actual IP header size. */
  119.   skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
  120.   icmph = (struct icmphdr *) (skb->data + offset);
  121.   icmph->type = type;
  122.   icmph->code = code;
  123.   icmph->checksum = 0;
  124.   icmph->un.gateway = 0;
  125.   memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
  126.  
  127.   icmph->checksum = ip_compute_csum((unsigned char *)icmph,
  128.                          sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
  129.  
  130.   DPRINTF((DBG_ICMP, ">>\n"));
  131.   print_icmp(icmph);
  132.  
  133.   /* Send it and free it. */
  134.   ip_queue_xmit(NULL, dev, skb, 1);
  135. }
  136.  
  137.  
  138. /* Handle ICMP_UNREACH and ICMP_QUENCH. */
  139. static void
  140. icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
  141. {
  142.   struct inet_protocol *ipprot;
  143.   struct iphdr *iph;
  144.   unsigned char hash;
  145.   int err;
  146.  
  147.   err = (icmph->type << 8) | icmph->code;
  148.   iph = (struct iphdr *) (icmph + 1);
  149.   switch(icmph->code & 7) {
  150.     case ICMP_NET_UNREACH:
  151.         DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
  152.                             in_ntoa(iph->daddr)));
  153.         break;
  154.     case ICMP_HOST_UNREACH:
  155.         DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
  156.                         in_ntoa(iph->daddr)));
  157.         break;
  158.     case ICMP_PROT_UNREACH:
  159.         printk("ICMP: %s:%d: protocol unreachable.\n",
  160.             in_ntoa(iph->daddr), ntohs(iph->protocol));
  161.         break;
  162.     case ICMP_PORT_UNREACH:
  163.         DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
  164.             in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
  165.         break;
  166.     case ICMP_FRAG_NEEDED:
  167.         printk("ICMP: %s: fragmentation needed and DF set.\n",
  168.                             in_ntoa(iph->daddr));
  169.         break;
  170.     case ICMP_SR_FAILED:
  171.         printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
  172.         break;
  173.     default:
  174.         DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
  175.                     (icmph->code & 7), in_ntoa(iph->daddr)));
  176.         break;
  177.   }
  178.  
  179.   /* Get the protocol(s). */
  180.   hash = iph->protocol & (MAX_INET_PROTOS -1);
  181.  
  182.   /* This can change while we are doing it. */
  183.   ipprot = (struct inet_protocol *) inet_protos[hash];
  184.   while(ipprot != NULL) {
  185.     struct inet_protocol *nextip;
  186.  
  187.     nextip = (struct inet_protocol *) ipprot->next;
  188.  
  189.     /* Pass it off to everyone who wants it. */
  190.     if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
  191.         ipprot->err_handler(err, (unsigned char *)(icmph + 1),
  192.                     iph->daddr, iph->saddr, ipprot);
  193.     }
  194.  
  195.     ipprot = nextip;
  196.   }
  197.   skb->sk = NULL;
  198.   kfree_skb(skb, FREE_READ);
  199. }
  200.  
  201.  
  202. /* Handle ICMP_REDIRECT. */
  203. static void
  204. icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
  205. {
  206.   struct iphdr *iph;
  207.   unsigned long ip;
  208.  
  209.   iph = (struct iphdr *) (icmph + 1);
  210.   ip = iph->daddr;
  211.   switch(icmph->code & 7) {
  212.     case ICMP_REDIR_NET:
  213. #ifdef not_a_good_idea
  214.         rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
  215.             ip, 0, icmph->un.gateway, dev);
  216.         break;
  217. #endif
  218.     case ICMP_REDIR_HOST:
  219.         rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
  220.             ip, 0, icmph->un.gateway, dev);
  221.         break;
  222.     case ICMP_REDIR_NETTOS:
  223.     case ICMP_REDIR_HOSTTOS:
  224.         printk("ICMP: cannot handle TOS redirects yet!\n");
  225.         break;
  226.     default:
  227.         DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
  228.                         (icmph->code & 7)));
  229.         break;
  230.   }
  231.   skb->sk = NULL;
  232.   kfree_skb(skb, FREE_READ);
  233. }
  234.  
  235.  
  236. /* Handle ICMP_ECHO ("ping") requests. */
  237. static void
  238. icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
  239.       unsigned long saddr, unsigned long daddr, int len,
  240.       struct options *opt)
  241. {
  242.   struct icmphdr *icmphr;
  243.   struct sk_buff *skb2;
  244.   int size, offset;
  245.  
  246.   size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
  247.   skb2 = alloc_skb(size, GFP_ATOMIC);
  248.   if (skb2 == NULL) {
  249.     skb->sk = NULL;
  250.     kfree_skb(skb, FREE_READ);
  251.     return;
  252.   }
  253.   skb2->sk = NULL;
  254.   skb2->mem_addr = skb2;
  255.   skb2->mem_len = size;
  256.   skb2->free = 1;
  257.  
  258.   /* Build Layer 2-3 headers for message back to source */
  259.   offset = ip_build_header(skb2, daddr, saddr, &dev,
  260.                  IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
  261.   if (offset < 0) {
  262.     printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
  263.     kfree_skb(skb2,FREE_WRITE);
  264.     skb->sk = NULL;
  265.     kfree_skb(skb, FREE_READ);
  266.     return;
  267.   }
  268.  
  269.   /* Re-adjust length according to actual IP header size. */
  270.   skb2->len = offset + len;
  271.  
  272.   /* Build ICMP_ECHO Response message. */
  273.   icmphr = (struct icmphdr *) (skb2->data + offset);
  274.   memcpy((char *) icmphr, (char *) icmph, len);
  275.   icmphr->type = ICMP_ECHOREPLY;
  276.   icmphr->code = 0;
  277.   icmphr->checksum = 0;
  278.   icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
  279.  
  280.   /* Ship it out - free it when done */
  281.   ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
  282.  
  283.   skb->sk = NULL;
  284.   kfree_skb(skb, FREE_READ);
  285. }
  286.  
  287.  
  288. /* Handle the ICMP INFORMATION REQUEST. */
  289. static void
  290. icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
  291.       unsigned long saddr, unsigned long daddr, int len,
  292.       struct options *opt)
  293. {
  294.   /* NOT YET */
  295.   skb->sk = NULL;
  296.   kfree_skb(skb, FREE_READ);
  297. }
  298.  
  299.  
  300. /* Handle ICMP_ADRESS_MASK requests. */
  301. static void
  302. icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
  303.       unsigned long saddr, unsigned long daddr, int len,
  304.       struct options *opt)
  305. {
  306.   struct icmphdr *icmphr;
  307.   struct sk_buff *skb2;
  308.   int size, offset;
  309.  
  310.   size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
  311.   skb2 = alloc_skb(size, GFP_ATOMIC);
  312.   if (skb2 == NULL) {
  313.     skb->sk = NULL;
  314.     kfree_skb(skb, FREE_READ);
  315.     return;
  316.   }
  317.   skb2->sk = NULL;
  318.   skb2->mem_addr = skb2;
  319.   skb2->mem_len = size;
  320.   skb2->free = 1;
  321.  
  322.   /* Build Layer 2-3 headers for message back to source */
  323.   offset = ip_build_header(skb2, daddr, saddr, &dev,
  324.                  IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
  325.   if (offset < 0) {
  326.     printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
  327.     kfree_skb(skb2,FREE_WRITE);
  328.     skb->sk = NULL;
  329.     kfree_skb(skb, FREE_READ);
  330.     return;
  331.   }
  332.  
  333.   /* Re-adjust length according to actual IP header size. */
  334.   skb2->len = offset + len;
  335.  
  336.   /* Build ICMP ADDRESS MASK Response message. */
  337.   icmphr = (struct icmphdr *) (skb2->data + offset);
  338.   icmphr->type = ICMP_ADDRESSREPLY;
  339.   icmphr->code = 0;
  340.   icmphr->checksum = 0;
  341.   icmphr->un.echo.id = icmph->un.echo.id;
  342.   icmphr->un.echo.sequence = icmph->un.echo.sequence;
  343.   memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
  344.  
  345.   icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
  346.  
  347.   /* Ship it out - free it when done */
  348.   ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
  349.  
  350.   skb->sk = NULL;
  351.   kfree_skb(skb, FREE_READ);
  352. }
  353.  
  354.  
  355. /* Deal with incoming ICMP packets. */
  356. int
  357. icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
  358.      unsigned long daddr, unsigned short len,
  359.      unsigned long saddr, int redo, struct inet_protocol *protocol)
  360. {
  361.   struct icmphdr *icmph;
  362.   unsigned char *buff;
  363.  
  364.   /* Drop broadcast packets. */
  365.   if (chk_addr(daddr) == IS_BROADCAST) {
  366.     DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
  367.                             in_ntoa(saddr)));
  368.     skb1->sk = NULL;
  369.     kfree_skb(skb1, FREE_READ);
  370.     return(0);
  371.   }
  372.  
  373.   buff = skb1->h.raw;
  374.   icmph = (struct icmphdr *) buff;
  375.  
  376.   /* Validate the packet first */
  377.   if (ip_compute_csum((unsigned char *) icmph, len)) {
  378.     /* Failed checksum! */
  379.     printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
  380.     skb1->sk = NULL;
  381.     kfree_skb(skb1, FREE_READ);
  382.     return(0);
  383.   }
  384.   print_icmp(icmph);
  385.  
  386.   /* Parse the ICMP message */
  387.   switch(icmph->type) {
  388.     case ICMP_TIME_EXCEEDED:
  389.     case ICMP_DEST_UNREACH:
  390.     case ICMP_SOURCE_QUENCH:
  391.         icmp_unreach(icmph, skb1);
  392.         return(0);
  393.     case ICMP_REDIRECT:
  394.         icmp_redirect(icmph, skb1, dev);
  395.         return(0);
  396.     case ICMP_ECHO: 
  397.         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
  398.         return 0;
  399.     case ICMP_ECHOREPLY:
  400.         skb1->sk = NULL;
  401.         kfree_skb(skb1, FREE_READ);
  402.         return(0);
  403.     case ICMP_INFO_REQUEST:
  404.         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
  405.         return 0;
  406.     case ICMP_INFO_REPLY:
  407.         skb1->sk = NULL;
  408.         kfree_skb(skb1, FREE_READ);
  409.         return(0);
  410.     case ICMP_ADDRESS:
  411.         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
  412.         return 0;
  413.     case ICMP_ADDRESSREPLY:
  414.         skb1->sk = NULL;
  415.         kfree_skb(skb1, FREE_READ);
  416.         return(0);
  417.     default:
  418.         DPRINTF((DBG_ICMP,
  419.             "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
  420.                         in_ntoa(saddr), icmph->type));
  421.         skb1->sk = NULL;
  422.         kfree_skb(skb1, FREE_READ);
  423.         return(0);
  424.   }
  425.   /*NOTREACHED*/
  426.   skb1->sk = NULL;
  427.   kfree_skb(skb1, FREE_READ);
  428.   return(-1);
  429. }
  430.  
  431.  
  432. /* Perform any ICMP-related I/O control requests. */
  433. int
  434. icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
  435. {
  436.   switch(cmd) {
  437.     case DDIOCSDBG:
  438.         return(dbg_ioctl((void *) arg, DBG_ICMP));
  439.     default:
  440.         return(-EINVAL);
  441.   }
  442.   return(0);
  443. }
  444.