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

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