ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

icmp.c
Go to the documentation of this file.
00001 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 /* Some ICMP messages should be passed to the transport protocols. This
00040    is not implemented. */
00041 
00042 #include "lwip/opt.h"
00043 
00044 #if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
00045 
00046 #include "lwip/icmp.h"
00047 #include "lwip/inet_chksum.h"
00048 #include "lwip/ip.h"
00049 #include "lwip/def.h"
00050 #include "lwip/stats.h"
00051 #include "lwip/snmp.h"
00052 
00053 #include <string.h>
00054 
00058 #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00059 #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
00060 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
00061 
00062 /* The amount of data from the original packet to return in a dest-unreachable */
00063 #define ICMP_DEST_UNREACH_DATASIZE 8
00064 
00065 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
00066 
00076 void
00077 icmp_input(struct pbuf *p, struct netif *inp)
00078 {
00079   u8_t type;
00080 #ifdef LWIP_DEBUG
00081   u8_t code;
00082 #endif /* LWIP_DEBUG */
00083   struct icmp_echo_hdr *iecho;
00084   struct ip_hdr *iphdr;
00085   s16_t hlen;
00086 
00087   ICMP_STATS_INC(icmp.recv);
00088   snmp_inc_icmpinmsgs();
00089 
00090 
00091   iphdr = (struct ip_hdr *)p->payload;
00092   hlen = IPH_HL(iphdr) * 4;
00093   if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
00094     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
00095     goto lenerr;
00096   }
00097 
00098   type = *((u8_t *)p->payload);
00099 #ifdef LWIP_DEBUG
00100   code = *(((u8_t *)p->payload)+1);
00101 #endif /* LWIP_DEBUG */
00102   switch (type) {
00103   case ICMP_ER:
00104     /* This is OK, echo reply might have been parsed by a raw PCB
00105        (as obviously, an echo request has been sent, too). */
00106     break; 
00107   case ICMP_ECHO:
00108 #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
00109     {
00110       int accepted = 1;
00111 #if !LWIP_MULTICAST_PING
00112       /* multicast destination address? */
00113       if (ip_addr_ismulticast(&current_iphdr_dest)) {
00114         accepted = 0;
00115       }
00116 #endif /* LWIP_MULTICAST_PING */
00117 #if !LWIP_BROADCAST_PING
00118       /* broadcast destination address? */
00119       if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
00120         accepted = 0;
00121       }
00122 #endif /* LWIP_BROADCAST_PING */
00123       /* broadcast or multicast destination address not acceptd? */
00124       if (!accepted) {
00125         LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
00126         ICMP_STATS_INC(icmp.err);
00127         pbuf_free(p);
00128         return;
00129       }
00130     }
00131 #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
00132     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
00133     if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
00134       LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
00135       goto lenerr;
00136     }
00137     if (inet_chksum_pbuf(p) != 0) {
00138       LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
00139       pbuf_free(p);
00140       ICMP_STATS_INC(icmp.chkerr);
00141       snmp_inc_icmpinerrors();
00142       return;
00143     }
00144 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00145     if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
00146       /* p is not big enough to contain link headers
00147        * allocate a new one and copy p into it
00148        */
00149       struct pbuf *r;
00150       /* switch p->payload to ip header */
00151       if (pbuf_header(p, hlen)) {
00152         LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
00153         goto memerr;
00154       }
00155       /* allocate new packet buffer with space for link headers */
00156       r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
00157       if (r == NULL) {
00158         LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
00159         goto memerr;
00160       }
00161       LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
00162                   (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
00163       /* copy the whole packet including ip header */
00164       if (pbuf_copy(r, p) != ERR_OK) {
00165         LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
00166         goto memerr;
00167       }
00168       iphdr = (struct ip_hdr *)r->payload;
00169       /* switch r->payload back to icmp header */
00170       if (pbuf_header(r, -hlen)) {
00171         LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
00172         goto memerr;
00173       }
00174       /* free the original p */
00175       pbuf_free(p);
00176       /* we now have an identical copy of p that has room for link headers */
00177       p = r;
00178     } else {
00179       /* restore p->payload to point to icmp header */
00180       if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
00181         LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
00182         goto memerr;
00183       }
00184     }
00185 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
00186     /* At this point, all checks are OK. */
00187     /* We generate an answer by switching the dest and src ip addresses,
00188      * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
00189     iecho = (struct icmp_echo_hdr *)p->payload;
00190     ip_addr_copy(iphdr->src, *ip_current_dest_addr());
00191     ip_addr_copy(iphdr->dest, *ip_current_src_addr());
00192     ICMPH_TYPE_SET(iecho, ICMP_ER);
00193     /* adjust the checksum */
00194     if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
00195       iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
00196     } else {
00197       iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
00198     }
00199 
00200     /* Set the correct TTL and recalculate the header checksum. */
00201     IPH_TTL_SET(iphdr, ICMP_TTL);
00202     IPH_CHKSUM_SET(iphdr, 0);
00203 #if CHECKSUM_GEN_IP
00204     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
00205 #endif /* CHECKSUM_GEN_IP */
00206 
00207     ICMP_STATS_INC(icmp.xmit);
00208     /* increase number of messages attempted to send */
00209     snmp_inc_icmpoutmsgs();
00210     /* increase number of echo replies attempted to send */
00211     snmp_inc_icmpoutechoreps();
00212 
00213     if(pbuf_header(p, hlen)) {
00214       LWIP_ASSERT("Can't move over header in packet", 0);
00215     } else {
00216       err_t ret;
00217       /* send an ICMP packet, src addr is the dest addr of the curren packet */
00218       ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
00219                    ICMP_TTL, 0, IP_PROTO_ICMP, inp);
00220       if (ret != ERR_OK) {
00221         LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
00222       }
00223     }
00224     break;
00225   default:
00226     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 
00227                 (s16_t)type, (s16_t)code));
00228     ICMP_STATS_INC(icmp.proterr);
00229     ICMP_STATS_INC(icmp.drop);
00230   }
00231   pbuf_free(p);
00232   return;
00233 lenerr:
00234   pbuf_free(p);
00235   ICMP_STATS_INC(icmp.lenerr);
00236   snmp_inc_icmpinerrors();
00237   return;
00238 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00239 memerr:
00240   pbuf_free(p);
00241   ICMP_STATS_INC(icmp.err);
00242   snmp_inc_icmpinerrors();
00243   return;
00244 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
00245 }
00246 
00256 void
00257 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
00258 {
00259   icmp_send_response(p, ICMP_DUR, t);
00260 }
00261 
00262 #if IP_FORWARD || IP_REASSEMBLY
00263 
00270 void
00271 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
00272 {
00273   icmp_send_response(p, ICMP_TE, t);
00274 }
00275 
00276 #endif /* IP_FORWARD || IP_REASSEMBLY */
00277 
00286 static void
00287 icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
00288 {
00289   struct pbuf *q;
00290   struct ip_hdr *iphdr;
00291   /* we can use the echo header here */
00292   struct icmp_echo_hdr *icmphdr;
00293   ip_addr_t iphdr_src;
00294 
00295   /* ICMP header + IP header + 8 bytes of data */
00296   q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
00297                  PBUF_RAM);
00298   if (q == NULL) {
00299     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
00300     return;
00301   }
00302   LWIP_ASSERT("check that first pbuf can hold icmp message",
00303              (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
00304 
00305   iphdr = (struct ip_hdr *)p->payload;
00306   LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
00307   ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
00308   LWIP_DEBUGF(ICMP_DEBUG, (" to "));
00309   ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
00310   LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
00311 
00312   icmphdr = (struct icmp_echo_hdr *)q->payload;
00313   icmphdr->type = type;
00314   icmphdr->code = code;
00315   icmphdr->id = 0;
00316   icmphdr->seqno = 0;
00317 
00318   /* copy fields from original packet */
00319   SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
00320           IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
00321 
00322   /* calculate checksum */
00323   icmphdr->chksum = 0;
00324   icmphdr->chksum = inet_chksum(icmphdr, q->len);
00325   ICMP_STATS_INC(icmp.xmit);
00326   /* increase number of messages attempted to send */
00327   snmp_inc_icmpoutmsgs();
00328   /* increase number of destination unreachable messages attempted to send */
00329   snmp_inc_icmpouttimeexcds();
00330   ip_addr_copy(iphdr_src, iphdr->src);
00331   ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
00332   pbuf_free(q);
00333 }
00334 
00335 #endif /* LWIP_ICMP */

Generated on Sat May 26 2012 04:34:53 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.