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