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

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