Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
icmp.c
00001 /** 00002 * @file 00003 * ICMP - Internet Control Message Protocol 00004 * 00005 */ 00006 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.h" 00048 #include "lwip/inet_chksum.h" 00049 #include "lwip/ip.h" 00050 #include "lwip/def.h" 00051 #include "lwip/stats.h" 00052 #include "lwip/snmp.h" 00053 00054 #include <string.h> 00055 00056 /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be 00057 * used to modify and send a response packet (and to 1 if this is not the case, 00058 * e.g. when link header is stripped of when receiving) */ 00059 #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00060 #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 00061 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00062 00063 /* The amount of data from the original packet to return in a dest-unreachable */ 00064 #define ICMP_DEST_UNREACH_DATASIZE 8 00065 00066 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); 00067 00068 /** 00069 * Processes ICMP input packets, called from ip_input(). 00070 * 00071 * Currently only processes icmp echo requests and sends 00072 * out the echo response. 00073 * 00074 * @param p the icmp echo request packet, p->payload pointing to the ip header 00075 * @param inp the netif on which this packet was received 00076 */ 00077 void 00078 icmp_input(struct pbuf *p, struct netif *inp) 00079 { 00080 u8_t type; 00081 #ifdef LWIP_DEBUG 00082 u8_t code; 00083 #endif /* LWIP_DEBUG */ 00084 struct icmp_echo_hdr *iecho; 00085 struct ip_hdr *iphdr; 00086 struct ip_addr tmpaddr; 00087 s16_t hlen; 00088 00089 ICMP_STATS_INC(icmp.recv); 00090 snmp_inc_icmpinmsgs(); 00091 00092 00093 iphdr = (struct ip_hdr *)p->payload; 00094 hlen = IPH_HL(iphdr) * 4; 00095 if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { 00096 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); 00097 goto lenerr; 00098 } 00099 00100 type = *((u8_t *)p->payload); 00101 #ifdef LWIP_DEBUG 00102 code = *(((u8_t *)p->payload)+1); 00103 #endif /* LWIP_DEBUG */ 00104 switch (type) { 00105 case ICMP_ECHO: 00106 #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING 00107 { 00108 int accepted = 1; 00109 #if !LWIP_MULTICAST_PING 00110 /* multicast destination address? */ 00111 if (ip_addr_ismulticast(&iphdr->dest)) { 00112 accepted = 0; 00113 } 00114 #endif /* LWIP_MULTICAST_PING */ 00115 #if !LWIP_BROADCAST_PING 00116 /* broadcast destination address? */ 00117 if (ip_addr_isbroadcast(&iphdr->dest, inp)) { 00118 accepted = 0; 00119 } 00120 #endif /* LWIP_BROADCAST_PING */ 00121 /* broadcast or multicast destination address not acceptd? */ 00122 if (!accepted) { 00123 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); 00124 ICMP_STATS_INC(icmp.err); 00125 pbuf_free(p); 00126 return; 00127 } 00128 } 00129 #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ 00130 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); 00131 if (p->tot_len < sizeof(struct icmp_echo_hdr)) { 00132 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); 00133 goto lenerr; 00134 } 00135 if (inet_chksum_pbuf(p) != 0) { 00136 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); 00137 pbuf_free(p); 00138 ICMP_STATS_INC(icmp.chkerr); 00139 snmp_inc_icmpinerrors(); 00140 return; 00141 } 00142 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00143 if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { 00144 /* p is not big enough to contain link headers 00145 * allocate a new one and copy p into it 00146 */ 00147 struct pbuf *r; 00148 /* switch p->payload to ip header */ 00149 if (pbuf_header(p, hlen)) { 00150 LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); 00151 goto memerr; 00152 } 00153 /* allocate new packet buffer with space for link headers */ 00154 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00155 if (r == NULL) { 00156 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); 00157 goto memerr; 00158 } 00159 LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", 00160 (r->len >= hlen + sizeof(struct icmp_echo_hdr))); 00161 /* copy the whole packet including ip header */ 00162 if (pbuf_copy(r, p) != ERR_OK) { 00163 LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); 00164 goto memerr; 00165 } 00166 iphdr = (struct ip_hdr *)r->payload; 00167 /* switch r->payload back to icmp header */ 00168 if (pbuf_header(r, -hlen)) { 00169 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); 00170 goto memerr; 00171 } 00172 /* free the original p */ 00173 pbuf_free(p); 00174 /* we now have an identical copy of p that has room for link headers */ 00175 p = r; 00176 } else { 00177 /* restore p->payload to point to icmp header */ 00178 if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { 00179 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); 00180 goto memerr; 00181 } 00182 } 00183 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00184 /* At this point, all checks are OK. */ 00185 /* We generate an answer by switching the dest and src ip addresses, 00186 * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ 00187 iecho = (struct icmp_echo_hdr *)p->payload; 00188 tmpaddr.addr = iphdr->src.addr; 00189 iphdr->src.addr = iphdr->dest.addr; 00190 iphdr->dest.addr = tmpaddr.addr; 00191 ICMPH_TYPE_SET(iecho, ICMP_ER); 00192 /* adjust the checksum */ 00193 if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { 00194 iecho->chksum += htons(ICMP_ECHO << 8) + 1; 00195 } else { 00196 iecho->chksum += htons(ICMP_ECHO << 8); 00197 } 00198 00199 /* Set the correct TTL and recalculate the header checksum. */ 00200 IPH_TTL_SET(iphdr, ICMP_TTL); 00201 IPH_CHKSUM_SET(iphdr, 0); 00202 #if CHECKSUM_GEN_IP 00203 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); 00204 #endif /* CHECKSUM_GEN_IP */ 00205 00206 ICMP_STATS_INC(icmp.xmit); 00207 /* increase number of messages attempted to send */ 00208 snmp_inc_icmpoutmsgs(); 00209 /* increase number of echo replies attempted to send */ 00210 snmp_inc_icmpoutechoreps(); 00211 00212 if(pbuf_header(p, hlen)) { 00213 LWIP_ASSERT("Can't move over header in packet", 0); 00214 } else { 00215 err_t ret; 00216 ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL, 00217 ICMP_TTL, 0, IP_PROTO_ICMP, inp); 00218 if (ret != ERR_OK) { 00219 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); 00220 } 00221 } 00222 break; 00223 default: 00224 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 00225 (s16_t)type, (s16_t)code)); 00226 ICMP_STATS_INC(icmp.proterr); 00227 ICMP_STATS_INC(icmp.drop); 00228 } 00229 pbuf_free(p); 00230 return; 00231 lenerr: 00232 pbuf_free(p); 00233 ICMP_STATS_INC(icmp.lenerr); 00234 snmp_inc_icmpinerrors(); 00235 return; 00236 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00237 memerr: 00238 pbuf_free(p); 00239 ICMP_STATS_INC(icmp.err); 00240 snmp_inc_icmpinerrors(); 00241 return; 00242 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00243 } 00244 00245 /** 00246 * Send an icmp 'destination unreachable' packet, called from ip_input() if 00247 * the transport layer protocol is unknown and from udp_input() if the local 00248 * port is not bound. 00249 * 00250 * @param p the input packet for which the 'unreachable' should be sent, 00251 * p->payload pointing to the IP header 00252 * @param t type of the 'unreachable' packet 00253 */ 00254 void 00255 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) 00256 { 00257 icmp_send_response(p, ICMP_DUR, t); 00258 } 00259 00260 #if IP_FORWARD || IP_REASSEMBLY 00261 /** 00262 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. 00263 * 00264 * @param p the input packet for which the 'time exceeded' should be sent, 00265 * p->payload pointing to the IP header 00266 * @param t type of the 'time exceeded' packet 00267 */ 00268 void 00269 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) 00270 { 00271 icmp_send_response(p, ICMP_TE, t); 00272 } 00273 00274 #endif /* IP_FORWARD || IP_REASSEMBLY */ 00275 00276 /** 00277 * Send an icmp packet in response to an incoming packet. 00278 * 00279 * @param p the input packet for which the 'unreachable' should be sent, 00280 * p->payload pointing to the IP header 00281 * @param type Type of the ICMP header 00282 * @param code Code of the ICMP header 00283 */ 00284 static void 00285 icmp_send_response(struct pbuf *p, u8_t type, u8_t code) 00286 { 00287 struct pbuf *q; 00288 struct ip_hdr *iphdr; 00289 /* we can use the echo header here */ 00290 struct icmp_echo_hdr *icmphdr; 00291 00292 /* ICMP header + IP header + 8 bytes of data */ 00293 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, 00294 PBUF_RAM); 00295 if (q == NULL) { 00296 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); 00297 return; 00298 } 00299 LWIP_ASSERT("check that first pbuf can hold icmp message", 00300 (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); 00301 00302 iphdr = (struct ip_hdr *)p->payload; 00303 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); 00304 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); 00305 LWIP_DEBUGF(ICMP_DEBUG, (" to ")); 00306 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); 00307 LWIP_DEBUGF(ICMP_DEBUG, ("\n")); 00308 00309 icmphdr = (struct icmp_echo_hdr *)q->payload; 00310 icmphdr->type = type; 00311 icmphdr->code = code; 00312 icmphdr->id = 0; 00313 icmphdr->seqno = 0; 00314 00315 /* copy fields from original packet */ 00316 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, 00317 IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); 00318 00319 /* calculate checksum */ 00320 icmphdr->chksum = 0; 00321 icmphdr->chksum = inet_chksum(icmphdr, q->len); 00322 ICMP_STATS_INC(icmp.xmit); 00323 /* increase number of messages attempted to send */ 00324 snmp_inc_icmpoutmsgs(); 00325 /* increase number of destination unreachable messages attempted to send */ 00326 snmp_inc_icmpouttimeexcds(); 00327 ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); 00328 pbuf_free(q); 00329 } 00330 00331 #endif /* LWIP_ICMP */
Generated on Tue Jul 12 2022 20:39:37 by
1.7.2