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 mbed-os by
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 13:15:53 by
