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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
lwip_icmp6.c
00001 /** 00002 * @file 00003 * 00004 * IPv6 version of ICMP, as per RFC 4443. 00005 */ 00006 00007 /* 00008 * Copyright (c) 2010 Inico Technologies Ltd. 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: Ivan Delamer <delamer@inicotech.com> 00036 * 00037 * 00038 * Please coordinate changes and requests with Ivan Delamer 00039 * <delamer@inicotech.com> 00040 */ 00041 00042 #include "lwip/opt.h" 00043 00044 #if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ 00045 00046 #include "lwip/icmp6.h" 00047 #include "lwip/ip6.h" 00048 #include "lwip/ip6_addr.h" 00049 #include "lwip/inet_chksum.h" 00050 #include "lwip/pbuf.h" 00051 #include "lwip/netif.h" 00052 #include "lwip/nd6.h" 00053 #include "lwip/mld6.h" 00054 #include "lwip/ip.h" 00055 #include "lwip/stats.h" 00056 00057 #include <string.h> 00058 00059 #ifndef LWIP_ICMP6_DATASIZE 00060 #define LWIP_ICMP6_DATASIZE 8 00061 #endif 00062 #if LWIP_ICMP6_DATASIZE == 0 00063 #define LWIP_ICMP6_DATASIZE 8 00064 #endif 00065 00066 /* Forward declarations */ 00067 static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); 00068 00069 00070 /** 00071 * Process an input ICMPv6 message. Called by ip6_input. 00072 * 00073 * Will generate a reply for echo requests. Other messages are forwarded 00074 * to nd6_input, or mld6_input. 00075 * 00076 * @param p the mld packet, p->payload pointing to the icmpv6 header 00077 * @param inp the netif on which this packet was received 00078 */ 00079 void 00080 icmp6_input(struct pbuf *p, struct netif *inp) 00081 { 00082 struct icmp6_hdr *icmp6hdr; 00083 struct pbuf * r; 00084 const ip6_addr_t * reply_src; 00085 00086 ICMP6_STATS_INC(icmp6.recv); 00087 00088 /* Check that ICMPv6 header fits in payload */ 00089 if (p->len < sizeof(struct icmp6_hdr)) { 00090 /* drop short packets */ 00091 pbuf_free(p); 00092 ICMP6_STATS_INC(icmp6.lenerr); 00093 ICMP6_STATS_INC(icmp6.drop); 00094 return; 00095 } 00096 00097 icmp6hdr = (struct icmp6_hdr *)p->payload; 00098 00099 #if CHECKSUM_CHECK_ICMP6 00100 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { 00101 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), 00102 ip6_current_dest_addr()) != 0) { 00103 /* Checksum failed */ 00104 pbuf_free(p); 00105 ICMP6_STATS_INC(icmp6.chkerr); 00106 ICMP6_STATS_INC(icmp6.drop); 00107 return; 00108 } 00109 } 00110 #endif /* CHECKSUM_CHECK_ICMP6 */ 00111 00112 switch (icmp6hdr->type) { 00113 case ICMP6_TYPE_NA: /* Neighbor advertisement */ 00114 case ICMP6_TYPE_NS: /* Neighbor solicitation */ 00115 case ICMP6_TYPE_RA: /* Router advertisement */ 00116 case ICMP6_TYPE_RD: /* Redirect */ 00117 case ICMP6_TYPE_PTB: /* Packet too big */ 00118 nd6_input(p, inp); 00119 return; 00120 break; 00121 case ICMP6_TYPE_RS: 00122 #if LWIP_IPV6_FORWARD 00123 /* @todo implement router functionality */ 00124 #endif 00125 break; 00126 #if LWIP_IPV6_MLD 00127 case ICMP6_TYPE_MLQ: 00128 case ICMP6_TYPE_MLR: 00129 case ICMP6_TYPE_MLD: 00130 mld6_input(p, inp); 00131 return; 00132 break; 00133 #endif 00134 case ICMP6_TYPE_EREQ: 00135 #if !LWIP_MULTICAST_PING 00136 /* multicast destination address? */ 00137 if (ip6_addr_ismulticast(ip6_current_dest_addr())) { 00138 /* drop */ 00139 pbuf_free(p); 00140 ICMP6_STATS_INC(icmp6.drop); 00141 return; 00142 } 00143 #endif /* LWIP_MULTICAST_PING */ 00144 00145 /* Allocate reply. */ 00146 r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); 00147 if (r == NULL) { 00148 /* drop */ 00149 pbuf_free(p); 00150 ICMP6_STATS_INC(icmp6.memerr); 00151 return; 00152 } 00153 00154 /* Copy echo request. */ 00155 if (pbuf_copy(r, p) != ERR_OK) { 00156 /* drop */ 00157 pbuf_free(p); 00158 pbuf_free(r); 00159 ICMP6_STATS_INC(icmp6.err); 00160 return; 00161 } 00162 00163 /* Determine reply source IPv6 address. */ 00164 #if LWIP_MULTICAST_PING 00165 if (ip6_addr_ismulticast(ip6_current_dest_addr())) { 00166 reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); 00167 if (reply_src == NULL) { 00168 /* drop */ 00169 pbuf_free(p); 00170 pbuf_free(r); 00171 ICMP6_STATS_INC(icmp6.rterr); 00172 return; 00173 } 00174 } 00175 else 00176 #endif /* LWIP_MULTICAST_PING */ 00177 { 00178 reply_src = ip6_current_dest_addr(); 00179 } 00180 00181 /* Set fields in reply. */ 00182 ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; 00183 ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; 00184 #if CHECKSUM_GEN_ICMP6 00185 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { 00186 ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, 00187 IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); 00188 } 00189 #endif /* CHECKSUM_GEN_ICMP6 */ 00190 00191 /* Send reply. */ 00192 ICMP6_STATS_INC(icmp6.xmit); 00193 ip6_output_if(r, reply_src, ip6_current_src_addr(), 00194 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); 00195 pbuf_free(r); 00196 00197 break; 00198 default: 00199 ICMP6_STATS_INC(icmp6.proterr); 00200 ICMP6_STATS_INC(icmp6.drop); 00201 break; 00202 } 00203 00204 pbuf_free(p); 00205 } 00206 00207 00208 /** 00209 * Send an icmpv6 'destination unreachable' packet. 00210 * 00211 * @param p the input packet for which the 'unreachable' should be sent, 00212 * p->payload pointing to the IPv6 header 00213 * @param c ICMPv6 code for the unreachable type 00214 */ 00215 void 00216 icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) 00217 { 00218 icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); 00219 } 00220 00221 /** 00222 * Send an icmpv6 'packet too big' packet. 00223 * 00224 * @param p the input packet for which the 'packet too big' should be sent, 00225 * p->payload pointing to the IPv6 header 00226 * @param mtu the maximum mtu that we can accept 00227 */ 00228 void 00229 icmp6_packet_too_big(struct pbuf *p, u32_t mtu) 00230 { 00231 icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); 00232 } 00233 00234 /** 00235 * Send an icmpv6 'time exceeded' packet. 00236 * 00237 * @param p the input packet for which the 'unreachable' should be sent, 00238 * p->payload pointing to the IPv6 header 00239 * @param c ICMPv6 code for the time exceeded type 00240 */ 00241 void 00242 icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) 00243 { 00244 icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); 00245 } 00246 00247 /** 00248 * Send an icmpv6 'parameter problem' packet. 00249 * 00250 * @param p the input packet for which the 'param problem' should be sent, 00251 * p->payload pointing to the IP header 00252 * @param c ICMPv6 code for the param problem type 00253 * @param pointer the pointer to the byte where the parameter is found 00254 */ 00255 void 00256 icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) 00257 { 00258 icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); 00259 } 00260 00261 /** 00262 * Send an ICMPv6 packet in response to an incoming packet. 00263 * 00264 * @param p the input packet for which the response should be sent, 00265 * p->payload pointing to the IPv6 header 00266 * @param code Code of the ICMPv6 header 00267 * @param data Additional 32-bit parameter in the ICMPv6 header 00268 * @param type Type of the ICMPv6 header 00269 */ 00270 static void 00271 icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) 00272 { 00273 struct pbuf *q; 00274 struct icmp6_hdr *icmp6hdr; 00275 const ip6_addr_t *reply_src; 00276 ip6_addr_t *reply_dest; 00277 ip6_addr_t reply_src_local, reply_dest_local; 00278 struct ip6_hdr *ip6hdr; 00279 struct netif *netif; 00280 00281 /* ICMPv6 header + IPv6 header + data */ 00282 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, 00283 PBUF_RAM); 00284 if (q == NULL) { 00285 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); 00286 ICMP6_STATS_INC(icmp6.memerr); 00287 return; 00288 } 00289 LWIP_ASSERT("check that first pbuf can hold icmp 6message", 00290 (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); 00291 00292 icmp6hdr = (struct icmp6_hdr *)q->payload; 00293 icmp6hdr->type = type; 00294 icmp6hdr->code = code; 00295 icmp6hdr->data = data; 00296 00297 /* copy fields from original packet */ 00298 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, 00299 IP6_HLEN + LWIP_ICMP6_DATASIZE); 00300 00301 /* Get the destination address and netif for this ICMP message. */ 00302 if ((ip_current_netif() == NULL) || 00303 ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { 00304 /* Special case, as ip6_current_xxx is either NULL, or points 00305 * to a different packet than the one that expired. 00306 * We must use the addresses that are stored in the expired packet. */ 00307 ip6hdr = (struct ip6_hdr *)p->payload; 00308 /* copy from packed address to aligned address */ 00309 ip6_addr_copy(reply_dest_local, ip6hdr->src); 00310 ip6_addr_copy(reply_src_local, ip6hdr->dest); 00311 reply_dest = &reply_dest_local; 00312 reply_src = &reply_src_local; 00313 netif = ip6_route(reply_src, reply_dest); 00314 if (netif == NULL) { 00315 /* drop */ 00316 pbuf_free(q); 00317 ICMP6_STATS_INC(icmp6.rterr); 00318 return; 00319 } 00320 } 00321 else { 00322 netif = ip_current_netif(); 00323 reply_dest = ip6_current_src_addr(); 00324 00325 /* Select an address to use as source. */ 00326 reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); 00327 if (reply_src == NULL) { 00328 /* drop */ 00329 pbuf_free(q); 00330 ICMP6_STATS_INC(icmp6.rterr); 00331 return; 00332 } 00333 } 00334 00335 /* calculate checksum */ 00336 icmp6hdr->chksum = 0; 00337 #if CHECKSUM_GEN_ICMP6 00338 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { 00339 icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, 00340 reply_src, reply_dest); 00341 } 00342 #endif /* CHECKSUM_GEN_ICMP6 */ 00343 00344 ICMP6_STATS_INC(icmp6.xmit); 00345 ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); 00346 pbuf_free(q); 00347 } 00348 00349 #endif /* LWIP_ICMP6 && LWIP_IPV6 */
Generated on Tue Jul 12 2022 11:02:41 by
