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 Bonjour by
icmp.cpp
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 ip_addr_t tmpaddr; 00086 s16_t hlen; 00087 00088 ICMP_STATS_INC(icmp.recv); 00089 snmp_inc_icmpinmsgs(); 00090 00091 00092 iphdr = (struct ip_hdr *)p->payload; 00093 hlen = IPH_HL(iphdr) * 4; 00094 if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { 00095 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); 00096 goto lenerr; 00097 } 00098 00099 type = *((u8_t *)p->payload); 00100 #ifdef LWIP_DEBUG 00101 code = *(((u8_t *)p->payload)+1); 00102 #endif /* LWIP_DEBUG */ 00103 switch (type) { 00104 case ICMP_ER: 00105 /* This is OK, echo reply might have been parsed by a raw PCB 00106 (as obviously, an echo request has been sent, too). */ 00107 break; 00108 case ICMP_ECHO: 00109 #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING 00110 { 00111 int accepted = 1; 00112 #if !LWIP_MULTICAST_PING 00113 /* multicast destination address? */ 00114 if (ip_addr_ismulticast(&iphdr->dest)) { 00115 accepted = 0; 00116 } 00117 #endif /* LWIP_MULTICAST_PING */ 00118 #if !LWIP_BROADCAST_PING 00119 /* broadcast destination address? */ 00120 if (ip_addr_isbroadcast(&iphdr->dest, inp)) { 00121 accepted = 0; 00122 } 00123 #endif /* LWIP_BROADCAST_PING */ 00124 /* broadcast or multicast destination address not acceptd? */ 00125 if (!accepted) { 00126 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); 00127 ICMP_STATS_INC(icmp.err); 00128 pbuf_free(p); 00129 return; 00130 } 00131 } 00132 #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ 00133 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); 00134 if (p->tot_len < sizeof(struct icmp_echo_hdr)) { 00135 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); 00136 goto lenerr; 00137 } 00138 if (inet_chksum_pbuf(p) != 0) { 00139 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); 00140 pbuf_free(p); 00141 ICMP_STATS_INC(icmp.chkerr); 00142 snmp_inc_icmpinerrors(); 00143 return; 00144 } 00145 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00146 if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { 00147 /* p is not big enough to contain link headers 00148 * allocate a new one and copy p into it 00149 */ 00150 struct pbuf *r; 00151 /* switch p->payload to ip header */ 00152 if (pbuf_header(p, hlen)) { 00153 LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); 00154 goto memerr; 00155 } 00156 /* allocate new packet buffer with space for link headers */ 00157 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00158 if (r == NULL) { 00159 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); 00160 goto memerr; 00161 } 00162 LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", 00163 (r->len >= hlen + sizeof(struct icmp_echo_hdr))); 00164 /* copy the whole packet including ip header */ 00165 if (pbuf_copy(r, p) != ERR_OK) { 00166 LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); 00167 goto memerr; 00168 } 00169 iphdr = (struct ip_hdr *)r->payload; 00170 /* switch r->payload back to icmp header */ 00171 if (pbuf_header(r, -hlen)) { 00172 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); 00173 goto memerr; 00174 } 00175 /* free the original p */ 00176 pbuf_free(p); 00177 /* we now have an identical copy of p that has room for link headers */ 00178 p = r; 00179 } else { 00180 /* restore p->payload to point to icmp header */ 00181 if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { 00182 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); 00183 goto memerr; 00184 } 00185 } 00186 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00187 /* At this point, all checks are OK. */ 00188 /* We generate an answer by switching the dest and src ip addresses, 00189 * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ 00190 iecho = (struct icmp_echo_hdr *)p->payload; 00191 ip_addr_copy(tmpaddr, iphdr->src); 00192 ip_addr_copy(iphdr->src, iphdr->dest); 00193 ip_addr_copy(iphdr->dest, tmpaddr); 00194 ICMPH_TYPE_SET(iecho, ICMP_ER); 00195 /* adjust the checksum */ 00196 if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { 00197 iecho->chksum += htons(ICMP_ECHO << 8) + 1; 00198 } else { 00199 iecho->chksum += htons(ICMP_ECHO << 8); 00200 } 00201 00202 /* Set the correct TTL and recalculate the header checksum. */ 00203 IPH_TTL_SET(iphdr, ICMP_TTL); 00204 IPH_CHKSUM_SET(iphdr, 0); 00205 #if CHECKSUM_GEN_IP 00206 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); 00207 #endif /* CHECKSUM_GEN_IP */ 00208 00209 ICMP_STATS_INC(icmp.xmit); 00210 /* increase number of messages attempted to send */ 00211 snmp_inc_icmpoutmsgs(); 00212 /* increase number of echo replies attempted to send */ 00213 snmp_inc_icmpoutechoreps(); 00214 00215 if(pbuf_header(p, hlen)) { 00216 LWIP_ASSERT("Can't move over header in packet", 0); 00217 } else { 00218 err_t ret; 00219 ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL, 00220 ICMP_TTL, 0, IP_PROTO_ICMP, inp); 00221 if (ret != ERR_OK) { 00222 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); 00223 } 00224 } 00225 break; 00226 default: 00227 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 00228 (s16_t)type, (s16_t)code)); 00229 ICMP_STATS_INC(icmp.proterr); 00230 ICMP_STATS_INC(icmp.drop); 00231 } 00232 pbuf_free(p); 00233 return; 00234 lenerr: 00235 pbuf_free(p); 00236 ICMP_STATS_INC(icmp.lenerr); 00237 snmp_inc_icmpinerrors(); 00238 return; 00239 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00240 memerr: 00241 pbuf_free(p); 00242 ICMP_STATS_INC(icmp.err); 00243 snmp_inc_icmpinerrors(); 00244 return; 00245 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00246 } 00247 00248 /** 00249 * Send an icmp 'destination unreachable' packet, called from ip_input() if 00250 * the transport layer protocol is unknown and from udp_input() if the local 00251 * port is not bound. 00252 * 00253 * @param p the input packet for which the 'unreachable' should be sent, 00254 * p->payload pointing to the IP header 00255 * @param t type of the 'unreachable' packet 00256 */ 00257 void 00258 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) 00259 { 00260 icmp_send_response(p, ICMP_DUR, t); 00261 } 00262 00263 #if IP_FORWARD || IP_REASSEMBLY 00264 /** 00265 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. 00266 * 00267 * @param p the input packet for which the 'time exceeded' should be sent, 00268 * p->payload pointing to the IP header 00269 * @param t type of the 'time exceeded' packet 00270 */ 00271 void 00272 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) 00273 { 00274 icmp_send_response(p, ICMP_TE, t); 00275 } 00276 00277 #endif /* IP_FORWARD || IP_REASSEMBLY */ 00278 00279 /** 00280 * Send an icmp packet in response to an incoming packet. 00281 * 00282 * @param p the input packet for which the 'unreachable' should be sent, 00283 * p->payload pointing to the IP header 00284 * @param type Type of the ICMP header 00285 * @param code Code of the ICMP header 00286 */ 00287 static void 00288 icmp_send_response(struct pbuf *p, u8_t type, u8_t code) 00289 { 00290 struct pbuf *q; 00291 struct ip_hdr *iphdr; 00292 /* we can use the echo header here */ 00293 struct icmp_echo_hdr *icmphdr; 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_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); 00331 pbuf_free(q); 00332 } 00333 00334 #endif /* LWIP_ICMP */
Generated on Tue Jul 12 2022 18:11:29 by
