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