root/net/tcp/icmp.c

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

DEFINITIONS

This source file includes following definitions.
  1. print_icmph
  2. icmp_reply
  3. icmp_rcv

   1 /* Internet Control Message Protocol (ICMP) icmp.c */
   2 
   3 /*
   4     Copyright (C) 1992  Bob Harris
   5 
   6     This program is free software; you can redistribute it and/or modify
   7     it under the terms of the GNU General Public License as published by
   8     the Free Software Foundation; either version 2, or (at your option)
   9     any later version.
  10 
  11     This program is distributed in the hope that it will be useful,
  12     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14     GNU General Public License for more details.
  15 
  16     You should have received a copy of the GNU General Public License
  17     along with this program; if not, write to the Free Software
  18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  19 
  20     The Author of tcpip package may be reached as bir7@leland.stanford.edu or
  21     C/O Department of Mathematics; Stanford University; Stanford, CA 94305
  22 
  23     The author of this file may be reached at rth@sparta.com or Sparta, Inc.
  24     7926 Jones Branch Dr. Suite 900, McLean Va 22102.
  25 */
  26 /* $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ */
  27 /* $Log: icmp.c,v $
  28  * Revision 0.8.4.9  1993/01/23  18:00:11  bir7
  29  * added volatile keyword to many variables.
  30  *
  31  * Revision 0.8.4.8  1993/01/22  23:21:38  bir7
  32  * Merged with 99 pl4
  33  *
  34  * Revision 0.8.4.7  1992/12/12  19:25:04  bir7
  35  * Cleaned up Log messages.
  36  *
  37  * Revision 0.8.4.6  1992/12/12  01:50:49  bir7
  38  * Fixed bug in call to err routine.
  39  *
  40  * Revision 0.8.4.5  1992/12/05  21:35:53  bir7
  41  * fixed type mismatch.
  42  *
  43  * Revision 0.8.4.4  1992/12/03  19:52:20  bir7
  44  * Fixed minor pugs in icmp_reply.
  45  *
  46  * Revision 0.8.4.3  1992/11/18  15:38:03  bir7
  47  * Fixed some printk's.
  48  *
  49  * Revision 0.8.4.2  1992/11/10  10:38:48  bir7
  50  * Change free_s to kfree_s and accidently changed free_skb to kfree_skb.
  51  *
  52  * Revision 0.8.4.1  1992/11/10  00:17:18  bir7
  53  * version change only.
  54  *
  55  * Revision 0.8.3.3  1992/11/10  00:14:47  bir7
  56  * Changed malloc to kmalloc and added Id and Log
  57  *
  58  */
  59 
  60 /* modified by Ross Biro bir7@leland.stanford.edu to do more than just
  61    echo responses. */
  62 
  63 #include <linux/types.h>
  64 #include <linux/sched.h>
  65 #include <linux/kernel.h>       /* kfree_s */
  66 #include <linux/fcntl.h>
  67 #include <linux/socket.h>
  68 #include <netinet/in.h>
  69 #include "timer.h"
  70 #include "ip.h"
  71 #include "tcp.h"
  72 #include "sock.h"
  73 #include <linux/errno.h>
  74 #include <linux/timer.h>
  75 #include <asm/system.h>
  76 #include <asm/segment.h>
  77 #include "icmp.h"
  78 #ifdef PRINTK
  79 #undef PRINTK
  80 #endif
  81 
  82 #undef ICMP_DEBUG
  83 
  84 #ifdef ICMP_DEBUG
  85 #define PRINTK(x) printk x
  86 #else
  87 #define PRINTK(x) /**/
  88 #endif
  89 
  90 #define min(a,b) ((a)<(b)?(a):(b))
  91 
  92 /* an array of errno for error messages from dest unreach. */
  93 struct icmp_err icmp_err_convert[]=
  94 {
  95    {ENETUNREACH, 1},
  96    {EHOSTUNREACH, 1},
  97    {ENOPROTOOPT, 1},
  98    {ECONNREFUSED, 1},
  99    {EOPNOTSUPP, 0},
 100    {EOPNOTSUPP, 0},
 101    {ENETUNREACH, 1},
 102    {EHOSTDOWN, 1},
 103    {ENONET, 1},
 104    {ENETUNREACH, 1},
 105    {EHOSTUNREACH, 1},
 106    {EOPNOTSUPP, 0},
 107    {EOPNOTSUPP, 0}
 108 };
 109 
 110 void
 111 print_icmph (struct icmp_header *icmph)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113    PRINTK (("  type = %d, code = %d, checksum = %X\n", icmph->type,
 114            icmph->code, icmph->checksum));
 115    PRINTK ((" gateway = %X\n", icmph->un.gateway));
 116 }
 117 
 118 /* sends an icmp message in response to a packet. */
 119 void
 120 icmp_reply (struct sk_buff *skb_in,  int type, int code, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122    struct sk_buff *skb;
 123    struct ip_header *iph;
 124    int offset;
 125    struct icmp_header *icmph;
 126    int len;
 127 
 128    PRINTK (("icmp_reply (skb_in = %X, type = %d, code = %d, dev=%X)\n",
 129            skb_in, type, code, dev));
 130 
 131    /* get some memory for the reply. */
 132    len = sizeof (*skb) + 8 /* amount of header to return. */ +
 133          sizeof (struct icmp_header) +
 134          64 /* enough for an ip header. */ +
 135          dev->hard_header_len;
 136            
 137    skb = kmalloc (len, GFP_ATOMIC);
 138    if (skb == NULL) return;
 139 
 140    skb->lock = 0;
 141    skb->mem_addr = skb;
 142    skb->mem_len = len;
 143 
 144    len -= sizeof (*skb);
 145 
 146    /* find the ip header. */
 147    iph = (struct ip_header *)(skb_in+1);
 148    iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len);
 149 
 150    /* Build Layer 2-3 headers for message back to source */
 151    offset = ip_build_header( skb, iph->daddr, iph->saddr,
 152                             &dev, IPPROTO_ICMP, NULL, len );
 153 
 154    if (offset < 0)
 155      {
 156         skb->sk = NULL;
 157         kfree_skb (skb, FREE_READ);
 158         return;
 159      }
 160 
 161    /* Readjust length according to actual IP header size */
 162    skb->len = offset + sizeof (struct icmp_header) + 8;
 163    
 164    icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset);
 165    icmph->type = type;
 166    icmph->code = code;
 167    icmph->checksum = 0; /* we don't need to compute this. */
 168    icmph->un.gateway = 0; /* might as well 0 it. */
 169    memcpy (icmph+1, iph+1, 8);
 170    /* send it and free it. */
 171    ip_queue_xmit (NULL, dev, skb, 1);
 172    
 173 }
 174 
 175 /* deals with incoming icmp packets. */
 176 
 177 int
 178 icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 179         unsigned long daddr, unsigned short len,
 180         unsigned long saddr, int redo, struct ip_protocol *protocol )
 181 {
 182    int size, offset;
 183    struct icmp_header *icmph, *icmphr;
 184    struct sk_buff *skb;
 185    unsigned char *buff;
 186 
 187 
 188    /* drop broadcast packets.  */
 189    if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000)
 190      {
 191         skb1->sk = NULL;
 192         kfree_skb (skb1, FREE_READ);
 193         return (0);
 194      }
 195 
 196    buff = skb1->h.raw;
 197 
 198    icmph = (struct icmp_header *)buff;
 199 
 200    /* Validate the packet first */
 201    if( icmph->checksum )
 202      { /* Checksums Enabled? */
 203         if( ip_compute_csum( (unsigned char *)icmph, len ) )
 204           {
 205              /* Failed checksum! */
 206              PRINTK(("ICMP ECHO failed checksum!\n"));
 207              skb1->sk = NULL;
 208              kfree_skb (skb1, FREE_READ);
 209              return (0);
 210           }
 211      }
 212 
 213    print_icmph(icmph);
 214 
 215    /* Parse the ICMP message */
 216    switch( icmph->type )
 217      {
 218        case ICMP_DEST_UNREACH:
 219        case ICMP_SOURCE_QUENCH:
 220         {
 221            struct ip_header *iph;
 222            struct ip_protocol *ipprot;
 223            unsigned char hash;
 224            int err;
 225 
 226            err = icmph->type << 8 | icmph->code;
 227 
 228            /* we need to cause the socket to be closed and the error message
 229               to be set appropriately. */
 230            iph = (struct ip_header *)(icmph+1);
 231 
 232            /* get the protocol(s) */
 233            hash = iph->protocol & (MAX_IP_PROTOS -1 );
 234 
 235            /* this can change while we are doing it. */
 236            for (ipprot = (struct ip_protocol *)ip_protos[hash];
 237                 ipprot != NULL; )
 238              {
 239                struct ip_protocol *nextip;
 240                nextip = (struct ip_protocol *)ipprot->next;
 241                /* pass it off to everyone who wants it. */
 242                if (iph->protocol == ipprot->protocol && ipprot->err_handler)
 243                  ipprot->err_handler (err, (unsigned char *)(icmph+1),
 244                                      iph->daddr, iph->saddr, ipprot);
 245                ipprot = nextip;
 246              }
 247 
 248            skb1->sk = NULL;
 249            kfree_skb (skb1, FREE_READ);
 250            return (0);
 251         }
 252 
 253        case ICMP_REDIRECT:
 254         {
 255            /* we need to put a new route in the routing table. */
 256            struct rtable *rt; /* we will add a new route. */
 257            struct ip_header *iph;
 258 
 259            iph = (struct ip_header *)(icmph+1);
 260            rt = kmalloc (sizeof (*rt), GFP_ATOMIC);
 261            if (rt != NULL)
 262              {
 263                 rt->net = iph->daddr;
 264                 /* assume class C network.  Technically this is incorrect,
 265                    but will give it a try. */
 266                 if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff;
 267                 rt->dev = dev;
 268                 rt->router = icmph->un.gateway;
 269                 add_route (rt);
 270              }
 271            skb1->sk = NULL;
 272            kfree_skb (skb1, FREE_READ);
 273            return (0);
 274         }
 275 
 276        case ICMP_ECHO: 
 277         
 278         /* Allocate an sk_buff response buffer (assume 64 byte IP header) */
 279 
 280         size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len;
 281         skb = kmalloc( size, GFP_ATOMIC );
 282         if (skb == NULL)
 283           {
 284              skb1->sk = NULL;
 285              kfree_skb (skb1, FREE_READ);
 286              return (0);
 287           }
 288         skb->sk = NULL;
 289         skb->lock = 0;
 290         skb->mem_addr = skb;
 291         skb->mem_len = size;
 292 
 293         /* Build Layer 2-3 headers for message back to source */
 294         offset = ip_build_header( skb, daddr, saddr, &dev, IPPROTO_ICMP, opt, len );
 295         if (offset < 0)
 296           {
 297              /* Problems building header */
 298              PRINTK(("Could not build IP Header for ICMP ECHO Response\n"));
 299              kfree_s (skb->mem_addr, skb->mem_len);
 300              skb1->sk = NULL;
 301              kfree_skb (skb1, FREE_READ);
 302              return( 0 ); /* just toss the received packet */
 303           }
 304 
 305         /* Readjust length according to actual IP header size */
 306         skb->len = offset + len;
 307 
 308         /* Build ICMP_ECHO Response message */
 309         icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset );
 310         memcpy( (char *)icmphr, (char *)icmph, len );
 311         icmphr->type = ICMP_ECHOREPLY;
 312         icmphr->code = 0;
 313         icmphr->checksum = 0;
 314 
 315         if( icmph->checksum )
 316           { /* Calculate Checksum */
 317              icmphr->checksum = ip_compute_csum( (void *)icmphr, len );
 318           }
 319 
 320         /* Ship it out - free it when done */
 321         ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 );
 322         
 323         skb1->sk = NULL;
 324         kfree_skb (skb1, FREE_READ);
 325         return( 0 );
 326 
 327         default:
 328         PRINTK(("Unsupported ICMP type = x%x\n", icmph->type ));
 329         skb1->sk = NULL;
 330         kfree_skb (skb1, FREE_READ);
 331         return( 0 ); /* just toss the packet */
 332      }
 333 
 334    /* should be unecessary, but just in case. */
 335    skb1->sk = NULL;
 336    kfree_skb (skb1, FREE_READ);
 337    return( 0 ); /* just toss the packet */
 338 }
 339 

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