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.28    20/12/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  *              Tegge           :       Subnet problems
  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  
  26 #include <linux/types.h>
  27 #include <linux/sched.h>
  28 #include <linux/kernel.h>
  29 #include <linux/fcntl.h>
  30 #include <linux/socket.h>
  31 #include <linux/in.h>
  32 #include "inet.h"
  33 #include "devinet.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 "sockinet.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 #ifdef ICMP_DEBUG
  69 
  70 /* Display the contents of an ICMP header. */
  71 static void
  72 print_icmp(struct icmphdr *icmph)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         if (inet_debug != DBG_ICMP) 
  75                 return;
  76 
  77         printk("ICMP: type = %d, code = %d, checksum = %X\n",
  78                         icmph->type, icmph->code, icmph->checksum);
  79         printk("      gateway = %s\n", in_ntoa(icmph->un.gateway));
  80 }
  81 
  82 #endif
  83 
  84 /* 
  85  *      Send an ICMP message. 
  86  *
  87  *      ICMP is the control message protocol for error reporting in IP.
  88  *      A good document to start with for this stuff is RFC 791.
  89  */
  90 
  91 void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         struct sk_buff *skb;
  94         struct iphdr *iph;
  95         int offset;
  96         struct icmphdr *icmph;
  97         int len;
  98 
  99         DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
 100                                                 skb_in, type, code, dev));
 101 
 102         /* Get some memory for the reply. */
 103         len = sizeof(struct sk_buff) + dev->hard_header_len +
 104                 sizeof(struct iphdr) + sizeof(struct icmphdr) +
 105                 sizeof(struct iphdr) + 8;       /* amount of header to return */
 106            
 107         skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
 108         /* We just forget about failed ICMP messages. ICMP is unreliable anyway and
 109            things will sort out in time */
 110            
 111         if (skb == NULL) 
 112                 return;
 113 
 114         skb->sk = NULL;
 115         len -= sizeof(struct sk_buff);
 116 
 117         /* Find the IP header. */
 118         iph = (struct iphdr *) (skb_in + 1);
 119         iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
 120 
 121         /* Build Layer 2-3 headers for message back to source. */
 122         offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
 123                            &dev, IPPROTO_ICMP, NULL, len, 25, IPTOS_RELIABILITY);
 124         if (offset < 0) 
 125         {
 126                 skb->sk = NULL;
 127                 kfree_skb(skb, FREE_READ);
 128                 return;
 129         }
 130 
 131         /* Re-adjust length according to actual IP header size. */
 132         skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
 133         icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
 134         icmph->type = type;
 135         icmph->code = code;
 136         icmph->checksum = 0;
 137         icmph->un.gateway = 0;
 138         memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
 139 
 140         icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 141                                sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
 142 
 143 #ifdef ICMP_DEBUG
 144         DPRINTF((DBG_ICMP, ">>\n"));
 145         print_icmp(icmph);
 146 #endif
 147         /* Send it and free it. */
 148         ip_queue_xmit(NULL, dev, skb, 1);
 149 }
 150 
 151 
 152 /*
 153  *      Handle ICMP_UNREACH and ICMP_QUENCH. 
 154  */
 155 
 156 static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158         struct inet_protocol *ipprot;
 159         struct iphdr *iph;
 160         unsigned char hash;
 161         int err;
 162         
 163         err = (icmph->type << 8) | icmph->code;
 164         iph = (struct iphdr *) (icmph + 1);
 165         switch(icmph->code & 7) 
 166         {
 167                 case ICMP_NET_UNREACH:
 168                         DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
 169                                                         in_ntoa(iph->daddr)));
 170                         break;
 171                 case ICMP_HOST_UNREACH:
 172                         DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
 173                                                         in_ntoa(iph->daddr)));
 174                         break;
 175                 case ICMP_PROT_UNREACH:
 176                         printk("ICMP: %s:%d: protocol unreachable.\n",
 177                                 in_ntoa(iph->daddr), ntohs(iph->protocol));
 178                         break;
 179                 case ICMP_PORT_UNREACH:
 180                         DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
 181                                 in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
 182                         break;
 183                 case ICMP_FRAG_NEEDED:
 184                         printk("ICMP: %s: fragmentation needed and DF set.\n",
 185                                                                 in_ntoa(iph->daddr));
 186                         break;
 187                 case ICMP_SR_FAILED:
 188                         printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
 189                         break;
 190                 default:
 191                         DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
 192                                         (icmph->code & 7), in_ntoa(iph->daddr)));
 193                         break;
 194         }
 195         
 196         /* Get the protocol(s). */
 197         hash = iph->protocol & (MAX_INET_PROTOS -1);
 198 
 199         /* This can change while we are doing it. */
 200         ipprot = (struct inet_protocol *) inet_protos[hash];
 201         while(ipprot != NULL) 
 202         {
 203                 struct inet_protocol *nextip;
 204 
 205                 nextip = (struct inet_protocol *) ipprot->next;
 206 
 207                 /* Pass it off to everyone who wants it. */
 208                 if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 209                 {
 210                         ipprot->err_handler(err, (unsigned char *)(icmph + 1),
 211                                     iph->daddr, iph->saddr, ipprot);
 212                 }
 213 
 214                 ipprot = nextip;
 215         }
 216         skb->sk = NULL;
 217         kfree_skb(skb, FREE_READ);
 218 }
 219 
 220 
 221 /* 
 222  *      Handle ICMP_REDIRECT.
 223  */
 224 
 225 static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227         struct iphdr *iph;
 228         unsigned long ip;
 229 
 230         iph = (struct iphdr *) (icmph + 1);
 231         ip = iph->daddr;
 232         switch(icmph->code & 7) 
 233         {
 234                 case ICMP_REDIR_NET:
 235                         rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 236                                 ip, 0, icmph->un.gateway, dev);
 237                         break;
 238                 case ICMP_REDIR_HOST:
 239                         rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 240                                 ip, 0, icmph->un.gateway, dev);
 241                         break;
 242                 case ICMP_REDIR_NETTOS:
 243                 case ICMP_REDIR_HOSTTOS:
 244                         printk("ICMP: cannot handle TOS redirects yet!\n");
 245                         break;
 246                 default:
 247                         DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
 248                                                         (icmph->code & 7)));
 249                 break;
 250         }
 251         skb->sk = NULL;
 252         kfree_skb(skb, FREE_READ);
 253 }
 254 
 255 
 256 /* Handle ICMP_ECHO ("ping") requests. */
 257 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 258           unsigned long saddr, unsigned long daddr, int len,
 259           struct options *opt)
 260 {
 261         struct icmphdr *icmphr;
 262         struct sk_buff *skb2;
 263         int size, offset;
 264 
 265         size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
 266         skb2 = alloc_skb(size, GFP_ATOMIC);
 267         if (skb2 == NULL) 
 268         {
 269                 skb->sk = NULL;
 270                 kfree_skb(skb, FREE_READ);
 271                 return;
 272         }
 273         skb2->sk = NULL;
 274         skb2->free = 1;
 275 
 276         /* Build Layer 2-3 headers for message back to source */
 277         offset = ip_build_header(skb2, daddr, saddr, &dev,
 278                                 IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
 279         if (offset < 0) 
 280         {
 281                 printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
 282                 kfree_skb(skb2,FREE_WRITE);
 283                 skb->sk = NULL;
 284                 kfree_skb(skb, FREE_READ);
 285                 return;
 286         }
 287 
 288         /* Re-adjust length according to actual IP header size. */
 289         skb2->len = offset + len;
 290 
 291         /* Build ICMP_ECHO Response message. */
 292         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 293         memcpy((char *) icmphr, (char *) icmph, len);
 294         icmphr->type = ICMP_ECHOREPLY;
 295         icmphr->code = 0;
 296         icmphr->checksum = 0;
 297         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 298         
 299         /* Ship it out - free it when done */
 300         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 301 
 302         skb->sk = NULL;
 303         kfree_skb(skb, FREE_READ);
 304 }
 305 
 306 
 307 /* 
 308  *      Handle the ICMP INFORMATION REQUEST. 
 309  */
 310 
 311 static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 312           unsigned long saddr, unsigned long daddr, int len,
 313           struct options *opt)
 314 {
 315         /* NOT YET */
 316         skb->sk = NULL;
 317         kfree_skb(skb, FREE_READ);
 318 }
 319 
 320 
 321 /* 
 322  *      Handle ICMP_ADRESS_MASK requests. 
 323  */
 324 
 325 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 326           unsigned long saddr, unsigned long daddr, int len,
 327           struct options *opt)
 328 {
 329         struct icmphdr *icmphr;
 330         struct sk_buff *skb2;
 331         int size, offset;
 332 
 333         size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
 334         skb2 = alloc_skb(size, GFP_ATOMIC);
 335         if (skb2 == NULL) 
 336         {
 337                 skb->sk = NULL;
 338                 kfree_skb(skb, FREE_READ);
 339                 return;
 340         }
 341         skb2->sk = NULL;
 342         skb2->free = 1;
 343 
 344         /* Build Layer 2-3 headers for message back to source */
 345         offset = ip_build_header(skb2, daddr, saddr, &dev,
 346                                 IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
 347         if (offset < 0) 
 348         {
 349                 printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
 350                 kfree_skb(skb2,FREE_WRITE);
 351                 skb->sk = NULL;
 352                 kfree_skb(skb, FREE_READ);
 353                 return;
 354         }
 355 
 356         /* Re-adjust length according to actual IP header size. */
 357         skb2->len = offset + len;
 358         
 359         /* Build ICMP ADDRESS MASK Response message. */
 360         icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
 361         icmphr->type = ICMP_ADDRESSREPLY;
 362         icmphr->code = 0;
 363         icmphr->checksum = 0;
 364         icmphr->un.echo.id = icmph->un.echo.id;
 365         icmphr->un.echo.sequence = icmph->un.echo.sequence;
 366         memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
 367         
 368         icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
 369 
 370         /* Ship it out - free it when done */
 371         ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
 372 
 373         skb->sk = NULL;
 374         kfree_skb(skb, FREE_READ);
 375 }
 376 
 377 
 378 /*
 379  *      Deal with incoming ICMP packets. 
 380  */
 381 
 382 int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 383          unsigned long daddr, unsigned short len,
 384          unsigned long saddr, int redo, struct inet_protocol *protocol)
 385 {
 386         struct icmphdr *icmph;
 387         unsigned char *buff;
 388 
 389         /* Drop broadcast packets. */
 390         if (chk_addr(daddr) == IS_BROADCAST) 
 391         {
 392                 DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
 393                                                         in_ntoa(saddr)));
 394                 skb1->sk = NULL;
 395                 kfree_skb(skb1, FREE_READ);
 396                 return(0);
 397         }
 398 
 399         buff = skb1->h.raw;
 400         icmph = (struct icmphdr *) buff;
 401 
 402         /* Validate the packet first */
 403         if (ip_compute_csum((unsigned char *) icmph, len)) 
 404         {
 405                 /* Failed checksum! */
 406                 printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
 407                 skb1->sk = NULL;
 408                 kfree_skb(skb1, FREE_READ);
 409                 return(0);
 410         }
 411 #ifdef ICMP_DEBUG
 412         print_icmp(icmph);
 413 #endif
 414         /* Parse the ICMP message */
 415         switch(icmph->type) 
 416         {
 417                 case ICMP_TIME_EXCEEDED:
 418                 case ICMP_DEST_UNREACH:
 419                 case ICMP_SOURCE_QUENCH:
 420                         icmp_unreach(icmph, skb1);
 421                         return(0);
 422                 case ICMP_REDIRECT:
 423                         icmp_redirect(icmph, skb1, dev);
 424                         return(0);
 425                 case ICMP_ECHO: 
 426                         icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
 427                         return 0;
 428                 case ICMP_ECHOREPLY:
 429                         skb1->sk = NULL;
 430                         kfree_skb(skb1, FREE_READ);
 431                         return(0);
 432                 case ICMP_INFO_REQUEST:
 433                         icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
 434                         return 0;
 435                 case ICMP_INFO_REPLY:
 436                         skb1->sk = NULL;
 437                         kfree_skb(skb1, FREE_READ);
 438                         return(0);
 439                 case ICMP_ADDRESS:
 440                         icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
 441                         return 0;
 442                 case ICMP_ADDRESSREPLY:
 443                         skb1->sk = NULL;
 444                         kfree_skb(skb1, FREE_READ);
 445                         return(0);
 446                 default:
 447                         DPRINTF((DBG_ICMP,
 448                                 "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
 449                                                         in_ntoa(saddr), icmph->type));
 450                         skb1->sk = NULL;
 451                         kfree_skb(skb1, FREE_READ);
 452                         return(0);
 453         }
 454         /*NOTREACHED*/
 455         skb1->sk = NULL;
 456         kfree_skb(skb1, FREE_READ);
 457         return(-1);
 458 }
 459 
 460 
 461 /* 
 462  *      Perform any ICMP-related I/O control requests. 
 463  *
 464  *      In the case of ICMP all the user can do is play with the debygging
 465  */
 466  
 467 int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 468 {
 469         switch(cmd) 
 470         {
 471                 case DDIOCSDBG:
 472                         return(dbg_ioctl((void *) arg, DBG_ICMP));
 473                 default:
 474                         return(-EINVAL);
 475         }
 476         return(0);
 477 }

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