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 #ifdef ICMP_DEBUG
  78 #define PRINTK printk
  79 #else
  80 #define PRINTK dummy_routine
  81 #endif
  82 
  83 #define min(a,b) ((a)<(b)?(a):(b))
  84 
  85 /* an array of errno for error messages from dest unreach. */
  86 struct icmp_err icmp_err_convert[]=
  87 {
  88    {ENETUNREACH, 1},
  89    {EHOSTUNREACH, 1},
  90    {ENOPROTOOPT, 1},
  91    {ECONNREFUSED, 1},
  92    {EOPNOTSUPP, 0},
  93    {EOPNOTSUPP, 0},
  94    {ENETUNREACH, 1},
  95    {EHOSTDOWN, 1},
  96    {ENONET, 1},
  97    {ENETUNREACH, 1},
  98    {EHOSTUNREACH, 1},
  99    {EOPNOTSUPP, 0},
 100    {EOPNOTSUPP, 0}
 101 };
 102 
 103 void
 104 print_icmph (struct icmp_header *icmph)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106    PRINTK ("  type = %d, code = %d, checksum = %X\n", icmph->type,
 107            icmph->code, icmph->checksum);
 108    PRINTK (" gateway = %X\n", icmph->un.gateway);
 109 }
 110 
 111 /* sends an icmp message in response to a packet. */
 112 void
 113 icmp_reply (struct sk_buff *skb_in,  int type, int code, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115    struct sk_buff *skb;
 116    struct ip_header *iph;
 117    int offset;
 118    struct icmp_header *icmph;
 119    int len;
 120 
 121    PRINTK ("icmp_reply (skb_in = %X, type = %d, code = %d, dev=%X)\n",
 122            skb_in, type, code, dev);
 123 
 124    /* get some memory for the reply. */
 125    len = sizeof (*skb) + 8 /* amount of header to return. */ +
 126          sizeof (struct icmp_header) +
 127          64 /* enough for an ip header. */ +
 128          dev->hard_header_len;
 129            
 130    skb = kmalloc (len, GFP_ATOMIC);
 131    if (skb == NULL) return;
 132 
 133    skb->lock = 0;
 134    skb->mem_addr = skb;
 135    skb->mem_len = len;
 136 
 137    len -= sizeof (*skb);
 138 
 139    /* find the ip header. */
 140    iph = (struct ip_header *)(skb_in+1);
 141    iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len);
 142 
 143    /* Build Layer 2-3 headers for message back to source */
 144    offset = ip_build_header( skb, iph->daddr, iph->saddr,
 145                             &dev, IPPROTO_ICMP, NULL, len );
 146 
 147    if (offset < 0)
 148      {
 149         skb->sk = NULL;
 150         kfree_skb (skb, FREE_READ);
 151         return;
 152      }
 153 
 154    /* Readjust length according to actual IP header size */
 155    skb->len = offset + sizeof (struct icmp_header) + 8;
 156    
 157    icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset);
 158    icmph->type = type;
 159    icmph->code = code;
 160    icmph->checksum = 0; /* we don't need to compute this. */
 161    icmph->un.gateway = 0; /* might as well 0 it. */
 162    memcpy (icmph+1, iph+1, 8);
 163    /* send it and free it. */
 164    ip_queue_xmit (NULL, dev, skb, 1);
 165    
 166 }
 167 
 168 /* deals with incoming icmp packets. */
 169 
 170 int
 171 icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 172         unsigned long daddr, unsigned short len,
 173         unsigned long saddr, int redo, struct ip_protocol *protocol )
 174 {
 175    int size, offset;
 176    struct icmp_header *icmph, *icmphr;
 177    struct sk_buff *skb;
 178    unsigned char *buff;
 179 
 180 
 181    /* drop broadcast packets.  */
 182    if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000)
 183      {
 184         skb1->sk = NULL;
 185         kfree_skb (skb1, FREE_READ);
 186         return (0);
 187      }
 188 
 189    buff = skb1->h.raw;
 190 
 191    icmph = (struct icmp_header *)buff;
 192 
 193    /* Validate the packet first */
 194    if( icmph->checksum )
 195      { /* Checksums Enabled? */
 196         if( ip_compute_csum( (unsigned char *)icmph, len ) )
 197           {
 198              /* Failed checksum! */
 199              PRINTK("ICMP ECHO failed checksum!\n");
 200              skb1->sk = NULL;
 201              kfree_skb (skb1, FREE_READ);
 202              return (0);
 203           }
 204      }
 205 
 206    print_icmph(icmph);
 207 
 208    /* Parse the ICMP message */
 209    switch( icmph->type )
 210      {
 211        case ICMP_DEST_UNREACH:
 212        case ICMP_SOURCE_QUENCH:
 213         {
 214            struct ip_header *iph;
 215            struct ip_protocol *ipprot;
 216            unsigned char hash;
 217            int err;
 218 
 219            err = icmph->type << 8 | icmph->code;
 220 
 221            /* we need to cause the socket to be closed and the error message
 222               to be set appropriately. */
 223            iph = (struct ip_header *)(icmph+1);
 224 
 225            /* get the protocol(s) */
 226            hash = iph->protocol & (MAX_IP_PROTOS -1 );
 227 
 228            /* this can change while we are doing it. */
 229            for (ipprot = ip_protos[hash]; ipprot != NULL; )
 230              {
 231                struct ip_protocol *nextip;
 232                nextip = ipprot->next;
 233                /* pass it off to everyone who wants it. */
 234                if (iph->protocol == ipprot->protocol && ipprot->err_handler)
 235                  ipprot->err_handler (err, (unsigned char *)(icmph+1),
 236                                      iph->daddr, iph->saddr, ipprot);
 237                ipprot = nextip;
 238              }
 239 
 240            skb1->sk = NULL;
 241            kfree_skb (skb1, FREE_READ);
 242            return (0);
 243         }
 244 
 245        case ICMP_REDIRECT:
 246         {
 247            /* we need to put a new route in the routing table. */
 248            struct rtable *rt; /* we will add a new route. */
 249            struct ip_header *iph;
 250 
 251            iph = (struct ip_header *)(icmph+1);
 252            rt = kmalloc (sizeof (*rt), GFP_ATOMIC);
 253            if (rt != NULL)
 254              {
 255                 rt->net = iph->daddr;
 256                 /* assume class C network.  Technically this is incorrect,
 257                    but will give it a try. */
 258                 if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff;
 259                 rt->dev = dev;
 260                 rt->router = icmph->un.gateway;
 261                 add_route (rt);
 262              }
 263            skb1->sk = NULL;
 264            kfree_skb (skb1, FREE_READ);
 265            return (0);
 266         }
 267 
 268        case ICMP_ECHO: 
 269         
 270         /* Allocate an sk_buff response buffer (assume 64 byte IP header) */
 271 
 272         size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len;
 273         skb = kmalloc( size, GFP_ATOMIC );
 274         if (skb == NULL)
 275           {
 276              skb1->sk = NULL;
 277              kfree_skb (skb1, FREE_READ);
 278              return (0);
 279           }
 280         skb->sk = NULL;
 281         skb->lock = 0;
 282         skb->mem_addr = skb;
 283         skb->mem_len = size;
 284 
 285         /* Build Layer 2-3 headers for message back to source */
 286         offset = ip_build_header( skb, daddr, saddr, &dev, IPPROTO_ICMP, opt, len );
 287         if (offset < 0)
 288           {
 289              /* Problems building header */
 290              PRINTK("Could not build IP Header for ICMP ECHO Response\n");
 291              kfree_s (skb->mem_addr, skb->mem_len);
 292              skb1->sk = NULL;
 293              kfree_skb (skb1, FREE_READ);
 294              return( 0 ); /* just toss the received packet */
 295           }
 296 
 297         /* Readjust length according to actual IP header size */
 298         skb->len = offset + len;
 299 
 300         /* Build ICMP_ECHO Response message */
 301         icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset );
 302         memcpy( (char *)icmphr, (char *)icmph, len );
 303         icmphr->type = ICMP_ECHOREPLY;
 304         icmphr->code = 0;
 305         icmphr->checksum = 0;
 306 
 307         if( icmph->checksum )
 308           { /* Calculate Checksum */
 309              icmphr->checksum = ip_compute_csum( (void *)icmphr, len );
 310           }
 311 
 312         /* Ship it out - free it when done */
 313         ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 );
 314         
 315         skb1->sk = NULL;
 316         kfree_skb (skb1, FREE_READ);
 317         return( 0 );
 318 
 319         default:
 320         PRINTK("Unsupported ICMP type = x%x\n", icmph->type );
 321         skb1->sk = NULL;
 322         kfree_skb (skb1, FREE_READ);
 323         return( 0 ); /* just toss the packet */
 324      }
 325 
 326    /* should be unecessary, but just in case. */
 327    skb1->sk = NULL;
 328    kfree_skb (skb1, FREE_READ);
 329    return( 0 ); /* just toss the packet */
 330 }
 331 

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