From 71810d041524b4d296c0ba2b52f46165928110af Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Fri, 16 Dec 2016 21:26:32 +0000 Subject: [PATCH] ipv6: adjust MLD membership on address state changes If MLD support is enabled, each locally assigned IPv6 address in the appropriate state must be a member of the solicited-node multicast group corresponding to that address. Ensure that this is always the case by (re-)deciding on the membership upon every address state change. By doing so, this patch enforces that user-initiated state changes to addresses (e.g., deletion) never cause a desynchronization with the corresponding solicited-node multicast group membership, thereby making such user-initiated state changes simpler and safer. --- src/core/ipv6/nd6.c | 47 ++++++++++++++++++++++++++++++------------ src/core/netif.c | 7 +++++++ src/include/lwip/nd6.h | 3 +++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index ca7d8e91..23cbf5f3 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -171,12 +171,6 @@ nd6_input(struct pbuf *p, struct netif *inp) /* We are using a duplicate address. */ netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); -#if LWIP_IPV6_MLD - /* Leave solicited node multicast group. */ - ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); - mld6_leavegroup_netif(inp, &multicast_address); -#endif /* LWIP_IPV6_MLD */ - #if LWIP_IPV6_AUTOCONFIG /* Check to see if this address was autoconfigured. */ if (!ip6_addr_islinklocal(&target_address)) { @@ -871,13 +865,6 @@ nd6_tmr(void) netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); /* @todo implement preferred and valid lifetimes. */ } else if (netif->flags & NETIF_FLAG_UP) { -#if LWIP_IPV6_MLD - if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) == 0) { - /* Join solicited node multicast group. */ - ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); - mld6_joingroup_netif(netif, &multicast_address); - } -#endif /* LWIP_IPV6_MLD */ /* 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 */ @@ -2074,4 +2061,38 @@ nd6_cleanup_netif(struct netif *netif) } } +#if LWIP_IPV6_MLD +/** + * The state of a local IPv6 address entry is about to change. If needed, join + * or leave the solicited-node multicast group for the address. + * + * @param netif The netif that owns the address. + * @param addr_idx The index of the address. + * @param new_state The new (IP6_ADDR_) state for the address. + */ +void +nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) +{ + u8_t old_state, old_member, new_member; + + old_state = netif_ip6_addr_state(netif, addr_idx); + + /* 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); + + if (old_member != new_member) { + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); + + if (new_member) { + mld6_joingroup_netif(netif, &multicast_address); + } else { + mld6_leavegroup_netif(netif, &multicast_address); + } + } +} +#endif /* LWIP_IPV6_MLD */ + #endif /* LWIP_IPV6 */ diff --git a/src/core/netif.c b/src/core/netif.c index 1d3de0ff..428b1484 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -1096,6 +1096,13 @@ netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state) u8_t new_valid = state & IP6_ADDR_VALID; LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n")); +#if LWIP_IPV6_MLD + /* Reevaluate solicited-node multicast group membership. */ + if (netif->flags & NETIF_FLAG_MLD6) { + nd6_adjust_mld_membership(netif, addr_idx, state); + } +#endif /* LWIP_IPV6_MLD */ + if (old_valid && !new_valid) { /* address about to be removed by setting invalid */ #if LWIP_TCP diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index 817dfb9e..8204fa4c 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -71,6 +71,9 @@ u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); void nd6_reachability_hint(const ip6_addr_t *ip6addr); #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ void nd6_cleanup_netif(struct netif *netif); +#if LWIP_IPV6_MLD +void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state); +#endif /* LWIP_IPV6_MLD */ #ifdef __cplusplus }