diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 92f952d093d..01a0ffc7b40 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -611,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); } +static void ndisc_send_unsol_na(struct net_device *dev) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + struct in6_addr mcaddr; + + idev = in6_dev_get(dev); + if (!idev) + return; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + addrconf_addr_solict_mult(&ifa->addr, &mcaddr); + ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, + /*router=*/ !!idev->cnf.forwarding, + /*solicited=*/ false, /*override=*/ true, + /*inc_opt=*/ true); + } + read_unlock_bh(&idev->lock); + + in6_dev_put(idev); +} + void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *solicit, const struct in6_addr *daddr, const struct in6_addr *saddr) @@ -945,9 +968,10 @@ static void ndisc_recv_na(struct sk_buff *skb) } ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { - if (ifp->flags & IFA_F_TENTATIVE) { - addrconf_dad_failure(ifp); - return; + if (skb->pkt_type != PACKET_LOOPBACK + && (ifp->flags & IFA_F_TENTATIVE)) { + addrconf_dad_failure(ifp); + return; } /* What should we make now? The advertisement is invalid, but ndisc specs say nothing @@ -1722,6 +1746,10 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, neigh_ifdown(&nd_tbl, dev); fib6_run_gc(~0UL, net); break; + case NETDEV_NOTIFY_PEERS: + case NETDEV_BONDING_FAILOVER: + ndisc_send_unsol_na(dev); + break; default: break; } |