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