nd6: improve address autoconfiguration support

In summary, this patch aims to resolve bugs #47923 and #48162, by
decoupling address autoconfiguration from the on-link prefix list,
since those are not related. Important necessary changes are needed
to meet this goal, ultimately bringing the lwIP ND6 implementation
closer to compliance with RFC 4862. The main changes are:

  1. support for address lifetimes, and,
  2. addition of a new DUPLICATED address state.

The decoupling implies that the prefix list can no longer be used to
maintain state for address autoconfiguration. Most importantly, the
lifetime of each address, which was previously derived from the
prefix slot's lifetime, must now be associated with the address
itself. This patch implements address lifetime tracking, maintaining
both a valid and a preferred lifetime for each address, along with
the corresponding address state changes (e.g., between PREFERRED and
DEPRECATED), all as required by RFC 4862.

The support for address lifetimes can be enabled with a new
LWIP_IPV6_ADDRESS_LIFETIMES setting in lwipopts.h. It is required for
autoconfiguration and enabled by default if autoconfiguration is
enabled as well, but it may also be enabled separately, so as to allow
application-controlled lifetime management (e.g., if autoconfiguration
is implemented in a separate application). A special valid-lifetime of
zero is used to denote a static address--that is, an address that was
configured manually, that does not have lifetimes, and that should be
left alone by the autoconfiguration functionality. Addresses assigned
without setting a lifetime are deemed static, thus preserving
compatibility with existing lwIP-based applications in this respect.

Similarly, the decoupling implies that the prefix list can no longer
be used to remember cases of address duplication. Previously, the
detection of a duplicated address would simply result in removal of
the address altogether. Instead, this patch introduces a new state
"DUPLICATED", indicating that the address, while technically still
present, has been found to conflict with other node addresses, and no
attempt should be made to produce an autoconfiguration address for
that prefix.

Manually added addresses, including the link-local address, once set
to DUPLICATED, will remain in that state until manual intervention.
Autoconfigured DUPLICATED addresses will expire according to their
valid-lifetime, essentially preserving the current behavior but
without the use of the prefix list. As a first attempt to approach
compliance with RFC 4862 Sec. 5.4.5, if the link-local address is
detected to be duplicated, all derived addresses are marked duplicated
as well, and no new addresses will be autoconfigured. More work is to
be done for full compliance with that section, however.

Together, those two main changes indeed do fully decouple address
autoconfiguration from the on-link prefix list. Changes to the latter
thus no longer affect the former, resolving bug #47923. Moreover, as a
result, autoconfiguration can, and does, now also take place on
advertised prefixes that do not have the on-link flag set, resolving
bug #48162. The routing changes mentioned in the discussion of that
bug are left to a separate patch, though.
This commit is contained in:
David van Moolenbroek 2016-12-29 21:03:41 +00:00 committed by Dirk Ziegelmeier
parent 3cc7b319d9
commit e0c5e1988f
6 changed files with 292 additions and 115 deletions

View File

