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.
Fork of OmniWheels by
lwip_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_IPV4 && 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 00052 #include <string.h> 00053 00054 #ifdef LWIP_HOOK_FILENAME 00055 #include LWIP_HOOK_FILENAME 00056 #endif 00057 00058 /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be 00059 * used to modify and send a response packet (and to 1 if this is not the case, 00060 * e.g. when link header is stripped of when receiving) */ 00061 #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00062 #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 00063 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00064 00065 /* The amount of data from the original packet to return in a dest-unreachable */ 00066 #define ICMP_DEST_UNREACH_DATASIZE 8 00067 00068 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); 00069 00070 /** 00071 * Processes ICMP input packets, called from ip_input(). 00072 * 00073 * Currently only processes icmp echo requests and sends 00074 * out the echo response. 00075 * 00076 * @param p the icmp echo request packet, p->payload pointing to the icmp header 00077 * @param inp the netif on which this packet was received 00078 */ 00079 void 00080 icmp_input(struct pbuf *p, struct netif *inp) 00081 { 00082 u8_t type; 00083 #ifdef LWIP_DEBUG 00084 u8_t code; 00085 #endif /* LWIP_DEBUG */ 00086 struct icmp_echo_hdr *iecho; 00087 const struct ip_hdr *iphdr_in; 00088 u16_t hlen; 00089 const ip4_addr_t* src; 00090 00091 ICMP_STATS_INC(icmp.recv); 00092 MIB2_STATS_INC(mib2.icmpinmsgs); 00093 00094 iphdr_in = ip4_current_header(); 00095 hlen = IPH_HL(iphdr_in) * 4; 00096 if (hlen < IP_HLEN) { 00097 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen)); 00098 goto lenerr; 00099 } 00100 if (p->len < sizeof(u16_t)*2) { 00101 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); 00102 goto lenerr; 00103 } 00104 00105 type = *((u8_t *)p->payload); 00106 #ifdef LWIP_DEBUG 00107 code = *(((u8_t *)p->payload)+1); 00108 #endif /* LWIP_DEBUG */ 00109 switch (type) { 00110 case ICMP_ER: 00111 /* This is OK, echo reply might have been parsed by a raw PCB 00112 (as obviously, an echo request has been sent, too). */ 00113 MIB2_STATS_INC(mib2.icmpinechoreps); 00114 break; 00115 case ICMP_ECHO: 00116 MIB2_STATS_INC(mib2.icmpinechos); 00117 src = ip4_current_dest_addr(); 00118 /* multicast destination address? */ 00119 if (ip4_addr_ismulticast(ip4_current_dest_addr())) { 00120 #if LWIP_MULTICAST_PING 00121 /* For multicast, use address of receiving interface as source address */ 00122 src = netif_ip4_addr(inp); 00123 #else /* LWIP_MULTICAST_PING */ 00124 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n")); 00125 goto icmperr; 00126 #endif /* LWIP_MULTICAST_PING */ 00127 } 00128 /* broadcast destination address? */ 00129 if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) { 00130 #if LWIP_BROADCAST_PING 00131 /* For broadcast, use address of receiving interface as source address */ 00132 src = netif_ip4_addr(inp); 00133 #else /* LWIP_BROADCAST_PING */ 00134 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n")); 00135 goto icmperr; 00136 #endif /* LWIP_BROADCAST_PING */ 00137 } 00138 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); 00139 if (p->tot_len < sizeof(struct icmp_echo_hdr)) { 00140 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); 00141 goto lenerr; 00142 } 00143 #if CHECKSUM_CHECK_ICMP 00144 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) { 00145 if (inet_chksum_pbuf(p) != 0) { 00146 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); 00147 pbuf_free(p); 00148 ICMP_STATS_INC(icmp.chkerr); 00149 MIB2_STATS_INC(mib2.icmpinerrors); 00150 return; 00151 } 00152 } 00153 #endif 00154 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00155 if (pbuf_header(p, (s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) { 00156 /* p is not big enough to contain link headers 00157 * allocate a new one and copy p into it 00158 */ 00159 struct pbuf *r; 00160 /* allocate new packet buffer with space for link headers */ 00161 r = pbuf_alloc(PBUF_LINK, p->tot_len + hlen, PBUF_RAM); 00162 if (r == NULL) { 00163 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); 00164 goto icmperr; 00165 } 00166 if (r->len < hlen + sizeof(struct icmp_echo_hdr)) { 00167 LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header")); 00168 pbuf_free(r); 00169 goto icmperr; 00170 } 00171 /* copy the ip header */ 00172 MEMCPY(r->payload, iphdr_in, hlen); 00173 /* switch r->payload back to icmp header (cannot fail) */ 00174 if (pbuf_header(r, (s16_t)-hlen)) { 00175 LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0); 00176 pbuf_free(r); 00177 goto icmperr; 00178 } 00179 /* copy the rest of the packet without ip header */ 00180 if (pbuf_copy(r, p) != ERR_OK) { 00181 LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed")); 00182 pbuf_free(r); 00183 goto icmperr; 00184 } 00185 /* free the original p */ 00186 pbuf_free(p); 00187 /* we now have an identical copy of p that has room for link headers */ 00188 p = r; 00189 } else { 00190 /* restore p->payload to point to icmp header (cannot fail) */ 00191 if (pbuf_header(p, -(s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) { 00192 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); 00193 goto icmperr; 00194 } 00195 } 00196 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00197 /* At this point, all checks are OK. */ 00198 /* We generate an answer by switching the dest and src ip addresses, 00199 * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ 00200 iecho = (struct icmp_echo_hdr *)p->payload; 00201 if (pbuf_header(p, (s16_t)hlen)) { 00202 LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet")); 00203 } else { 00204 err_t ret; 00205 struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; 00206 ip4_addr_copy(iphdr->src, *src); 00207 ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); 00208 ICMPH_TYPE_SET(iecho, ICMP_ER); 00209 #if CHECKSUM_GEN_ICMP 00210 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { 00211 /* adjust the checksum */ 00212 if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { 00213 iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; 00214 } else { 00215 iecho->chksum += PP_HTONS(ICMP_ECHO << 8); 00216 } 00217 } 00218 #if LWIP_CHECKSUM_CTRL_PER_NETIF 00219 else { 00220 iecho->chksum = 0; 00221 } 00222 #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ 00223 #else /* CHECKSUM_GEN_ICMP */ 00224 iecho->chksum = 0; 00225 #endif /* CHECKSUM_GEN_ICMP */ 00226 00227 /* Set the correct TTL and recalculate the header checksum. */ 00228 IPH_TTL_SET(iphdr, ICMP_TTL); 00229 IPH_CHKSUM_SET(iphdr, 0); 00230 #if CHECKSUM_GEN_IP 00231 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { 00232 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); 00233 } 00234 #endif /* CHECKSUM_GEN_IP */ 00235 00236 ICMP_STATS_INC(icmp.xmit); 00237 /* increase number of messages attempted to send */ 00238 MIB2_STATS_INC(mib2.icmpoutmsgs); 00239 /* increase number of echo replies attempted to send */ 00240 MIB2_STATS_INC(mib2.icmpoutechoreps); 00241 00242 /* send an ICMP packet */ 00243 ret = ip4_output_if(p, src, LWIP_IP_HDRINCL, 00244 ICMP_TTL, 0, IP_PROTO_ICMP, inp); 00245 if (ret != ERR_OK) { 00246 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret))); 00247 } 00248 } 00249 break; 00250 default: 00251 if (type == ICMP_DUR) { 00252 MIB2_STATS_INC(mib2.icmpindestunreachs); 00253 } else if (type == ICMP_TE) { 00254 MIB2_STATS_INC(mib2.icmpintimeexcds); 00255 } else if (type == ICMP_PP) { 00256 MIB2_STATS_INC(mib2.icmpinparmprobs); 00257 } else if (type == ICMP_SQ) { 00258 MIB2_STATS_INC(mib2.icmpinsrcquenchs); 00259 } else if (type == ICMP_RD) { 00260 MIB2_STATS_INC(mib2.icmpinredirects); 00261 } else if (type == ICMP_TS) { 00262 MIB2_STATS_INC(mib2.icmpintimestamps); 00263 } else if (type == ICMP_TSR) { 00264 MIB2_STATS_INC(mib2.icmpintimestampreps); 00265 } else if (type == ICMP_AM) { 00266 MIB2_STATS_INC(mib2.icmpinaddrmasks); 00267 } else if (type == ICMP_AMR) { 00268 MIB2_STATS_INC(mib2.icmpinaddrmaskreps); 00269 } 00270 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 00271 (s16_t)type, (s16_t)code)); 00272 ICMP_STATS_INC(icmp.proterr); 00273 ICMP_STATS_INC(icmp.drop); 00274 } 00275 pbuf_free(p); 00276 return; 00277 lenerr: 00278 pbuf_free(p); 00279 ICMP_STATS_INC(icmp.lenerr); 00280 MIB2_STATS_INC(mib2.icmpinerrors); 00281 return; 00282 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING 00283 icmperr: 00284 pbuf_free(p); 00285 ICMP_STATS_INC(icmp.err); 00286 MIB2_STATS_INC(mib2.icmpinerrors); 00287 return; 00288 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ 00289 } 00290 00291 /** 00292 * Send an icmp 'destination unreachable' packet, called from ip_input() if 00293 * the transport layer protocol is unknown and from udp_input() if the local 00294 * port is not bound. 00295 * 00296 * @param p the input packet for which the 'unreachable' should be sent, 00297 * p->payload pointing to the IP header 00298 * @param t type of the 'unreachable' packet 00299 */ 00300 void 00301 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) 00302 { 00303 MIB2_STATS_INC(mib2.icmpoutdestunreachs); 00304 icmp_send_response(p, ICMP_DUR, t); 00305 } 00306 00307 #if IP_FORWARD || IP_REASSEMBLY 00308 /** 00309 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. 00310 * 00311 * @param p the input packet for which the 'time exceeded' should be sent, 00312 * p->payload pointing to the IP header 00313 * @param t type of the 'time exceeded' packet 00314 */ 00315 void 00316 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) 00317 { 00318 MIB2_STATS_INC(mib2.icmpouttimeexcds); 00319 icmp_send_response(p, ICMP_TE, t); 00320 } 00321 00322 #endif /* IP_FORWARD || IP_REASSEMBLY */ 00323 00324 /** 00325 * Send an icmp packet in response to an incoming packet. 00326 * 00327 * @param p the input packet for which the 'unreachable' should be sent, 00328 * p->payload pointing to the IP header 00329 * @param type Type of the ICMP header 00330 * @param code Code of the ICMP header 00331 */ 00332 static void 00333 icmp_send_response(struct pbuf *p, u8_t type, u8_t code) 00334 { 00335 struct pbuf *q; 00336 struct ip_hdr *iphdr; 00337 /* we can use the echo header here */ 00338 struct icmp_echo_hdr *icmphdr; 00339 ip4_addr_t iphdr_src; 00340 struct netif *netif; 00341 00342 /* increase number of messages attempted to send */ 00343 MIB2_STATS_INC(mib2.icmpoutmsgs); 00344 00345 /* ICMP header + IP header + 8 bytes of data */ 00346 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, 00347 PBUF_RAM); 00348 if (q == NULL) { 00349 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); 00350 MIB2_STATS_INC(mib2.icmpouterrors); 00351 return; 00352 } 00353 LWIP_ASSERT("check that first pbuf can hold icmp message", 00354 (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); 00355 00356 iphdr = (struct ip_hdr *)p->payload; 00357 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); 00358 ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src); 00359 LWIP_DEBUGF(ICMP_DEBUG, (" to ")); 00360 ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest); 00361 LWIP_DEBUGF(ICMP_DEBUG, ("\n")); 00362 00363 icmphdr = (struct icmp_echo_hdr *)q->payload; 00364 icmphdr->type = type; 00365 icmphdr->code = code; 00366 icmphdr->id = 0; 00367 icmphdr->seqno = 0; 00368 00369 /* copy fields from original packet */ 00370 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, 00371 IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); 00372 00373 ip4_addr_copy(iphdr_src, iphdr->src); 00374 #ifdef LWIP_HOOK_IP4_ROUTE_SRC 00375 { 00376 ip4_addr_t iphdr_dst; 00377 ip4_addr_copy(iphdr_dst, iphdr->dest); 00378 netif = ip4_route_src(&iphdr_src, &iphdr_dst); 00379 } 00380 #else 00381 netif = ip4_route(&iphdr_src); 00382 #endif 00383 if (netif != NULL) { 00384 /* calculate checksum */ 00385 icmphdr->chksum = 0; 00386 #if CHECKSUM_GEN_ICMP 00387 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { 00388 icmphdr->chksum = inet_chksum(icmphdr, q->len); 00389 } 00390 #endif 00391 ICMP_STATS_INC(icmp.xmit); 00392 ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); 00393 } 00394 pbuf_free(q); 00395 } 00396 00397 #endif /* LWIP_IPV4 && LWIP_ICMP */
Generated on Fri Jul 22 2022 04:53:52 by
1.7.2
