Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_nd6.c Source File

lwip_nd6.c

Go to the documentation of this file.
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 */