@ -98,8 +98,8 @@ static s8_t nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *neti
static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif);
static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif);
static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q);
@ -120,6 +120,146 @@ static void nd6_free_q(struct nd6_q_entry *q);
static void nd6_send_q(s8_t i);
/**
* A local address has been determined to be a duplicate. Take the appropriate
* action(s) on the address and the interface as a whole.
*
* @param netif the netif that owns the address
* @param addr_idx the index of the address detected to be a duplicate
*/
static void
nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx)
{
/* Mark the address as duplicate, but leave its lifetimes alone. If this was
* a manually assigned address, it will remain in existence as duplicate, and
* as such be unusable for any practical purposes until manual intervention.
* If this was an autogenerated address, the address will follow normal
* expiration rules, and thus disappear once its valid lifetime expires. */
netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED);
#if LWIP_IPV6_AUTOCONFIG
/* If the affected address was the link-local address that we use to generate
* all other addresses, then we should not continue to use those derived
* addresses either, so mark them as duplicate as well. For autoconfig-only
* setups, this will make the interface effectively unusable, approaching the
* intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */
if (addr_idx == 0) {
s8_t i;
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) &&
!netif_ip6_addr_isstatic(netif, i)) {
netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED);
}
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
}
#if LWIP_IPV6_AUTOCONFIG
/**
* We received a router advertisement that contains a prefix with the
* autoconfiguration flag set. Add or update an associated autogenerated
* address.
*
* @param netif the netif on which the router advertisement arrived
* @param prefix_opt a pointer to the prefix option data
* @param prefix_addr an aligned copy of the prefix address
*/
static void
nd6_process_autoconfig_prefix(struct netif *netif,
struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr)
{
ip6_addr_t ip6addr;
u32_t valid_life, pref_life;
u8_t addr_state;
s8_t i, free_idx;
/* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do
* the rest, starting with checks for (c) and (d) here. */
valid_life = lwip_htonl(prefix_opt->valid_lifetime);
pref_life = lwip_htonl(prefix_opt->preferred_lifetime);
if (pref_life > valid_life || prefix_opt->prefix_length != 64) {
return; /* silently ignore this prefix for autoconfiguration purposes */
}
/* If an autogenerated address already exists for this prefix, update its
* lifetimes. An address is considered autogenerated if 1) it is not static
* (i.e., manually assigned), and 2) there is an advertised autoconfiguration
* prefix for it (the one we are processing here). This does not necessarily
* exclude the possibility that the address was actually assigned by, say,
* DHCPv6. If that distinction becomes important in the future, more state
* must be kept. As explained elsewhere we also update lifetimes of tentative
* and duplicate addresses. Skip address slot 0 (the link-local address). */
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
addr_state = netif_ip6_addr_state(netif, i);
if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) &&
ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) {
/* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e).
* The valid lifetime will never drop to zero as a result of this. */
u32_t remaining_life = netif_ip6_addr_valid_life(netif, i);
if (valid_life > ND6_2HRS || valid_life > remaining_life) {
netif_ip6_addr_set_valid_life(netif, i, valid_life);
} else if (remaining_life > ND6_2HRS) {
netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS);
}
LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i));
/* Update the preferred lifetime. No bounds checks are needed here. In
* rare cases the advertisement may un-deprecate the address, though.
* Deprecation is left to the timer code where it is handled anyway. */
if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) {
netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
}
netif_ip6_addr_set_pref_life(netif, i, pref_life);
return; /* there should be at most one matching address */
}
}
/* No autogenerated address exists for this prefix yet. See if we can add a
* new one. However, if IPv6 autoconfiguration is administratively disabled,
* do not generate new addresses, but do keep updating lifetimes for existing
* addresses. Also, when adding new addresses, we must protect explicitly
* against a valid lifetime of zero, because again, we use that as a special
* value. The generated address would otherwise expire immediately anyway.
* Finally, the original link-local address must be usable at all. We start
* creating addresses even if the link-local address is still in tentative
* state though, and deal with the fallout of that upon DAD collision. */
addr_state = netif_ip6_addr_state(netif, 0);
if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC ||
ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) {
return;
}
/* Construct the new address that we intend to use, and then see if that
* address really does not exist. It might have been added manually, after
* all. As a side effect, find a free slot. Note that we cannot use
* netif_add_ip6_address() here, as it would return ERR_OK if the address
* already did exist, resulting in that address being given lifetimes. */
IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1],
netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]);
free_idx = 0;
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) {
return; /* formed address already exists */
}
} else if (free_idx == 0) {
free_idx = i;
}
}
if (free_idx == 0) {
return; /* no address slots available, try again on next advertisement */
}
/* Assign the new address to the interface. */
ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr);
netif_ip6_addr_set_valid_life(netif, free_idx, valid_life);
netif_ip6_addr_set_pref_life(netif, free_idx, pref_life);
netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE);
}
#endif /* LWIP_IPV6_AUTOCONFIG */
/**
* Process an incoming neighbor discovery message
*
@ -167,21 +307,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* If the target address matches this netif, it is a DAD response. */
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) &&
!ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) &&
ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) {
/* We are using a duplicate address. */
netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
#if LWIP_IPV6_AUTOCONFIG
/* Check to see if this address was autoconfigured. */
if (!ip6_addr_islinklocal(&target_address)) {
i = nd6_get_onlink_prefix(&target_address, inp);
if (i >= 0) {
/* Mark this prefix as duplicate, so that we don't use it
* to generate this address again. */
prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE;
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
nd6_duplicate_addr_detected(inp, i);
pbuf_free(p);
return;
@ -325,7 +454,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST);
if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) {
/* We shouldn't use this address either. */
netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
nd6_duplicate_addr_detected(inp, i);
}
}
}
@ -498,35 +627,38 @@ nd6_input(struct pbuf *p, struct netif *inp)
case ND6_OPTION_TYPE_PREFIX_INFO:
{
struct prefix_option *prefix_opt;
ip6_addr_t prefix_addr;
prefix_opt = (struct prefix_option *)buffer;
if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) &&
(prefix_opt->prefix_length == 64) &&
!ip6_addr_islinklocal(&(prefix_opt->prefix))) {
/* Add to on-link prefix list. */
s8_t prefix;
ip6_addr_t prefix_addr;
/* Get a memory-aligned copy of the prefix. */
ip6_addr_set(&prefix_addr, &(prefix_opt->prefix));
/* Get a memory-aligned copy of the prefix. */
ip6_addr_set(&prefix_addr, &(prefix_opt->prefix));
if (!ip6_addr_islinklocal(&prefix_addr)) {
if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) &&
(prefix_opt->prefix_length == 64)) {
/* Add to on-link prefix list. */
u32_t valid_life;
s8_t prefix;
/* find cache entry for this prefix. */
prefix = nd6_get_onlink_prefix(&prefix_addr, inp);
if (prefix < 0) {
/* Create a new cache entry. */
prefix = nd6_new_onlink_prefix(&prefix_addr, inp);
}
if (prefix >= 0) {
prefix_list[prefix].invalidation_timer = lwip_htonl(prefix_opt->valid_lifetime);
valid_life = lwip_htonl(prefix_opt->valid_lifetime);
#if LWIP_IPV6_AUTOCONFIG
if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
/* Mark prefix as autonomous, so that address autoconfiguration can take place.
* Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/
prefix_list[prefix].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS;
/* find cache entry for this prefix. */
prefix = nd6_get_onlink_prefix(&prefix_addr, inp);
if (prefix < 0 && valid_life > 0) {
/* Create a new cache entry. */
prefix = nd6_new_onlink_prefix(&prefix_addr, inp);
}
if (prefix >= 0) {
prefix_list[prefix].invalidation_timer = valid_life;
}
#endif /* LWIP_IPV6_AUTOCONFIG */
}
#if LWIP_IPV6_AUTOCONFIG
if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
/* Perform processing for autoconfiguration. */
nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr);
}
#endif /* LWIP_IPV6_AUTOCONFIG */
}
break;
@ -705,6 +837,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
* - Update neighbor reachability states
* - Update destination cache entries age
* - Update invalidation timers of default routers and on-link prefixes
* - Update lifetimes of our addresses
* - Perform duplicate address detection (DAD) for our addresses
* - Send router solicitations
*/
@ -796,81 +929,86 @@ nd6_tmr(void)
/* Process prefix entries. */
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
if (prefix_list[i].netif != NULL) {
if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) {
if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) {
/* Entry timed out, remove it */
prefix_list[i].invalidation_timer = 0;
#if LWIP_IPV6_AUTOCONFIG
/* If any addresses were configured with this prefix, remove them */
if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) {
s8_t j;
for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
if ((netif_ip6_addr_state(prefix_list[i].netif, j) != IP6_ADDR_INVALID) &&
ip6_addr_netcmp(&prefix_list[i].prefix, netif_ip6_addr(prefix_list[i].netif, j))) {
netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_INVALID);
prefix_list[i].flags = 0;
/* Exit loop. */
break;
}
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
prefix_list[i].netif = NULL;
prefix_list[i].flags = 0;
} else {
prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000;
#if LWIP_IPV6_AUTOCONFIG
/* Initiate address autoconfiguration for this prefix, if conditions are met. */
if (prefix_list[i].netif->ip6_autoconfig_enabled &&
(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) &&
!(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) {
s8_t j;
/* Try to get an address on this netif that is invalid.
* Skip 0 index (link-local address) */
for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) {
/* Generate an address using this prefix and interface ID from link-local address. */
netif_ip6_addr_set_parts(prefix_list[i].netif, j,
prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1],
netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]);
/* Mark it as tentative (DAD will be performed if configured). */
netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE);
/* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */
prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED;
/* Exit loop. */
break;
}
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
}
}
}
/* Process our own addresses, if DAD configured. */
/* Process our own addresses, updating address lifetimes and/or DAD state. */
for (netif = netif_list; netif != NULL; netif = netif->next) {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
u8_t addr_state = netif_ip6_addr_state(netif, i);
u8_t addr_state;
#if LWIP_IPV6_ADDRESS_LIFETIMES
/* Step 1: update address lifetimes (valid and preferred). */
addr_state = netif_ip6_addr_state(netif, i);
/* RFC 4862 is not entirely clear as to whether address lifetimes affect
* tentative addresses, and is even less clear as to what should happen
* with duplicate addresses. We choose to track and update lifetimes for
* both those types, although for different reasons:
* - for tentative addresses, the line of thought of Sec. 5.7 combined
* with the potentially long period that an address may be in tentative
* state (due to the interface being down) suggests that lifetimes
* should be independent of external factors which would include DAD;
* - for duplicate addresses, retiring them early could result in a new
* but unwanted attempt at marking them as valid, while retiring them
* late/never could clog up address slots on the netif.
* As a result, we may end up expiring addresses of either type here.
*/
if (!ip6_addr_isinvalid(addr_state) &&
!netif_ip6_addr_isstatic(netif, i)) {
u32_t life = netif_ip6_addr_valid_life(netif, i);
if (life <= ND6_TMR_INTERVAL / 1000) {
/* The address has expired. */
netif_ip6_addr_set_valid_life(netif, i, 0);
netif_ip6_addr_set_pref_life(netif, i, 0);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
} else {
if (!ip6_addr_life_isinfinite(life)) {
life -= ND6_TMR_INTERVAL / 1000;
LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC);
netif_ip6_addr_set_valid_life(netif, i, life);
}
/* The address is still here. Update the preferred lifetime too. */
life = netif_ip6_addr_pref_life(netif, i);
if (life <= ND6_TMR_INTERVAL / 1000) {
/* This case must also trigger if 'life' was already zero, so as to
* deal correctly with advertised preferred-lifetime reductions. */
netif_ip6_addr_set_pref_life(netif, i, 0);
if (addr_state == IP6_ADDR_PREFERRED)
netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED);
} else if (!ip6_addr_life_isinfinite(life)) {
life -= ND6_TMR_INTERVAL / 1000;
netif_ip6_addr_set_pref_life(netif, i, life);
}
}
}
/* The address state may now have changed, so reobtain it next. */
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
/* Step 2: update DAD state. */
addr_state = netif_ip6_addr_state(netif, i);
if (ip6_addr_istentative(addr_state)) {
if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
/* No NA received in response. Mark address as valid. */
netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
/* @todo implement preferred and valid lifetimes. */
/* No NA received in response. Mark address as valid. For dynamic
* addresses with an expired preferred lifetime, the state is set to
* deprecated right away. That should almost never happen, though. */
addr_state = IP6_ADDR_PREFERRED;
#if LWIP_IPV6_ADDRESS_LIFETIMES
if (!netif_ip6_addr_isstatic(netif, i) &&
netif_ip6_addr_pref_life(netif, i) == 0) {
addr_state = IP6_ADDR_DEPRECATED;
}
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
netif_ip6_addr_set_state(netif, i, addr_state);
} else if (netif->flags & NETIF_FLAG_UP) {
/* Send a NS for this address. */
nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
/* tentative: set next state by increasing by one */
netif_ip6_addr_set_state(netif, i, addr_state + 1);
/* @todo send max 1 NS per tmr call? enable return*/
/*return;*/
}
}
}
@ -880,7 +1018,8 @@ nd6_tmr(void)
/* Send router solicitation messages, if necessary. */
for (netif = netif_list; netif != NULL; netif = netif->next) {
if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP) &&
(!ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)))) {
!ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) &&
!ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) {
if (nd6_send_rs(netif) == ERR_OK) {
netif->rs_count--;
}
@ -1543,7 +1682,7 @@ nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif)
* @return the index on the prefix table, or -1 if not found
*/
static s8_t
nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif)
{
s8_t i;
@ -1567,7 +1706,7 @@ nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
* @return the index on the prefix table, or -1 if not created
*/
static s8_t
nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif)
{
s8_t i;
@ -1578,9 +1717,6 @@ nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
/* Found empty prefix entry. */
prefix_list[i].netif = netif;
ip6_addr_set(&(prefix_list[i].prefix), prefix);
#if LWIP_IPV6_AUTOCONFIG
prefix_list[i].flags = 0;
#endif /* LWIP_IPV6_AUTOCONFIG */
return i;
}
}
@ -2044,7 +2180,6 @@ nd6_cleanup_netif(struct netif *netif)
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
if (prefix_list[i].netif == netif) {
prefix_list[i].netif = NULL;
prefix_list[i].flags = 0;
}
}
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
@ -2080,8 +2215,8 @@ nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state)
/* Determine whether we were, and should be, a member of the solicited-node
* multicast group for this address. For tentative addresses, the group is
* not joined until the address enters the TENTATIVE_1 (or VALID) state. */
old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_TENTATIVE);
new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_TENTATIVE);
old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE);
new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE);
if (old_member != new_member) {
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]);

