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_nd6.c
00001 /** 00002 * @file 00003 * 00004 * Neighbor discovery and stateless address autoconfiguration for IPv6. 00005 * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 00006 * (Address autoconfiguration). 00007 */ 00008 00009 /* 00010 * Copyright (c) 2010 Inico Technologies Ltd. 00011 * All rights reserved. 00012 * 00013 * Redistribution and use in source and binary forms, with or without modification, 00014 * are permitted provided that the following conditions are met: 00015 * 00016 * 1. Redistributions of source code must retain the above copyright notice, 00017 * this list of conditions and the following disclaimer. 00018 * 2. Redistributions in binary form must reproduce the above copyright notice, 00019 * this list of conditions and the following disclaimer in the documentation 00020 * and/or other materials provided with the distribution. 00021 * 3. The name of the author may not be used to endorse or promote products 00022 * derived from this software without specific prior written permission. 00023 * 00024 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00025 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00026 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00027 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00028 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00029 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00030 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00031 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00032 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00033 * OF SUCH DAMAGE. 00034 * 00035 * This file is part of the lwIP TCP/IP stack. 00036 * 00037 * Author: Ivan Delamer <delamer@inicotech.com> 00038 * 00039 * 00040 * Please coordinate changes and requests with Ivan Delamer 00041 * <delamer@inicotech.com> 00042 */ 00043 00044 #include "lwip/opt.h" 00045 00046 #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ 00047 00048 #include "lwip/nd6.h" 00049 #include "lwip/pbuf.h" 00050 #include "lwip/mem.h" 00051 #include "lwip/memp.h" 00052 #include "lwip/ip6.h" 00053 #include "lwip/ip6_addr.h" 00054 #include "lwip/inet_chksum.h" 00055 #include "lwip/netif.h" 00056 #include "lwip/icmp6.h" 00057 #include "lwip/mld6.h" 00058 #include "lwip/ip.h" 00059 #include "lwip/stats.h" 00060 00061 #include <string.h> 00062 00063 00064 /* Router tables. */ 00065 struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; 00066 struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; 00067 struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; 00068 struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; 00069 00070 /* Default values, can be updated by a RA message. */ 00071 u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; 00072 u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ 00073 00074 /* Index for cache entries. */ 00075 static u8_t nd6_cached_neighbor_index; 00076 static u8_t nd6_cached_destination_index; 00077 00078 /* Multicast address holder. */ 00079 static ip6_addr_t multicast_address; 00080 00081 /* Static buffer to parse RA packet options (size of a prefix option, biggest option) */ 00082 static u8_t nd6_ra_buffer[sizeof(struct prefix_option)]; 00083 00084 /* Forward declarations. */ 00085 static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t * ip6addr); 00086 static s8_t nd6_new_neighbor_cache_entry(void); 00087 static void nd6_free_neighbor_cache_entry(s8_t i); 00088 static s8_t nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr); 00089 static s8_t nd6_new_destination_cache_entry(void); 00090 static s8_t nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif); 00091 static s8_t nd6_get_router(const ip6_addr_t * router_addr, struct netif * netif); 00092 static s8_t nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif); 00093 static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); 00094 static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); 00095 00096 #define ND6_SEND_FLAG_MULTICAST_DEST 0x01 00097 #define ND6_SEND_FLAG_ALLNODES_DEST 0x02 00098 static void nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags); 00099 static void nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags); 00100 #if LWIP_IPV6_SEND_ROUTER_SOLICIT 00101 static err_t nd6_send_rs(struct netif * netif); 00102 #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ 00103 00104 #if LWIP_ND6_QUEUEING 00105 static void nd6_free_q(struct nd6_q_entry *q); 00106 #else /* LWIP_ND6_QUEUEING */ 00107 #define nd6_free_q(q) pbuf_free(q) 00108 #endif /* LWIP_ND6_QUEUEING */ 00109 static void nd6_send_q(s8_t i); 00110 00111 00112 /** 00113 * Process an incoming neighbor discovery message 00114 * 00115 * @param p the nd packet, p->payload pointing to the icmpv6 header 00116 * @param inp the netif on which this packet was received 00117 */ 00118 void 00119 nd6_input(struct pbuf *p, struct netif *inp) 00120 { 00121 u8_t msg_type; 00122 s8_t i; 00123 00124 ND6_STATS_INC(nd6.recv); 00125 00126 msg_type = *((u8_t *)p->payload); 00127 switch (msg_type) { 00128 case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ 00129 { 00130 struct na_header * na_hdr; 00131 struct lladdr_option * lladdr_opt; 00132 00133 /* Check that na header fits in packet. */ 00134 if (p->len < (sizeof(struct na_header))) { 00135 /* @todo debug message */ 00136 pbuf_free(p); 00137 ND6_STATS_INC(nd6.lenerr); 00138 ND6_STATS_INC(nd6.drop); 00139 return; 00140 } 00141 00142 na_hdr = (struct na_header *)p->payload; 00143 00144 /* Unsolicited NA?*/ 00145 if (ip6_addr_ismulticast(ip6_current_dest_addr())) { 00146 /* This is an unsolicited NA. 00147 * link-layer changed? 00148 * part of DAD mechanism? */ 00149 00150 /* Check that link-layer address option also fits in packet. */ 00151 if (p->len < (sizeof(struct na_header) + 2)) { 00152 /* @todo debug message */ 00153 pbuf_free(p); 00154 ND6_STATS_INC(nd6.lenerr); 00155 ND6_STATS_INC(nd6.drop); 00156 return; 00157 } 00158 00159 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); 00160 00161 if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { 00162 /* @todo debug message */ 00163 pbuf_free(p); 00164 ND6_STATS_INC(nd6.lenerr); 00165 ND6_STATS_INC(nd6.drop); 00166 return; 00167 } 00168 00169 /* Override ip6_current_dest_addr() so that we have an aligned copy. */ 00170 ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); 00171 00172 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS 00173 /* If the target address matches this netif, it is a DAD response. */ 00174 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { 00175 if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && 00176 ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { 00177 /* We are using a duplicate address. */ 00178 netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); 00179 00180 #if LWIP_IPV6_MLD 00181 /* Leave solicited node multicast group. */ 00182 ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); 00183 mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address); 00184 #endif /* LWIP_IPV6_MLD */ 00185 00186 #if LWIP_IPV6_AUTOCONFIG 00187 /* Check to see if this address was autoconfigured. */ 00188 if (!ip6_addr_islinklocal(ip6_current_dest_addr())) { 00189 i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); 00190 if (i >= 0) { 00191 /* Mark this prefix as duplicate, so that we don't use it 00192 * to generate this address again. */ 00193 prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; 00194 } 00195 } 00196 #endif /* LWIP_IPV6_AUTOCONFIG */ 00197 00198 pbuf_free(p); 00199 return; 00200 } 00201 } 00202 #endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ 00203 00204 /* This is an unsolicited NA, most likely there was a LLADDR change. */ 00205 i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); 00206 if (i >= 0) { 00207 if (na_hdr->flags & ND6_FLAG_OVERRIDE) { 00208 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00209 } 00210 } 00211 } else { 00212 /* This is a solicited NA. 00213 * neighbor address resolution response? 00214 * neighbor unreachability detection response? */ 00215 00216 /* Override ip6_current_dest_addr() so that we have an aligned copy. */ 00217 ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); 00218 00219 /* Find the cache entry corresponding to this na. */ 00220 i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); 00221 if (i < 0) { 00222 /* We no longer care about this target address. drop it. */ 00223 pbuf_free(p); 00224 return; 00225 } 00226 00227 /* Update cache entry. */ 00228 neighbor_cache[i].netif = inp; 00229 neighbor_cache[i].counter.reachable_time = reachable_time; 00230 if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || 00231 (neighbor_cache[i].state == ND6_INCOMPLETE)) { 00232 /* Check that link-layer address option also fits in packet. */ 00233 if (p->len < (sizeof(struct na_header) + 2)) { 00234 /* @todo debug message */ 00235 pbuf_free(p); 00236 ND6_STATS_INC(nd6.lenerr); 00237 ND6_STATS_INC(nd6.drop); 00238 return; 00239 } 00240 00241 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); 00242 00243 if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { 00244 /* @todo debug message */ 00245 pbuf_free(p); 00246 ND6_STATS_INC(nd6.lenerr); 00247 ND6_STATS_INC(nd6.drop); 00248 return; 00249 } 00250 00251 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00252 } 00253 neighbor_cache[i].state = ND6_REACHABLE; 00254 00255 /* Send queued packets, if any. */ 00256 if (neighbor_cache[i].q != NULL) { 00257 nd6_send_q(i); 00258 } 00259 } 00260 00261 break; /* ICMP6_TYPE_NA */ 00262 } 00263 case ICMP6_TYPE_NS: /* Neighbor solicitation. */ 00264 { 00265 struct ns_header * ns_hdr; 00266 struct lladdr_option * lladdr_opt; 00267 u8_t accepted; 00268 00269 /* Check that ns header fits in packet. */ 00270 if (p->len < sizeof(struct ns_header)) { 00271 /* @todo debug message */ 00272 pbuf_free(p); 00273 ND6_STATS_INC(nd6.lenerr); 00274 ND6_STATS_INC(nd6.drop); 00275 return; 00276 } 00277 00278 ns_hdr = (struct ns_header *)p->payload; 00279 00280 /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ 00281 if (p->len >= (sizeof(struct ns_header) + 2)) { 00282 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); 00283 if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { 00284 lladdr_opt = NULL; 00285 } 00286 } else { 00287 lladdr_opt = NULL; 00288 } 00289 00290 /* Check if the target address is configured on the receiving netif. */ 00291 accepted = 0; 00292 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { 00293 if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || 00294 (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && 00295 ip6_addr_isany(ip6_current_src_addr()))) && 00296 ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { 00297 accepted = 1; 00298 break; 00299 } 00300 } 00301 00302 /* NS not for us? */ 00303 if (!accepted) { 00304 pbuf_free(p); 00305 return; 00306 } 00307 00308 /* Check for ANY address in src (DAD algorithm). */ 00309 if (ip6_addr_isany(ip6_current_src_addr())) { 00310 /* Sender is validating this address. */ 00311 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { 00312 if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && 00313 ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { 00314 /* Send a NA back so that the sender does not use this address. */ 00315 nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); 00316 if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { 00317 /* We shouldn't use this address either. */ 00318 netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); 00319 } 00320 } 00321 } 00322 } else { 00323 /* Sender is trying to resolve our address. */ 00324 /* Verify that they included their own link-layer address. */ 00325 if (lladdr_opt == NULL) { 00326 /* Not a valid message. */ 00327 pbuf_free(p); 00328 ND6_STATS_INC(nd6.proterr); 00329 ND6_STATS_INC(nd6.drop); 00330 return; 00331 } 00332 00333 i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); 00334 if (i>= 0) { 00335 /* We already have a record for the solicitor. */ 00336 if (neighbor_cache[i].state == ND6_INCOMPLETE) { 00337 neighbor_cache[i].netif = inp; 00338 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00339 00340 /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ 00341 neighbor_cache[i].state = ND6_DELAY; 00342 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; 00343 } 00344 } else { 00345 /* Add their IPv6 address and link-layer address to neighbor cache. 00346 * We will need it at least to send a unicast NA message, but most 00347 * likely we will also be communicating with this node soon. */ 00348 i = nd6_new_neighbor_cache_entry(); 00349 if (i < 0) { 00350 /* We couldn't assign a cache entry for this neighbor. 00351 * we won't be able to reply. drop it. */ 00352 pbuf_free(p); 00353 ND6_STATS_INC(nd6.memerr); 00354 return; 00355 } 00356 neighbor_cache[i].netif = inp; 00357 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00358 ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); 00359 00360 /* Receiving a message does not prove reachability: only in one direction. 00361 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ 00362 neighbor_cache[i].state = ND6_DELAY; 00363 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; 00364 } 00365 00366 /* Override ip6_current_dest_addr() so that we have an aligned copy. */ 00367 ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); 00368 00369 /* Send back a NA for us. Allocate the reply pbuf. */ 00370 nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); 00371 } 00372 00373 break; /* ICMP6_TYPE_NS */ 00374 } 00375 case ICMP6_TYPE_RA: /* Router Advertisement. */ 00376 { 00377 struct ra_header * ra_hdr; 00378 u8_t * buffer; /* Used to copy options. */ 00379 u16_t offset; 00380 00381 /* Check that RA header fits in packet. */ 00382 if (p->len < sizeof(struct ra_header)) { 00383 /* @todo debug message */ 00384 pbuf_free(p); 00385 ND6_STATS_INC(nd6.lenerr); 00386 ND6_STATS_INC(nd6.drop); 00387 return; 00388 } 00389 00390 ra_hdr = (struct ra_header *)p->payload; 00391 00392 /* If we are sending RS messages, stop. */ 00393 #if LWIP_IPV6_SEND_ROUTER_SOLICIT 00394 /* ensure at least one solicitation is sent */ 00395 if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || 00396 (nd6_send_rs(inp) == ERR_OK)) { 00397 inp->rs_count = 0; 00398 } 00399 #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ 00400 00401 /* Get the matching default router entry. */ 00402 i = nd6_get_router(ip6_current_src_addr(), inp); 00403 if (i < 0) { 00404 /* Create a new router entry. */ 00405 i = nd6_new_router(ip6_current_src_addr(), inp); 00406 } 00407 00408 if (i < 0) { 00409 /* Could not create a new router entry. */ 00410 pbuf_free(p); 00411 ND6_STATS_INC(nd6.memerr); 00412 return; 00413 } 00414 00415 /* Re-set invalidation timer. */ 00416 default_router_list[i].invalidation_timer = htons(ra_hdr->router_lifetime); 00417 00418 /* Re-set default timer values. */ 00419 #if LWIP_ND6_ALLOW_RA_UPDATES 00420 if (ra_hdr->retrans_timer > 0) { 00421 retrans_timer = htonl(ra_hdr->retrans_timer); 00422 } 00423 if (ra_hdr->reachable_time > 0) { 00424 reachable_time = htonl(ra_hdr->reachable_time); 00425 } 00426 #endif /* LWIP_ND6_ALLOW_RA_UPDATES */ 00427 00428 /* @todo set default hop limit... */ 00429 /* ra_hdr->current_hop_limit;*/ 00430 00431 /* Update flags in local entry (incl. preference). */ 00432 default_router_list[i].flags = ra_hdr->flags; 00433 00434 /* Offset to options. */ 00435 offset = sizeof(struct ra_header); 00436 00437 /* Process each option. */ 00438 while ((p->tot_len - offset) > 0) { 00439 if (p->len == p->tot_len) { 00440 /* no need to copy from contiguous pbuf */ 00441 buffer = &((u8_t*)p->payload)[offset]; 00442 } else { 00443 buffer = nd6_ra_buffer; 00444 pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); 00445 } 00446 if (buffer[1] == 0) { 00447 /* zero-length extension. drop packet */ 00448 pbuf_free(p); 00449 ND6_STATS_INC(nd6.lenerr); 00450 ND6_STATS_INC(nd6.drop); 00451 return; 00452 } 00453 switch (buffer[0]) { 00454 case ND6_OPTION_TYPE_SOURCE_LLADDR: 00455 { 00456 struct lladdr_option * lladdr_opt; 00457 lladdr_opt = (struct lladdr_option *)buffer; 00458 if ((default_router_list[i].neighbor_entry != NULL) && 00459 (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { 00460 SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); 00461 default_router_list[i].neighbor_entry->state = ND6_REACHABLE; 00462 default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; 00463 } 00464 break; 00465 } 00466 case ND6_OPTION_TYPE_MTU: 00467 { 00468 struct mtu_option * mtu_opt; 00469 mtu_opt = (struct mtu_option *)buffer; 00470 if (htonl(mtu_opt->mtu) >= 1280) { 00471 #if LWIP_ND6_ALLOW_RA_UPDATES 00472 inp->mtu = (u16_t)htonl(mtu_opt->mtu); 00473 #endif /* LWIP_ND6_ALLOW_RA_UPDATES */ 00474 } 00475 break; 00476 } 00477 case ND6_OPTION_TYPE_PREFIX_INFO: 00478 { 00479 struct prefix_option * prefix_opt; 00480 prefix_opt = (struct prefix_option *)buffer; 00481 00482 if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) { 00483 /* Add to on-link prefix list. */ 00484 s8_t prefix; 00485 00486 /* Get a memory-aligned copy of the prefix. */ 00487 ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix)); 00488 00489 /* find cache entry for this prefix. */ 00490 prefix = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); 00491 if (prefix < 0) { 00492 /* Create a new cache entry. */ 00493 prefix = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp); 00494 } 00495 if (prefix >= 0) { 00496 prefix_list[prefix].invalidation_timer = htonl(prefix_opt->valid_lifetime); 00497 00498 #if LWIP_IPV6_AUTOCONFIG 00499 if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { 00500 /* Mark prefix as autonomous, so that address autoconfiguration can take place. 00501 * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/ 00502 prefix_list[prefix].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; 00503 } 00504 #endif /* LWIP_IPV6_AUTOCONFIG */ 00505 } 00506 } 00507 00508 break; 00509 } 00510 case ND6_OPTION_TYPE_ROUTE_INFO: 00511 /* @todo implement preferred routes. 00512 struct route_option * route_opt; 00513 route_opt = (struct route_option *)buffer;*/ 00514 00515 break; 00516 default: 00517 /* Unrecognized option, abort. */ 00518 ND6_STATS_INC(nd6.proterr); 00519 break; 00520 } 00521 /* option length is checked earlier to be non-zero to make sure loop ends */ 00522 offset += 8 * ((u16_t)buffer[1]); 00523 } 00524 00525 break; /* ICMP6_TYPE_RA */ 00526 } 00527 case ICMP6_TYPE_RD: /* Redirect */ 00528 { 00529 struct redirect_header * redir_hdr; 00530 struct lladdr_option * lladdr_opt; 00531 00532 /* Check that Redir header fits in packet. */ 00533 if (p->len < sizeof(struct redirect_header)) { 00534 /* @todo debug message */ 00535 pbuf_free(p); 00536 ND6_STATS_INC(nd6.lenerr); 00537 ND6_STATS_INC(nd6.drop); 00538 return; 00539 } 00540 00541 redir_hdr = (struct redirect_header *)p->payload; 00542 00543 if (p->len >= (sizeof(struct redirect_header) + 2)) { 00544 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); 00545 if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { 00546 lladdr_opt = NULL; 00547 } 00548 } else { 00549 lladdr_opt = NULL; 00550 } 00551 00552 /* Copy original destination address to current source address, to have an aligned copy. */ 00553 ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address)); 00554 00555 /* Find dest address in cache */ 00556 i = nd6_find_destination_cache_entry(ip6_current_src_addr()); 00557 if (i < 0) { 00558 /* Destination not in cache, drop packet. */ 00559 pbuf_free(p); 00560 return; 00561 } 00562 00563 /* Set the new target address. */ 00564 ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address)); 00565 00566 /* If Link-layer address of other router is given, try to add to neighbor cache. */ 00567 if (lladdr_opt != NULL) { 00568 if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { 00569 /* Copy target address to current source address, to have an aligned copy. */ 00570 ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address)); 00571 00572 i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); 00573 if (i < 0) { 00574 i = nd6_new_neighbor_cache_entry(); 00575 if (i >= 0) { 00576 neighbor_cache[i].netif = inp; 00577 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00578 ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); 00579 00580 /* Receiving a message does not prove reachability: only in one direction. 00581 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ 00582 neighbor_cache[i].state = ND6_DELAY; 00583 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; 00584 } 00585 } 00586 if (i >= 0) { 00587 if (neighbor_cache[i].state == ND6_INCOMPLETE) { 00588 MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 00589 /* Receiving a message does not prove reachability: only in one direction. 00590 * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ 00591 neighbor_cache[i].state = ND6_DELAY; 00592 neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; 00593 } 00594 } 00595 } 00596 } 00597 break; /* ICMP6_TYPE_RD */ 00598 } 00599 case ICMP6_TYPE_PTB: /* Packet too big */ 00600 { 00601 struct icmp6_hdr *icmp6hdr; /* Packet too big message */ 00602 struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */ 00603 u32_t pmtu; 00604 00605 /* Check that ICMPv6 header + IPv6 header fit in payload */ 00606 if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { 00607 /* drop short packets */ 00608 pbuf_free(p); 00609 ND6_STATS_INC(nd6.lenerr); 00610 ND6_STATS_INC(nd6.drop); 00611 return; 00612 } 00613 00614 icmp6hdr = (struct icmp6_hdr *)p->payload; 00615 ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); 00616 00617 /* Copy original destination address to current source address, to have an aligned copy. */ 00618 ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest)); 00619 00620 /* Look for entry in destination cache. */ 00621 i = nd6_find_destination_cache_entry(ip6_current_src_addr()); 00622 if (i < 0) { 00623 /* Destination not in cache, drop packet. */ 00624 pbuf_free(p); 00625 return; 00626 } 00627 00628 /* Change the Path MTU. */ 00629 pmtu = htonl(icmp6hdr->data); 00630 destination_cache[i].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); 00631 00632 break; /* ICMP6_TYPE_PTB */ 00633 } 00634 00635 default: 00636 ND6_STATS_INC(nd6.proterr); 00637 ND6_STATS_INC(nd6.drop); 00638 break; /* default */ 00639 } 00640 00641 pbuf_free(p); 00642 } 00643 00644 00645 /** 00646 * Periodic timer for Neighbor discovery functions: 00647 * 00648 * - Update neighbor reachability states 00649 * - Update destination cache entries age 00650 * - Update invalidation timers of default routers and on-link prefixes 00651 * - Perform duplicate address detection (DAD) for our addresses 00652 * - Send router solicitations 00653 */ 00654 void 00655 nd6_tmr(void) 00656 { 00657 s8_t i; 00658 struct netif * netif; 00659 00660 /* Process neighbor entries. */ 00661 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 00662 switch (neighbor_cache[i].state) { 00663 case ND6_INCOMPLETE: 00664 if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && 00665 (!neighbor_cache[i].isrouter)) { 00666 /* Retries exceeded. */ 00667 nd6_free_neighbor_cache_entry(i); 00668 } else { 00669 /* Send a NS for this entry. */ 00670 neighbor_cache[i].counter.probes_sent++; 00671 nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST); 00672 } 00673 break; 00674 case ND6_REACHABLE: 00675 /* Send queued packets, if any are left. Should have been sent already. */ 00676 if (neighbor_cache[i].q != NULL) { 00677 nd6_send_q(i); 00678 } 00679 if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { 00680 /* Change to stale state. */ 00681 neighbor_cache[i].state = ND6_STALE; 00682 neighbor_cache[i].counter.stale_time = 0; 00683 } else { 00684 neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; 00685 } 00686 break; 00687 case ND6_STALE: 00688 neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL; 00689 break; 00690 case ND6_DELAY: 00691 if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) { 00692 /* Change to PROBE state. */ 00693 neighbor_cache[i].state = ND6_PROBE; 00694 neighbor_cache[i].counter.probes_sent = 0; 00695 } else { 00696 neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; 00697 } 00698 break; 00699 case ND6_PROBE: 00700 if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && 00701 (!neighbor_cache[i].isrouter)) { 00702 /* Retries exceeded. */ 00703 nd6_free_neighbor_cache_entry(i); 00704 } else { 00705 /* Send a NS for this entry. */ 00706 neighbor_cache[i].counter.probes_sent++; 00707 nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0); 00708 } 00709 break; 00710 case ND6_NO_ENTRY: 00711 default: 00712 /* Do nothing. */ 00713 break; 00714 } 00715 } 00716 00717 /* Process destination entries. */ 00718 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { 00719 destination_cache[i].age++; 00720 } 00721 00722 /* Process router entries. */ 00723 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { 00724 if (default_router_list[i].neighbor_entry != NULL) { 00725 /* Active entry. */ 00726 if (default_router_list[i].invalidation_timer > 0) { 00727 default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; 00728 } 00729 if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { 00730 /* Less than 1 second remaining. Clear this entry. */ 00731 default_router_list[i].neighbor_entry->isrouter = 0; 00732 default_router_list[i].neighbor_entry = NULL; 00733 default_router_list[i].invalidation_timer = 0; 00734 default_router_list[i].flags = 0; 00735 } 00736 } 00737 } 00738 00739 /* Process prefix entries. */ 00740 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { 00741 if (prefix_list[i].netif != NULL) { 00742 if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { 00743 /* Entry timed out, remove it */ 00744 prefix_list[i].invalidation_timer = 0; 00745 00746 #if LWIP_IPV6_AUTOCONFIG 00747 /* If any addresses were configured with this prefix, remove them */ 00748 if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) { 00749 s8_t j; 00750 00751 for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { 00752 if ((netif_ip6_addr_state(prefix_list[i].netif, j) != IP6_ADDR_INVALID) && 00753 ip6_addr_netcmp(&prefix_list[i].prefix, netif_ip6_addr(prefix_list[i].netif, j))) { 00754 netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_INVALID); 00755 prefix_list[i].flags = 0; 00756 00757 /* Exit loop. */ 00758 break; 00759 } 00760 } 00761 } 00762 #endif /* LWIP_IPV6_AUTOCONFIG */ 00763 00764 prefix_list[i].netif = NULL; 00765 prefix_list[i].flags = 0; 00766 } else { 00767 prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; 00768 00769 #if LWIP_IPV6_AUTOCONFIG 00770 /* Initiate address autoconfiguration for this prefix, if conditions are met. */ 00771 if (prefix_list[i].netif->ip6_autoconfig_enabled && 00772 (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) && 00773 !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) { 00774 s8_t j; 00775 /* Try to get an address on this netif that is invalid. 00776 * Skip 0 index (link-local address) */ 00777 for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { 00778 if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) { 00779 /* Generate an address using this prefix and interface ID from link-local address. */ 00780 netif_ip6_addr_set_parts(prefix_list[i].netif, j, 00781 prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1], 00782 netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]); 00783 00784 /* Mark it as tentative (DAD will be performed if configured). */ 00785 netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); 00786 00787 /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ 00788 prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; 00789 00790 /* Exit loop. */ 00791 break; 00792 } 00793 } 00794 } 00795 #endif /* LWIP_IPV6_AUTOCONFIG */ 00796 } 00797 } 00798 } 00799 00800 00801 /* Process our own addresses, if DAD configured. */ 00802 for (netif = netif_list; netif != NULL; netif = netif->next) { 00803 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { 00804 u8_t addr_state = netif_ip6_addr_state(netif, i); 00805 if (ip6_addr_istentative(addr_state)) { 00806 if ((addr_state & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { 00807 /* No NA received in response. Mark address as valid. */ 00808 netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); 00809 /* @todo implement preferred and valid lifetimes. */ 00810 } else if (netif->flags & NETIF_FLAG_UP) { 00811 #if LWIP_IPV6_MLD 00812 if ((addr_state & 0x07) == 0) { 00813 /* Join solicited node multicast group. */ 00814 ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); 00815 mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address); 00816 } 00817 #endif /* LWIP_IPV6_MLD */ 00818 /* Send a NS for this address. */ 00819 nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); 00820 /* tentative: set next state by increasing by one */ 00821 netif_ip6_addr_set_state(netif, i, addr_state + 1); 00822 /* @todo send max 1 NS per tmr call? enable return*/ 00823 /*return;*/ 00824 } 00825 } 00826 } 00827 } 00828 00829 #if LWIP_IPV6_SEND_ROUTER_SOLICIT 00830 /* Send router solicitation messages, if necessary. */ 00831 for (netif = netif_list; netif != NULL; netif = netif->next) { 00832 if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP) && 00833 (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)))) { 00834 if (nd6_send_rs(netif) == ERR_OK) { 00835 netif->rs_count--; 00836 } 00837 } 00838 } 00839 #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ 00840 00841 } 00842 00843 /** 00844 * Send a neighbor solicitation message 00845 * 00846 * @param netif the netif on which to send the message 00847 * @param target_addr the IPv6 target address for the ND message 00848 * @param flags one of ND6_SEND_FLAG_* 00849 */ 00850 static void 00851 nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags) 00852 { 00853 struct ns_header * ns_hdr; 00854 struct pbuf * p; 00855 const ip6_addr_t * src_addr; 00856 u16_t lladdr_opt_len; 00857 00858 if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { 00859 /* Use link-local address as source address. */ 00860 src_addr = netif_ip6_addr(netif, 0); 00861 /* calculate option length (in 8-byte-blocks) */ 00862 lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; 00863 } else { 00864 src_addr = IP6_ADDR_ANY6; 00865 /* Option "MUST NOT be included when the source IP address is the unspecified address." */ 00866 lladdr_opt_len = 0; 00867 } 00868 00869 /* Allocate a packet. */ 00870 p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); 00871 if (p == NULL) { 00872 ND6_STATS_INC(nd6.memerr); 00873 return; 00874 } 00875 00876 /* Set fields. */ 00877 ns_hdr = (struct ns_header *)p->payload; 00878 00879 ns_hdr->type = ICMP6_TYPE_NS; 00880 ns_hdr->code = 0; 00881 ns_hdr->chksum = 0; 00882 ns_hdr->reserved = 0; 00883 ip6_addr_set(&(ns_hdr->target_address), target_addr); 00884 00885 if (lladdr_opt_len != 0) { 00886 struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); 00887 lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; 00888 lladdr_opt->length = (u8_t)lladdr_opt_len; 00889 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); 00890 } 00891 00892 /* Generate the solicited node address for the target address. */ 00893 if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { 00894 ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); 00895 target_addr = &multicast_address; 00896 } 00897 00898 #if CHECKSUM_GEN_ICMP6 00899 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { 00900 ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, 00901 target_addr); 00902 } 00903 #endif /* CHECKSUM_GEN_ICMP6 */ 00904 00905 /* Send the packet out. */ 00906 ND6_STATS_INC(nd6.xmit); 00907 ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, 00908 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); 00909 pbuf_free(p); 00910 } 00911 00912 /** 00913 * Send a neighbor advertisement message 00914 * 00915 * @param netif the netif on which to send the message 00916 * @param target_addr the IPv6 target address for the ND message 00917 * @param flags one of ND6_SEND_FLAG_* 00918 */ 00919 static void 00920 nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags) 00921 { 00922 struct na_header * na_hdr; 00923 struct lladdr_option * lladdr_opt; 00924 struct pbuf * p; 00925 const ip6_addr_t * src_addr; 00926 const ip6_addr_t * dest_addr; 00927 u16_t lladdr_opt_len; 00928 00929 /* Use link-local address as source address. */ 00930 /* src_addr = netif_ip6_addr(netif, 0); */ 00931 /* Use target address as source address. */ 00932 src_addr = target_addr; 00933 00934 /* Allocate a packet. */ 00935 lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); 00936 p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); 00937 if (p == NULL) { 00938 ND6_STATS_INC(nd6.memerr); 00939 return; 00940 } 00941 00942 /* Set fields. */ 00943 na_hdr = (struct na_header *)p->payload; 00944 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); 00945 00946 na_hdr->type = ICMP6_TYPE_NA; 00947 na_hdr->code = 0; 00948 na_hdr->chksum = 0; 00949 na_hdr->flags = flags & 0xf0; 00950 na_hdr->reserved[0] = 0; 00951 na_hdr->reserved[1] = 0; 00952 na_hdr->reserved[2] = 0; 00953 ip6_addr_set(&(na_hdr->target_address), target_addr); 00954 00955 lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; 00956 lladdr_opt->length = (u8_t)lladdr_opt_len; 00957 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); 00958 00959 /* Generate the solicited node address for the target address. */ 00960 if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { 00961 ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); 00962 dest_addr = &multicast_address; 00963 } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { 00964 ip6_addr_set_allnodes_linklocal(&multicast_address); 00965 dest_addr = &multicast_address; 00966 } else { 00967 dest_addr = ip6_current_src_addr(); 00968 } 00969 00970 #if CHECKSUM_GEN_ICMP6 00971 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { 00972 na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, 00973 dest_addr); 00974 } 00975 #endif /* CHECKSUM_GEN_ICMP6 */ 00976 00977 /* Send the packet out. */ 00978 ND6_STATS_INC(nd6.xmit); 00979 ip6_output_if(p, src_addr, dest_addr, 00980 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); 00981 pbuf_free(p); 00982 } 00983 00984 #if LWIP_IPV6_SEND_ROUTER_SOLICIT 00985 /** 00986 * Send a router solicitation message 00987 * 00988 * @param netif the netif on which to send the message 00989 */ 00990 static err_t 00991 nd6_send_rs(struct netif * netif) 00992 { 00993 struct rs_header * rs_hdr; 00994 struct lladdr_option * lladdr_opt; 00995 struct pbuf * p; 00996 const ip6_addr_t * src_addr; 00997 err_t err; 00998 u16_t lladdr_opt_len = 0; 00999 01000 /* Link-local source address, or unspecified address? */ 01001 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { 01002 src_addr = netif_ip6_addr(netif, 0); 01003 } else { 01004 src_addr = IP6_ADDR_ANY6; 01005 } 01006 01007 /* Generate the all routers target address. */ 01008 ip6_addr_set_allrouters_linklocal(&multicast_address); 01009 01010 /* Allocate a packet. */ 01011 if (src_addr != IP6_ADDR_ANY6) { 01012 lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); 01013 } 01014 p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); 01015 if (p == NULL) { 01016 ND6_STATS_INC(nd6.memerr); 01017 return ERR_BUF; 01018 } 01019 01020 /* Set fields. */ 01021 rs_hdr = (struct rs_header *)p->payload; 01022 01023 rs_hdr->type = ICMP6_TYPE_RS; 01024 rs_hdr->code = 0; 01025 rs_hdr->chksum = 0; 01026 rs_hdr->reserved = 0; 01027 01028 if (src_addr != IP6_ADDR_ANY6) { 01029 /* Include our hw address. */ 01030 lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); 01031 lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; 01032 lladdr_opt->length = (u8_t)lladdr_opt_len; 01033 SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); 01034 } 01035 01036 #if CHECKSUM_GEN_ICMP6 01037 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { 01038 rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, 01039 &multicast_address); 01040 } 01041 #endif /* CHECKSUM_GEN_ICMP6 */ 01042 01043 /* Send the packet out. */ 01044 ND6_STATS_INC(nd6.xmit); 01045 01046 err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, 01047 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); 01048 pbuf_free(p); 01049 01050 return err; 01051 } 01052 #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ 01053 01054 /** 01055 * Search for a neighbor cache entry 01056 * 01057 * @param ip6addr the IPv6 address of the neighbor 01058 * @return The neighbor cache entry index that matched, -1 if no 01059 * entry is found 01060 */ 01061 static s8_t 01062 nd6_find_neighbor_cache_entry(const ip6_addr_t * ip6addr) 01063 { 01064 s8_t i; 01065 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01066 if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { 01067 return i; 01068 } 01069 } 01070 return -1; 01071 } 01072 01073 /** 01074 * Create a new neighbor cache entry. 01075 * 01076 * If no unused entry is found, will try to recycle an old entry 01077 * according to ad-hoc "age" heuristic. 01078 * 01079 * @return The neighbor cache entry index that was created, -1 if no 01080 * entry could be created 01081 */ 01082 static s8_t 01083 nd6_new_neighbor_cache_entry(void) 01084 { 01085 s8_t i; 01086 s8_t j; 01087 u32_t time; 01088 01089 01090 /* First, try to find an empty entry. */ 01091 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01092 if (neighbor_cache[i].state == ND6_NO_ENTRY) { 01093 return i; 01094 } 01095 } 01096 01097 /* We need to recycle an entry. in general, do not recycle if it is a router. */ 01098 01099 /* Next, try to find a Stale entry. */ 01100 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01101 if ((neighbor_cache[i].state == ND6_STALE) && 01102 (!neighbor_cache[i].isrouter)) { 01103 nd6_free_neighbor_cache_entry(i); 01104 return i; 01105 } 01106 } 01107 01108 /* Next, try to find a Probe entry. */ 01109 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01110 if ((neighbor_cache[i].state == ND6_PROBE) && 01111 (!neighbor_cache[i].isrouter)) { 01112 nd6_free_neighbor_cache_entry(i); 01113 return i; 01114 } 01115 } 01116 01117 /* Next, try to find a Delayed entry. */ 01118 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01119 if ((neighbor_cache[i].state == ND6_DELAY) && 01120 (!neighbor_cache[i].isrouter)) { 01121 nd6_free_neighbor_cache_entry(i); 01122 return i; 01123 } 01124 } 01125 01126 /* Next, try to find the oldest reachable entry. */ 01127 time = 0xfffffffful; 01128 j = -1; 01129 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01130 if ((neighbor_cache[i].state == ND6_REACHABLE) && 01131 (!neighbor_cache[i].isrouter)) { 01132 if (neighbor_cache[i].counter.reachable_time < time) { 01133 j = i; 01134 time = neighbor_cache[i].counter.reachable_time; 01135 } 01136 } 01137 } 01138 if (j >= 0) { 01139 nd6_free_neighbor_cache_entry(j); 01140 return j; 01141 } 01142 01143 /* Next, find oldest incomplete entry without queued packets. */ 01144 time = 0; 01145 j = -1; 01146 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01147 if ( 01148 (neighbor_cache[i].q == NULL) && 01149 (neighbor_cache[i].state == ND6_INCOMPLETE) && 01150 (!neighbor_cache[i].isrouter)) { 01151 if (neighbor_cache[i].counter.probes_sent >= time) { 01152 j = i; 01153 time = neighbor_cache[i].counter.probes_sent; 01154 } 01155 } 01156 } 01157 if (j >= 0) { 01158 nd6_free_neighbor_cache_entry(j); 01159 return j; 01160 } 01161 01162 /* Next, find oldest incomplete entry with queued packets. */ 01163 time = 0; 01164 j = -1; 01165 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01166 if ((neighbor_cache[i].state == ND6_INCOMPLETE) && 01167 (!neighbor_cache[i].isrouter)) { 01168 if (neighbor_cache[i].counter.probes_sent >= time) { 01169 j = i; 01170 time = neighbor_cache[i].counter.probes_sent; 01171 } 01172 } 01173 } 01174 if (j >= 0) { 01175 nd6_free_neighbor_cache_entry(j); 01176 return j; 01177 } 01178 01179 /* No more entries to try. */ 01180 return -1; 01181 } 01182 01183 /** 01184 * Will free any resources associated with a neighbor cache 01185 * entry, and will mark it as unused. 01186 * 01187 * @param i the neighbor cache entry index to free 01188 */ 01189 static void 01190 nd6_free_neighbor_cache_entry(s8_t i) 01191 { 01192 if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { 01193 return; 01194 } 01195 if (neighbor_cache[i].isrouter) { 01196 /* isrouter needs to be cleared before deleting a neighbor cache entry */ 01197 return; 01198 } 01199 01200 /* Free any queued packets. */ 01201 if (neighbor_cache[i].q != NULL) { 01202 nd6_free_q(neighbor_cache[i].q); 01203 neighbor_cache[i].q = NULL; 01204 } 01205 01206 neighbor_cache[i].state = ND6_NO_ENTRY; 01207 neighbor_cache[i].isrouter = 0; 01208 neighbor_cache[i].netif = NULL; 01209 neighbor_cache[i].counter.reachable_time = 0; 01210 ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); 01211 } 01212 01213 /** 01214 * Search for a destination cache entry 01215 * 01216 * @param ip6addr the IPv6 address of the destination 01217 * @return The destination cache entry index that matched, -1 if no 01218 * entry is found 01219 */ 01220 static s8_t 01221 nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr) 01222 { 01223 s8_t i; 01224 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { 01225 if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { 01226 return i; 01227 } 01228 } 01229 return -1; 01230 } 01231 01232 /** 01233 * Create a new destination cache entry. If no unused entry is found, 01234 * will recycle oldest entry. 01235 * 01236 * @return The destination cache entry index that was created, -1 if no 01237 * entry was created 01238 */ 01239 static s8_t 01240 nd6_new_destination_cache_entry(void) 01241 { 01242 s8_t i, j; 01243 u32_t age; 01244 01245 /* Find an empty entry. */ 01246 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { 01247 if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { 01248 return i; 01249 } 01250 } 01251 01252 /* Find oldest entry. */ 01253 age = 0; 01254 j = LWIP_ND6_NUM_DESTINATIONS - 1; 01255 for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { 01256 if (destination_cache[i].age > age) { 01257 j = i; 01258 } 01259 } 01260 01261 return j; 01262 } 01263 01264 /** 01265 * Determine whether an address matches an on-link prefix. 01266 * 01267 * @param ip6addr the IPv6 address to match 01268 * @return 1 if the address is on-link, 0 otherwise 01269 */ 01270 static s8_t 01271 nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif) 01272 { 01273 s8_t i; 01274 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { 01275 if ((prefix_list[i].netif == netif) && 01276 (prefix_list[i].invalidation_timer > 0) && 01277 ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { 01278 return 1; 01279 } 01280 } 01281 /* Check to see if address prefix matches a (manually?) configured address. */ 01282 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { 01283 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && 01284 ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { 01285 return 1; 01286 } 01287 } 01288 return 0; 01289 } 01290 01291 /** 01292 * Select a default router for a destination. 01293 * 01294 * @param ip6addr the destination address 01295 * @param netif the netif for the outgoing packet, if known 01296 * @return the default router entry index, or -1 if no suitable 01297 * router is found 01298 */ 01299 s8_t 01300 nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif) 01301 { 01302 s8_t i; 01303 /* last_router is used for round-robin router selection (as recommended 01304 * in RFC). This is more robust in case one router is not reachable, 01305 * we are not stuck trying to resolve it. */ 01306 static s8_t last_router; 01307 (void)ip6addr; /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ 01308 01309 /* @todo: implement default router preference */ 01310 01311 /* Look for reachable routers. */ 01312 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { 01313 if (++last_router >= LWIP_ND6_NUM_ROUTERS) { 01314 last_router = 0; 01315 } 01316 if ((default_router_list[i].neighbor_entry != NULL) && 01317 (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && 01318 (default_router_list[i].invalidation_timer > 0) && 01319 (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { 01320 return i; 01321 } 01322 } 01323 01324 /* Look for router in other reachability states, but still valid according to timer. */ 01325 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { 01326 if (++last_router >= LWIP_ND6_NUM_ROUTERS) { 01327 last_router = 0; 01328 } 01329 if ((default_router_list[i].neighbor_entry != NULL) && 01330 (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && 01331 (default_router_list[i].invalidation_timer > 0)) { 01332 return i; 01333 } 01334 } 01335 01336 /* Look for any router for which we have any information at all. */ 01337 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { 01338 if (++last_router >= LWIP_ND6_NUM_ROUTERS) { 01339 last_router = 0; 01340 } 01341 if (default_router_list[i].neighbor_entry != NULL && 01342 (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { 01343 return i; 01344 } 01345 } 01346 01347 /* no suitable router found. */ 01348 return -1; 01349 } 01350 01351 /** 01352 * Find an entry for a default router. 01353 * 01354 * @param router_addr the IPv6 address of the router 01355 * @param netif the netif on which the router is found, if known 01356 * @return the index of the router entry, or -1 if not found 01357 */ 01358 static s8_t 01359 nd6_get_router(const ip6_addr_t * router_addr, struct netif * netif) 01360 { 01361 s8_t i; 01362 01363 /* Look for router. */ 01364 for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { 01365 if ((default_router_list[i].neighbor_entry != NULL) && 01366 ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && 01367 ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { 01368 return i; 01369 } 01370 } 01371 01372 /* router not found. */ 01373 return -1; 01374 } 01375 01376 /** 01377 * Create a new entry for a default router. 01378 * 01379 * @param router_addr the IPv6 address of the router 01380 * @param netif the netif on which the router is connected, if known 01381 * @return the index on the router table, or -1 if could not be created 01382 */ 01383 static s8_t 01384 nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif) 01385 { 01386 s8_t router_index; 01387 s8_t neighbor_index; 01388 01389 /* Do we have a neighbor entry for this router? */ 01390 neighbor_index = nd6_find_neighbor_cache_entry(router_addr); 01391 if (neighbor_index < 0) { 01392 /* Create a neighbor entry for this router. */ 01393 neighbor_index = nd6_new_neighbor_cache_entry(); 01394 if (neighbor_index < 0) { 01395 /* Could not create neighbor entry for this router. */ 01396 return -1; 01397 } 01398 ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); 01399 neighbor_cache[neighbor_index].netif = netif; 01400 neighbor_cache[neighbor_index].q = NULL; 01401 neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; 01402 neighbor_cache[neighbor_index].counter.probes_sent = 0; 01403 } 01404 01405 /* Mark neighbor as router. */ 01406 neighbor_cache[neighbor_index].isrouter = 1; 01407 01408 /* Look for empty entry. */ 01409 for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { 01410 if (default_router_list[router_index].neighbor_entry == NULL) { 01411 default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); 01412 return router_index; 01413 } 01414 } 01415 01416 /* Could not create a router entry. */ 01417 01418 /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ 01419 neighbor_cache[neighbor_index].isrouter = 0; 01420 01421 /* router not found. */ 01422 return -1; 01423 } 01424 01425 /** 01426 * Find the cached entry for an on-link prefix. 01427 * 01428 * @param prefix the IPv6 prefix that is on-link 01429 * @param netif the netif on which the prefix is on-link 01430 * @return the index on the prefix table, or -1 if not found 01431 */ 01432 static s8_t 01433 nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) 01434 { 01435 s8_t i; 01436 01437 /* Look for prefix in list. */ 01438 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { 01439 if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && 01440 (prefix_list[i].netif == netif)) { 01441 return i; 01442 } 01443 } 01444 01445 /* Entry not available. */ 01446 return -1; 01447 } 01448 01449 /** 01450 * Creates a new entry for an on-link prefix. 01451 * 01452 * @param prefix the IPv6 prefix that is on-link 01453 * @param netif the netif on which the prefix is on-link 01454 * @return the index on the prefix table, or -1 if not created 01455 */ 01456 static s8_t 01457 nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) 01458 { 01459 s8_t i; 01460 01461 /* Create new entry. */ 01462 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { 01463 if ((prefix_list[i].netif == NULL) || 01464 (prefix_list[i].invalidation_timer == 0)) { 01465 /* Found empty prefix entry. */ 01466 prefix_list[i].netif = netif; 01467 ip6_addr_set(&(prefix_list[i].prefix), prefix); 01468 #if LWIP_IPV6_AUTOCONFIG 01469 prefix_list[i].flags = 0; 01470 #endif /* LWIP_IPV6_AUTOCONFIG */ 01471 return i; 01472 } 01473 } 01474 01475 /* Entry not available. */ 01476 return -1; 01477 } 01478 01479 /** 01480 * Determine the next hop for a destination. Will determine if the 01481 * destination is on-link, else a suitable on-link router is selected. 01482 * 01483 * The last entry index is cached for fast entry search. 01484 * 01485 * @param ip6addr the destination address 01486 * @param netif the netif on which the packet will be sent 01487 * @return the neighbor cache entry for the next hop, ERR_RTE if no 01488 * suitable next hop was found, ERR_MEM if no cache entry 01489 * could be created 01490 */ 01491 s8_t 01492 nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif) 01493 { 01494 s8_t i; 01495 01496 #if LWIP_NETIF_HWADDRHINT 01497 if (netif->addr_hint != NULL) { 01498 /* per-pcb cached entry was given */ 01499 u8_t addr_hint = *(netif->addr_hint); 01500 if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { 01501 nd6_cached_destination_index = addr_hint; 01502 } 01503 } 01504 #endif /* LWIP_NETIF_HWADDRHINT */ 01505 01506 /* Look for ip6addr in destination cache. */ 01507 if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { 01508 /* the cached entry index is the right one! */ 01509 /* do nothing. */ 01510 ND6_STATS_INC(nd6.cachehit); 01511 } else { 01512 /* Search destination cache. */ 01513 i = nd6_find_destination_cache_entry(ip6addr); 01514 if (i >= 0) { 01515 /* found destination entry. make it our new cached index. */ 01516 nd6_cached_destination_index = i; 01517 } else { 01518 /* Not found. Create a new destination entry. */ 01519 i = nd6_new_destination_cache_entry(); 01520 if (i >= 0) { 01521 /* got new destination entry. make it our new cached index. */ 01522 nd6_cached_destination_index = i; 01523 } else { 01524 /* Could not create a destination cache entry. */ 01525 return ERR_MEM; 01526 } 01527 01528 /* Copy dest address to destination cache. */ 01529 ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); 01530 01531 /* Now find the next hop. is it a neighbor? */ 01532 if (ip6_addr_islinklocal(ip6addr) || 01533 nd6_is_prefix_in_netif(ip6addr, netif)) { 01534 /* Destination in local link. */ 01535 destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; 01536 ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); 01537 } else { 01538 /* We need to select a router. */ 01539 i = nd6_select_router(ip6addr, netif); 01540 if (i < 0) { 01541 /* No router found. */ 01542 ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); 01543 return ERR_RTE; 01544 } 01545 destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */ 01546 ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); 01547 } 01548 } 01549 } 01550 01551 #if LWIP_NETIF_HWADDRHINT 01552 if (netif->addr_hint != NULL) { 01553 /* per-pcb cached entry was given */ 01554 *(netif->addr_hint) = nd6_cached_destination_index; 01555 } 01556 #endif /* LWIP_NETIF_HWADDRHINT */ 01557 01558 /* Look in neighbor cache for the next-hop address. */ 01559 if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), 01560 &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { 01561 /* Cache hit. */ 01562 /* Do nothing. */ 01563 ND6_STATS_INC(nd6.cachehit); 01564 } else { 01565 i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); 01566 if (i >= 0) { 01567 /* Found a matching record, make it new cached entry. */ 01568 nd6_cached_neighbor_index = i; 01569 } else { 01570 /* Neighbor not in cache. Make a new entry. */ 01571 i = nd6_new_neighbor_cache_entry(); 01572 if (i >= 0) { 01573 /* got new neighbor entry. make it our new cached index. */ 01574 nd6_cached_neighbor_index = i; 01575 } else { 01576 /* Could not create a neighbor cache entry. */ 01577 return ERR_MEM; 01578 } 01579 01580 /* Initialize fields. */ 01581 ip6_addr_copy(neighbor_cache[i].next_hop_address, 01582 destination_cache[nd6_cached_destination_index].next_hop_addr); 01583 neighbor_cache[i].isrouter = 0; 01584 neighbor_cache[i].netif = netif; 01585 neighbor_cache[i].state = ND6_INCOMPLETE; 01586 neighbor_cache[i].counter.probes_sent = 0; 01587 } 01588 } 01589 01590 /* Reset this destination's age. */ 01591 destination_cache[nd6_cached_destination_index].age = 0; 01592 01593 return nd6_cached_neighbor_index; 01594 } 01595 01596 /** 01597 * Queue a packet for a neighbor. 01598 * 01599 * @param neighbor_index the index in the neighbor cache table 01600 * @param q packet to be queued 01601 * @return ERR_OK if succeeded, ERR_MEM if out of memory 01602 */ 01603 err_t 01604 nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) 01605 { 01606 err_t result = ERR_MEM; 01607 struct pbuf *p; 01608 int copy_needed = 0; 01609 #if LWIP_ND6_QUEUEING 01610 struct nd6_q_entry *new_entry, *r; 01611 #endif /* LWIP_ND6_QUEUEING */ 01612 01613 if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { 01614 return ERR_ARG; 01615 } 01616 01617 /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but 01618 * to copy the whole queue into a new PBUF_RAM (see bug #11400) 01619 * PBUF_ROMs can be left as they are, since ROM must not get changed. */ 01620 p = q; 01621 while (p) { 01622 if (p->type != PBUF_ROM) { 01623 copy_needed = 1; 01624 break; 01625 } 01626 p = p->next; 01627 } 01628 if (copy_needed) { 01629 /* copy the whole packet into new pbufs */ 01630 p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); 01631 while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { 01632 /* Free oldest packet (as per RFC recommendation) */ 01633 #if LWIP_ND6_QUEUEING 01634 r = neighbor_cache[neighbor_index].q; 01635 neighbor_cache[neighbor_index].q = r->next; 01636 r->next = NULL; 01637 nd6_free_q(r); 01638 #else /* LWIP_ND6_QUEUEING */ 01639 pbuf_free(neighbor_cache[neighbor_index].q); 01640 neighbor_cache[neighbor_index].q = NULL; 01641 #endif /* LWIP_ND6_QUEUEING */ 01642 p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); 01643 } 01644 if (p != NULL) { 01645 if (pbuf_copy(p, q) != ERR_OK) { 01646 pbuf_free(p); 01647 p = NULL; 01648 } 01649 } 01650 } else { 01651 /* referencing the old pbuf is enough */ 01652 p = q; 01653 pbuf_ref(p); 01654 } 01655 /* packet was copied/ref'd? */ 01656 if (p != NULL) { 01657 /* queue packet ... */ 01658 #if LWIP_ND6_QUEUEING 01659 /* allocate a new nd6 queue entry */ 01660 new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); 01661 if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { 01662 /* Free oldest packet (as per RFC recommendation) */ 01663 r = neighbor_cache[neighbor_index].q; 01664 neighbor_cache[neighbor_index].q = r->next; 01665 r->next = NULL; 01666 nd6_free_q(r); 01667 new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); 01668 } 01669 if (new_entry != NULL) { 01670 new_entry->next = NULL; 01671 new_entry->p = p; 01672 if (neighbor_cache[neighbor_index].q != NULL) { 01673 /* queue was already existent, append the new entry to the end */ 01674 r = neighbor_cache[neighbor_index].q; 01675 while (r->next != NULL) { 01676 r = r->next; 01677 } 01678 r->next = new_entry; 01679 } else { 01680 /* queue did not exist, first item in queue */ 01681 neighbor_cache[neighbor_index].q = new_entry; 01682 } 01683 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); 01684 result = ERR_OK; 01685 } else { 01686 /* the pool MEMP_ND6_QUEUE is empty */ 01687 pbuf_free(p); 01688 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); 01689 /* { result == ERR_MEM } through initialization */ 01690 } 01691 #else /* LWIP_ND6_QUEUEING */ 01692 /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ 01693 if (neighbor_cache[neighbor_index].q != NULL) { 01694 pbuf_free(neighbor_cache[neighbor_index].q); 01695 } 01696 neighbor_cache[neighbor_index].q = p; 01697 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); 01698 result = ERR_OK; 01699 #endif /* LWIP_ND6_QUEUEING */ 01700 } else { 01701 LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); 01702 /* { result == ERR_MEM } through initialization */ 01703 } 01704 01705 return result; 01706 } 01707 01708 #if LWIP_ND6_QUEUEING 01709 /** 01710 * Free a complete queue of nd6 q entries 01711 * 01712 * @param q a queue of nd6_q_entry to free 01713 */ 01714 static void 01715 nd6_free_q(struct nd6_q_entry *q) 01716 { 01717 struct nd6_q_entry *r; 01718 LWIP_ASSERT("q != NULL", q != NULL); 01719 LWIP_ASSERT("q->p != NULL", q->p != NULL); 01720 while (q) { 01721 r = q; 01722 q = q->next; 01723 LWIP_ASSERT("r->p != NULL", (r->p != NULL)); 01724 pbuf_free(r->p); 01725 memp_free(MEMP_ND6_QUEUE, r); 01726 } 01727 } 01728 #endif /* LWIP_ND6_QUEUEING */ 01729 01730 /** 01731 * Send queued packets for a neighbor 01732 * 01733 * @param i the neighbor to send packets to 01734 */ 01735 static void 01736 nd6_send_q(s8_t i) 01737 { 01738 struct ip6_hdr *ip6hdr; 01739 #if LWIP_ND6_QUEUEING 01740 struct nd6_q_entry *q; 01741 #endif /* LWIP_ND6_QUEUEING */ 01742 01743 if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { 01744 return; 01745 } 01746 01747 #if LWIP_ND6_QUEUEING 01748 while (neighbor_cache[i].q != NULL) { 01749 /* remember first in queue */ 01750 q = neighbor_cache[i].q; 01751 /* pop first item off the queue */ 01752 neighbor_cache[i].q = q->next; 01753 /* Get ipv6 header. */ 01754 ip6hdr = (struct ip6_hdr *)(q->p->payload); 01755 /* Override ip6_current_dest_addr() so that we have an aligned copy. */ 01756 ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); 01757 /* send the queued IPv6 packet */ 01758 (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr()); 01759 /* free the queued IP packet */ 01760 pbuf_free(q->p); 01761 /* now queue entry can be freed */ 01762 memp_free(MEMP_ND6_QUEUE, q); 01763 } 01764 #else /* LWIP_ND6_QUEUEING */ 01765 if (neighbor_cache[i].q != NULL) { 01766 /* Get ipv6 header. */ 01767 ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); 01768 /* Override ip6_current_dest_addr() so that we have an aligned copy. */ 01769 ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); 01770 /* send the queued IPv6 packet */ 01771 (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr()); 01772 /* free the queued IP packet */ 01773 pbuf_free(neighbor_cache[i].q); 01774 neighbor_cache[i].q = NULL; 01775 } 01776 #endif /* LWIP_ND6_QUEUEING */ 01777 } 01778 01779 01780 /** 01781 * Get the Path MTU for a destination. 01782 * 01783 * @param ip6addr the destination address 01784 * @param netif the netif on which the packet will be sent 01785 * @return the Path MTU, if known, or the netif default MTU 01786 */ 01787 u16_t 01788 nd6_get_destination_mtu(const ip6_addr_t * ip6addr, struct netif * netif) 01789 { 01790 s8_t i; 01791 01792 i = nd6_find_destination_cache_entry(ip6addr); 01793 if (i >= 0) { 01794 if (destination_cache[i].pmtu > 0) { 01795 return destination_cache[i].pmtu; 01796 } 01797 } 01798 01799 if (netif != NULL) { 01800 return netif->mtu; 01801 } 01802 01803 return 1280; /* Minimum MTU */ 01804 } 01805 01806 01807 #if LWIP_ND6_TCP_REACHABILITY_HINTS 01808 /** 01809 * Provide the Neighbor discovery process with a hint that a 01810 * destination is reachable. Called by tcp_receive when ACKs are 01811 * received or sent (as per RFC). This is useful to avoid sending 01812 * NS messages every 30 seconds. 01813 * 01814 * @param ip6addr the destination address which is know to be reachable 01815 * by an upper layer protocol (TCP) 01816 */ 01817 void 01818 nd6_reachability_hint(const ip6_addr_t * ip6addr) 01819 { 01820 s8_t i; 01821 01822 /* Find destination in cache. */ 01823 if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { 01824 i = nd6_cached_destination_index; 01825 ND6_STATS_INC(nd6.cachehit); 01826 } else { 01827 i = nd6_find_destination_cache_entry(ip6addr); 01828 } 01829 if (i < 0) { 01830 return; 01831 } 01832 01833 /* Find next hop neighbor in cache. */ 01834 if (ip6_addr_cmp(&(destination_cache[i].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { 01835 i = nd6_cached_neighbor_index; 01836 ND6_STATS_INC(nd6.cachehit); 01837 } else { 01838 i = nd6_find_neighbor_cache_entry(&(destination_cache[i].next_hop_addr)); 01839 } 01840 if (i < 0) { 01841 return; 01842 } 01843 01844 /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ 01845 if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { 01846 return; 01847 } 01848 01849 /* Set reachability state. */ 01850 neighbor_cache[i].state = ND6_REACHABLE; 01851 neighbor_cache[i].counter.reachable_time = reachable_time; 01852 } 01853 #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ 01854 01855 /** 01856 * Remove all prefix, neighbor_cache and router entries of the specified netif. 01857 * 01858 * @param netif points to a network interface 01859 */ 01860 void 01861 nd6_cleanup_netif(struct netif * netif) 01862 { 01863 u8_t i; 01864 s8_t router_index; 01865 for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { 01866 if (prefix_list[i].netif == netif) { 01867 prefix_list[i].netif = NULL; 01868 prefix_list[i].flags = 0; 01869 } 01870 } 01871 for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { 01872 if (neighbor_cache[i].netif == netif) { 01873 for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { 01874 if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { 01875 default_router_list[router_index].neighbor_entry = NULL; 01876 default_router_list[router_index].flags = 0; 01877 } 01878 } 01879 neighbor_cache[i].isrouter = 0; 01880 nd6_free_neighbor_cache_entry(i); 01881 } 01882 } 01883 } 01884 01885 #endif /* LWIP_IPV6 */
Generated on Tue Jul 12 2022 13:15:53 by
