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 F7_Ethernet 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 #if CHECKSUM_GEN_ICMP 00194 /* adjust the checksum */ 00195 if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { 00196 iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; 00197 } else { 00198 iecho->chksum += PP_HTONS(ICMP_ECHO << 8); 00199 } 00200 #else /* CHECKSUM_GEN_ICMP */ 00201 iecho->chksum = 0; 00202 #endif /* CHECKSUM_GEN_ICMP */ 00203 00204 /* Set the correct TTL and recalculate the header checksum. */ 00205 IPH_TTL_SET(iphdr, ICMP_TTL); 00206 IPH_CHKSUM_SET(iphdr, 0); 00207 #if CHECKSUM_GEN_IP 00208 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); 00209 #endif /* CHECKSUM_GEN_IP */ 00210 00211 ICMP_STATS_INC(icmp.xmit); 00212 /* increase number of messages attempted to send */ 00213 snmp_inc_icmpoutmsgs(); 00214 /* increase number of echo replies attempted to send */ 00215 snmp_inc_icmpoutechoreps(); 00216 00217 if(pbuf_header(p, hlen)) { 00218 LWIP_ASSERT("Can't move over header in packet", 0); 00219 } else { 00220 err_t ret; 00221 /* send an ICMP packet, src addr is the dest addr of the curren packet */ 00222 ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, 00223 ICMP_TTL, 0, IP_PROTO_ICMP, inp); 00224 if (ret != ERR_OK) { 00225 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); 00226 } 00227 } 00228 break; 00229 default: 00230 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 00231 (s16_t)type, (s16_t)code)); 00232 ICMP_STATS_INC(icmp.proterr); 00233 ICMP_STATS_INC(icmp.drop); 00234 } 00235 pbuf_free(p); 00236 return; 00237 lenerr: 00238 pbuf_free(p); 00239 ICMP_STATS_INC(icmp.lenerr); 00240 snmp_inc_icmpinerrors(); 00241 return; 00242 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 00243 memerr: 00244 pbuf_free(p); 00245 ICMP_STATS_INC(icmp.err); 00246 snmp_inc_icmpinerrors(); 00247 return; 00248 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ 00249 } 00250 00251 /** 00252 * Send an icmp 'destination unreachable' packet, called from ip_input() if 00253 * the transport layer protocol is unknown and from udp_input() if the local 00254 * port is not bound. 00255 * 00256 * @param p the input packet for which the 'unreachable' should be sent, 00257 * p->payload pointing to the IP header 00258 * @param t type of the 'unreachable' packet 00259 */ 00260 void 00261 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) 00262 { 00263 icmp_send_response(p, ICMP_DUR, t); 00264 } 00265 00266 #if IP_FORWARD || IP_REASSEMBLY 00267 /** 00268 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. 00269 * 00270 * @param p the input packet for which the 'time exceeded' should be sent, 00271 * p->payload pointing to the IP header 00272 * @param t type of the 'time exceeded' packet 00273 */ 00274 void 00275 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) 00276 { 00277 icmp_send_response(p, ICMP_TE, t); 00278 } 00279 00280 #endif /* IP_FORWARD || IP_REASSEMBLY */ 00281 00282 /** 00283 * Send an icmp packet in response to an incoming packet. 00284 * 00285 * @param p the input packet for which the 'unreachable' should be sent, 00286 * p->payload pointing to the IP header 00287 * @param type Type of the ICMP header 00288 * @param code Code of the ICMP header 00289 */ 00290 static void 00291 icmp_send_response(struct pbuf *p, u8_t type, u8_t code) 00292 { 00293 struct pbuf *q; 00294 struct ip_hdr *iphdr; 00295 /* we can use the echo header here */ 00296 struct icmp_echo_hdr *icmphdr; 00297 ip_addr_t iphdr_src; 00298 00299 /* ICMP header + IP header + 8 bytes of data */ 00300 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_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_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); 00308 00309 iphdr = (struct ip_hdr *)p->payload; 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 icmphdr = (struct icmp_echo_hdr *)q->payload; 00317 icmphdr->type = type; 00318 icmphdr->code = code; 00319 icmphdr->id = 0; 00320 icmphdr->seqno = 0; 00321 00322 /* copy fields from original packet */ 00323 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, 00324 IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); 00325 00326 /* calculate checksum */ 00327 icmphdr->chksum = 0; 00328 icmphdr->chksum = inet_chksum(icmphdr, q->len); 00329 ICMP_STATS_INC(icmp.xmit); 00330 /* increase number of messages attempted to send */ 00331 snmp_inc_icmpoutmsgs(); 00332 /* increase number of destination unreachable messages attempted to send */ 00333 snmp_inc_icmpouttimeexcds(); 00334 ip_addr_copy(iphdr_src, iphdr->src); 00335 ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP); 00336 pbuf_free(q); 00337 } 00338 00339 #endif /* LWIP_ICMP */
Generated on Wed Jul 13 2022 02:45:40 by
