root/net/inet/icmp.c

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

DEFINITIONS

This source file includes following definitions.
  1. print_icmp
  2. icmp_send
  3. icmp_unreach
  4. icmp_redirect
  5. icmp_echo
  6. icmp_info
  7. icmp_address
  8. icmp_rcv
  9. icmp_ioctl

   1 /*
   2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3  *              operating system.  INET is implemented using the  BSD Socket
   4  *              interface as the means of communication with the user level.
   5  *
   6  *              Internet Control Message Protocol (ICMP)
   7  *
   8  * Version:     @(#)icmp.c      1.0.11  06/02/93
   9  *
  10  * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
  11  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  12  *              Mark Evans, <evansmp@uhura.aston.ac.uk>
  13  *
  14  * Fixes:       
  15  *              Alan Cox        :       Generic queue usage.
  16  *
  17  *
  18  *              This program is free software; you can redistribute it and/or
  19  *              modify it under the terms of the GNU General Public License
  20  *              as published by the Free Software Foundation; either version
  21  *              2 of the License, or (at your option) any later version.
  22  */
  23 #include <linux/types.h>
  24 #include <linux/sched.h>
  25 #include <linux/kernel.h>
  26 #include <linux/fcntl.h>
  27 #include <linux/socket.h>
  28 #include <linux/in.h>
  29 #include "inet.h"
  30 #include "dev.h"
  31 #include "ip.h"
  32 #include "route.h"
  33 #include "protocol.h"
  34 #include "icmp.h"
  35 #include "tcp.h"
  36 #include "skbuff.h"
  37 #include "sock.h"
  38 #include <linux/errno.h>
  39 #include <linux/timer.h>
  40 #include <asm/system.h>
  41 #include <asm/segment.h>
  42 
  43 
  44 #define min(a,b)        ((a)<(b)?(a):(b))
  45 
  46 
  47 /* An array of errno for error messages from dest unreach. */
  48 struct icmp_err icmp_err_convert[] = {
  49   { ENETUNREACH,        1 },    /*      ICMP_NET_UNREACH        */
  50   { EHOSTUNREACH,       1 },    /*      ICMP_HOST_UNREACH       */
  51   { ENOPROTOOPT,        1 },    /*      ICMP_PROT_UNREACH       */
  52   { ECONNREFUSED,       1 },    /*      ICMP_PORT_UNREACH       */
  53   { EOPNOTSUPP,         0 },    /*      ICMP_FRAG_NEEDED        */
  54   { EOPNOTSUPP,         0 },    /*      ICMP_SR_FAILED          */
  55   { ENETUNREACH,        1 },    /*      ICMP_NET_UNKNOWN        */
  56   { EHOSTDOWN,          1 },    /*      ICMP_HOST_UNKNOWN       */
  57   { ENONET,             1 },    /*      ICMP_HOST_ISOLATED      */
  58   { ENETUNREACH,        1 },    /*      ICMP_NET_ANO            */
  59   { EHOSTUNREACH,       1 },    /*      ICMP_HOST_ANO           */
  60   { EOPNOTSUPP,         0 },    /*      ICMP_NET_UNR_TOS        */
  61   { EOPNOTSUPP,         0 }     /*      ICMP_HOST_UNR_TOS       */
  62 };
  63 
  64 
  65 /* Display the contents of an ICMP header. */
  66 static void
  67 print_icmp(struct icmphdr *icmph)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69   if (inet_debug != DBG_ICMP) return;
  70 
  71   printk("ICMP: type = %d, code = %d, checksum = %X\n",
  72                         icmph->type, icmph->code, icmph->checksum);
  73   printk("      gateway = %s\n", in_ntoa(icmph->un.gateway));
  74 }
  75 
  76 
  77 /* Send an ICMP message. */
  78 void
  79 icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81   struct sk_buff *skb;
  82   struct iphdr *iph;
  83   int offset;
  84   struct icmphdr *icmph;
  85   int len;
  86 
  87   DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
  88                                                 skb_in, type, code, dev));
  89 
  90   /* Get some memory for the reply. */
  91   len = sizeof(struct sk_buff) + dev->hard_header_len +
  92         sizeof(struct iphdr) + sizeof(struct icmphdr) +
  93         sizeof(struct iphdr) + 8;       /* amount of header to return */
  94            
  95   skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
  96   if (skb == NULL) 
  97         return;
  98 
  99   skb->sk = NULL;
 100   skb->mem_addr = skb;
 101   skb->mem_len = len;
 102   len -= sizeof(struct sk_buff);
 103 
 104   /* Find the IP header. */
 105   iph = (struct iphdr *) (skb_in + 1);
 106   iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
 107 
 108   /* Build Layer 2-3 headers for message back to source. */
 109   offset = ip_build_header(skb, iph->daddr, iph->saddr,
 110                            &dev, IPPROTO_ICMP, NULL, len);
 111   if (offset < 0) {
 112         skb->sk = NULL;
 113         kfree_skb(skb, FREE_READ);
 114         return;
 115   }
 116 
 117   /* Re-adjust length according to actual IP header size. */
 118   skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
 119   icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
 120   icmph->type = type;
 121   icmph->code = code;
 122   icmph->checksum = 0;
 123   icmph->un.gateway = 0;
 124   memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
 125 
 126   icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 127                          sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 128 
 129   DPRINTF((DBG_ICMP, ">>\n"));
 130   print_icmp(icmph);
 131 
 132   /* Send it and free it. */
 133   ip_queue_xmit(NULL, dev, skb, 1);
 134 }
 135 
 136 
 137 /* Handle ICMP_UNREACH and ICMP_QUENCH. */
 138 static void
 139 icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141   struct inet_protocol *ipprot;
 142   struct iphdr *iph;
 143   unsigned char hash;
 144   int err;
 145 
 146   err = (icmph->type << 8) | icmph->code;
 147   iph = (struct iphdr *) (icmph + 1);
 148   switch(icmph->code & 7) {
 149         case ICMP_NET_UNREACH:
 150                 DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
 151                                                         in_ntoa(iph->daddr)));
 152                 break;
 153         case ICMP_HOST_UNREACH:
 154                 DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
 155                                                 in_ntoa(iph->daddr)));
 156                 break;
 157         case ICMP_PROT_UNREACH:
 158                 printk("ICMP: %s:%d: protocol unreachable.\n",
 159                         in_ntoa(iph->daddr), ntohs(iph->protocol));
 160                 break;
 161         case ICMP_PORT_UNREACH:
 162                 DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
 163                         in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
 164                 break;
 165         case ICMP_FRAG_NEEDED:
 166                 printk("ICMP: %s: fragmentation needed and DF set.\n",
 167                                                         in_ntoa(iph->daddr));
 168                 break;
 169         case ICMP_SR_FAILED:
 170                 printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
 171                 break;
 172         default:
 173                 DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
 174                                 (icmph->code & 7), in_ntoa(iph->daddr)));
 175                 break;
 176   }
 177 
 178   /* Get the protocol(s). */
 179   hash = iph->protocol & (MAX_INET_PROTOS -1);
 180 
 181   /* This can change while we are doing it. */
 182   ipprot = (struct inet_protocol *) inet_protos[hash];
 183   while(ipprot != NULL) {
 184         struct inet_protocol *nextip;
 185 
 186         nextip = (struct inet_protocol *) ipprot->next;
 187 
 188         /* Pass it off to everyone who wants it. */
 189         if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
 190                 ipprot->err_handler(err, (unsigned char *)(icmph + 1),
 191                                     iph->daddr, iph->saddr, ipprot);
 192         }
 193 
 194         ipprot = nextip;
 195   }
 196   skb->sk = NULL;
 197   kfree_skb(skb, FREE_READ);
 198 }
 199 
 200 
 201 /* Handle ICMP_REDIRECT. */
 202 static void
 203 icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 204 {
 205   struct iphdr *iph;
 206   unsigned long ip;
 207 
 208   iph = (struct iphdr *) (icmph + 1);
 209   ip = iph->daddr;
 210   switch(icmph->code & 7) {
 211         case ICMP_REDIR_NET:
 212                 rt_add((RTF_DYNAMIC | RTF_MODIFIED),
 213                         ip, icmph->un.gateway, dev);
 214                 break;
 215         case ICMP_REDIR_HOST:
 216                 rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST),
 217                         ip, icmph->un.gateway, dev);
 218                 break;
 219         case ICMP_REDIR_NETTOS:
 220         case ICMP_REDIR_HOSTTOS:
 221                 printk("ICMP: cannot handle TOS redirects yet!\n");
 222                 break;
 223         default:
 224                 DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
 225                                                 (icmph->code & 7)));
 226                 break;
 227   }
 228   skb->sk = NULL;
 229   kfree_skb(skb, FREE_READ);
 230 }
 231 
 232 
 233 /* Handle ICMP_ECHO ("ping") requests. */
 234 static void
 235 icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 236           unsigned long saddr, unsigned long daddr, int len,
 237           struct options *opt)
 238 {
 239   struct icmphdr *icmphr;
 240   struct sk_buff *skb2;
 241   int size, offset;
 242 
 243   size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
 244   skb2 = alloc_skb(size, GFP_ATOMIC);
 245   if (skb2 == NULL) {
 246         skb->sk = NULL;
 247         kfree_skb(skb, FREE_READ);
 248         return;
 249   }
 250   skb2->sk = NULL;
 251   skb2->mem_addr = skb2;
 252   skb2->mem_len = size;
 253   skb2->free = 1;
 254 
 255   /* Build Layer 2-3 headers for message back to source */
 256   offset = ip_build_header(skb2, daddr, saddr, &dev,
 257                                 IPPROTO_ICMP, opt, len);
 258   if (offset < 0) {
 259         printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 260         kfree_skb(skb2,FREE_WRITE);
 261         skb->sk = NULL;
 262         kfree_skb(skb, FREE_READ);
 263         return;
 264   }
 265 
 266   /* Re-adjust length according to actual IP header size. */
 267   skb2->len = offset + len;
 268 
 269   /* Build ICMP_ECHO Response message. */
 270   icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 271   memcpy((char *) icmphr, (char *) icmph, len);
 272   icmphr->type = ICMP_ECHOREPLY;
 273   icmphr->code = 0;
 274   icmphr->checksum = 0;
 275   icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 276 
 277   /* Ship it out - free it when done */
 278   ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 279 
 280   skb->sk = NULL;
 281   kfree_skb(skb, FREE_READ);
 282 }
 283 
 284 
 285 /* Handle the ICMP INFORMATION REQUEST. */
 286 static void
 287 icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 288           unsigned long saddr, unsigned long daddr, int len,
 289           struct options *opt)
 290 {
 291   /* NOT YET */
 292   skb->sk = NULL;
 293   kfree_skb(skb, FREE_READ);
 294 }
 295 
 296 
 297 /* Handle ICMP_ADRESS_MASK requests. */
 298 static void
 299 icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 300           unsigned long saddr, unsigned long daddr, int len,
 301           struct options *opt)
 302 {
 303   struct icmphdr *icmphr;
 304   struct sk_buff *skb2;
 305   int size, offset;
 306 
 307   size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
 308   skb2 = alloc_skb(size, GFP_ATOMIC);
 309   if (skb2 == NULL) {
 310         skb->sk = NULL;
 311         kfree_skb(skb, FREE_READ);
 312         return;
 313   }
 314   skb2->sk = NULL;
 315   skb2->mem_addr = skb2;
 316   skb2->mem_len = size;
 317   skb2->free = 1;
 318 
 319   /* Build Layer 2-3 headers for message back to source */
 320   offset = ip_build_header(skb2, daddr, saddr, &dev,
 321                                 IPPROTO_ICMP, opt, len);
 322   if (offset < 0) {
 323         printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 324         kfree_skb(skb2,FREE_WRITE);
 325         skb->sk = NULL;
 326         kfree_skb(skb, FREE_READ);
 327         return;
 328   }
 329 
 330   /* Re-adjust length according to actual IP header size. */
 331   skb2->len = offset + len;
 332 
 333   /* Build ICMP ADDRESS MASK Response message. */
 334   icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 335   icmphr->type = ICMP_ADDRESSREPLY;
 336   icmphr->code = 0;
 337   icmphr->checksum = 0;
 338   icmphr->un.echo.id = icmph->un.echo.id;
 339   icmphr->un.echo.sequence = icmph->un.echo.sequence;
 340   memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 341 
 342   icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 343 
 344   /* Ship it out - free it when done */
 345   ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 346 
 347   skb->sk = NULL;
 348   kfree_skb(skb, FREE_READ);
 349 }
 350 
 351 
 352 /* Deal with incoming ICMP packets. */
 353 int
 354 icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 355          unsigned long daddr, unsigned short len,
 356          unsigned long saddr, int redo, struct inet_protocol *protocol)
 357 {
 358   struct icmphdr *icmph;
 359   unsigned char *buff;
 360 
 361   /* Drop broadcast packets. */
 362   if (chk_addr(daddr) == IS_BROADCAST) {
 363         DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
 364                                                         in_ntoa(saddr)));
 365         skb1->sk = NULL;
 366         kfree_skb(skb1, FREE_READ);
 367         return(0);
 368   }
 369 
 370   buff = skb1->h.raw;
 371   icmph = (struct icmphdr *) buff;
 372 
 373   /* Validate the packet first */
 374   if (ip_compute_csum((unsigned char *) icmph, len)) {
 375         /* Failed checksum! */
 376         printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 377         skb1->sk = NULL;
 378         kfree_skb(skb1, FREE_READ);
 379         return(0);
 380   }
 381   print_icmp(icmph);
 382 
 383   /* Parse the ICMP message */
 384   switch(icmph->type) {
 385         case ICMP_TIME_EXCEEDED:
 386         case ICMP_DEST_UNREACH:
 387         case ICMP_SOURCE_QUENCH:
 388                 icmp_unreach(icmph, skb1);
 389                 return(0);
 390         case ICMP_REDIRECT:
 391                 icmp_redirect(icmph, skb1, dev);
 392                 return(0);
 393         case ICMP_ECHO: 
 394                 icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 395                 return 0;
 396         case ICMP_ECHOREPLY:
 397                 skb1->sk = NULL;
 398                 kfree_skb(skb1, FREE_READ);
 399                 return(0);
 400         case ICMP_INFO_REQUEST:
 401                 icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 402                 return 0;
 403         case ICMP_INFO_REPLY:
 404                 skb1->sk = NULL;
 405                 kfree_skb(skb1, FREE_READ);
 406                 return(0);
 407         case ICMP_ADDRESS:
 408                 icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 409                 return 0;
 410         case ICMP_ADDRESSREPLY:
 411                 skb1->sk = NULL;
 412                 kfree_skb(skb1, FREE_READ);
 413                 return(0);
 414         default:
 415                 DPRINTF((DBG_ICMP,
 416                         "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
 417                                                 in_ntoa(saddr), icmph->type));
 418                 skb1->sk = NULL;
 419                 kfree_skb(skb1, FREE_READ);
 420                 return(0);
 421   }
 422   /*NOTREACHED*/
 423   skb1->sk = NULL;
 424   kfree_skb(skb1, FREE_READ);
 425   return(-1);
 426 }
 427 
 428 
 429 /* Perform any ICMP-related I/O control requests. */
 430 int
 431 icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433   switch(cmd) {
 434         case DDIOCSDBG:
 435                 return(dbg_ioctl((void *) arg, DBG_ICMP));
 436         default:
 437                 return(-EINVAL);
 438   }
 439   return(0);
 440 }

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