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_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 11:02:42 by
