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

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