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

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