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 lwip by
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_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 00055 /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be 00056 * used to modify and send a response packet (and to 1 if this is not the case, 00057 * e.g. when link header is stripped of when receiving) */ 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 00067 /** 00068 * Processes ICMP input packets, called from ip_input(). 00069 * 00070 * Currently only processes icmp echo requests and sends 00071 * out the echo response. 00072 * 00073 * @param p the icmp echo request packet, p->payload pointing to the ip header 00074 * @param inp the netif on which this packet was received 00075 */ 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(¤t_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(¤t_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 00247 /** 00248 * Send an icmp 'destination unreachable' packet, called from ip_input() if 00249 * the transport layer protocol is unknown and from udp_input() if the local 00250 * port is not bound. 00251 * 00252 * @param p the input packet for which the 'unreachable' should be sent, 00253 * p->payload pointing to the IP header 00254 * @param t type of the 'unreachable' packet 00255 */ 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 /** 00264 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. 00265 * 00266 * @param p the input packet for which the 'time exceeded' should be sent, 00267 * p->payload pointing to the IP header 00268 * @param t type of the 'time exceeded' packet 00269 */ 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 00278 /** 00279 * Send an icmp packet in response to an incoming packet. 00280 * 00281 * @param p the input packet for which the 'unreachable' should be sent, 00282 * p->payload pointing to the IP header 00283 * @param type Type of the ICMP header 00284 * @param code Code of the ICMP header 00285 */ 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 Tue Jul 12 2022 11:29:36 by