View File

@ -260,6 +260,10 @@ netif_add(struct netif *netif,
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip_addr_set_zero_ip6(&netif->ip6_addr[i]);
netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
#if LWIP_IPV6_ADDRESS_LIFETIMES
netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC;
netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC;
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
}
netif->output_ip6 = netif_null_output_ip6;
#endif /* LWIP_IPV6 */
@ -1136,8 +1140,9 @@ netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state)
}
/**
* Checks if a specific address is assigned to the netif and returns its
* index.
* Checks if a specific local address is present on the netif and returns its
* index. Depending on its state, it may or may not be assigned to the
* interface (as per RFC terminology).
*
* @param netif the netif to check
* @param ip6addr the IPv6 address to find

View File

@ -234,6 +234,7 @@ typedef struct ip6_addr ip6_addr_t;
#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */
#define IP6_ADDR_PREFERRED 0x30
#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */
#define IP6_ADDR_DUPLICATED 0x40 /* Failed DAD test, not valid */
#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */
@ -242,6 +243,14 @@ typedef struct ip6_addr ip6_addr_t;
#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
#define ip6_addr_isduplicated(addr_state) (addr_state == IP6_ADDR_DUPLICATED)
#if LWIP_IPV6_ADDRESS_LIFETIMES
#define IP6_ADDR_LIFE_STATIC (0)
#define IP6_ADDR_LIFE_INFINITE (0xffffffffUL)
#define ip6_addr_life_isstatic(addr_life) ((addr_life) == IP6_ADDR_LIFE_STATIC)
#define ip6_addr_life_isinfinite(addr_life) ((addr_life) == IP6_ADDR_LIFE_INFINITE)
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \
LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \

