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

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