View File

@ -238,6 +238,13 @@ struct netif {
/** The state of each IPv6 address (Tentative, Preferred, etc).
* @see ip6_addr.h */
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#if LWIP_IPV6_ADDRESS_LIFETIMES
/** Remaining valid and preferred lifetime of each IPv6 address, in seconds.
* For valid lifetimes, the special value of IP6_ADDR_LIFE_STATIC (0)
* indicates the address is static and has no lifetimes. */
u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES];
u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
#endif /* LWIP_IPV6 */
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
@ -459,6 +466,20 @@ s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr);
void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit);
err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx);
#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0)
#if LWIP_IPV6_ADDRESS_LIFETIMES
#define netif_ip6_addr_valid_life(netif, i) \
(((netif) != NULL) ? ((netif)->ip6_addr_valid_life[i]) : IP6_ADDR_LIFE_STATIC)
#define netif_ip6_addr_set_valid_life(netif, i, secs) \
do { if (netif != NULL) { (netif)->ip6_addr_valid_life[i] = (secs); }} while (0)
#define netif_ip6_addr_pref_life(netif, i) \
(((netif) != NULL) ? ((netif)->ip6_addr_pref_life[i]) : IP6_ADDR_LIFE_STATIC)
#define netif_ip6_addr_set_pref_life(netif, i, secs) \
do { if (netif != NULL) { (netif)->ip6_addr_pref_life[i] = (secs); }} while (0)
#define netif_ip6_addr_isstatic(netif, i) \
(netif_ip6_addr_valid_life((netif), (i)) == IP6_ADDR_LIFE_STATIC)
#else /* !LWIP_IPV6_ADDRESS_LIFETIMES */
#define netif_ip6_addr_isstatic(netif, i) (1) /* all addresses are static */
#endif /* !LWIP_IPV6_ADDRESS_LIFETIMES */
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_HWADDRHINT

View File

@ -2198,6 +2198,17 @@
#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6)
#endif
/**
* LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each
* IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled
* otherwise, in which case the application may assign address lifetimes with
* the appropriate macros. Addresses with no lifetime are assumed to be static.
* If this option is disabled, all addresses are assumed to be static.
*/
#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__
#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG)
#endif
/**
* LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts.
*/

View File

@ -83,7 +83,7 @@ struct nd6_neighbor_cache_entry {
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time; /* in ms since value may originate from network packet */
u32_t reachable_time; /* in seconds */
u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */
u32_t probes_sent;
u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */
@ -100,18 +100,12 @@ struct nd6_destination_cache_entry {
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif *netif;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
u32_t invalidation_timer; /* in seconds */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry *neighbor_entry;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
u32_t invalidation_timer; /* in seconds */
u8_t flags;
};
@ -124,6 +118,8 @@ enum nd6_neighbor_cache_entry_state {
ND6_PROBE
};
#define ND6_2HRS 7200 /* two hours, expressed in number of seconds */
/* Router tables. */
/* @todo make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];