|
@@ -3189,6 +3189,22 @@ out:
|
|
in6_ifa_put(ifp);
|
|
in6_ifa_put(ifp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* ifp->idev must be at least read locked */
|
|
|
|
+static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp)
|
|
|
|
+{
|
|
|
|
+ struct inet6_ifaddr *ifpiter;
|
|
|
|
+ struct inet6_dev *idev = ifp->idev;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(ifpiter, &idev->addr_list, if_list) {
|
|
|
|
+ if (ifp != ifpiter && ifpiter->scope == IFA_LINK &&
|
|
|
|
+ (ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|
|
|
|
|
+ IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) ==
|
|
|
|
+ IFA_F_PERMANENT)
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
|
|
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
|
|
{
|
|
{
|
|
struct net_device *dev = ifp->idev->dev;
|
|
struct net_device *dev = ifp->idev->dev;
|
|
@@ -3208,14 +3224,11 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
|
|
*/
|
|
*/
|
|
|
|
|
|
read_lock_bh(&ifp->idev->lock);
|
|
read_lock_bh(&ifp->idev->lock);
|
|
- spin_lock(&ifp->lock);
|
|
|
|
- send_mld = ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL &&
|
|
|
|
- ifp->idev->valid_ll_addr_cnt == 1;
|
|
|
|
|
|
+ send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp);
|
|
send_rs = send_mld &&
|
|
send_rs = send_mld &&
|
|
ipv6_accept_ra(ifp->idev) &&
|
|
ipv6_accept_ra(ifp->idev) &&
|
|
ifp->idev->cnf.rtr_solicits > 0 &&
|
|
ifp->idev->cnf.rtr_solicits > 0 &&
|
|
(dev->flags&IFF_LOOPBACK) == 0;
|
|
(dev->flags&IFF_LOOPBACK) == 0;
|
|
- spin_unlock(&ifp->lock);
|
|
|
|
read_unlock_bh(&ifp->idev->lock);
|
|
read_unlock_bh(&ifp->idev->lock);
|
|
|
|
|
|
/* While dad is in progress mld report's source address is in6_addrany.
|
|
/* While dad is in progress mld report's source address is in6_addrany.
|
|
@@ -4512,19 +4525,6 @@ errout:
|
|
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
|
|
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
|
|
}
|
|
}
|
|
|
|
|
|
-static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count)
|
|
|
|
-{
|
|
|
|
- write_lock_bh(&ifp->idev->lock);
|
|
|
|
- spin_lock(&ifp->lock);
|
|
|
|
- if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|
|
|
|
|
- IFA_F_DADFAILED)) == IFA_F_PERMANENT) &&
|
|
|
|
- (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL))
|
|
|
|
- ifp->idev->valid_ll_addr_cnt += count;
|
|
|
|
- WARN_ON(ifp->idev->valid_ll_addr_cnt < 0);
|
|
|
|
- spin_unlock(&ifp->lock);
|
|
|
|
- write_unlock_bh(&ifp->idev->lock);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
{
|
|
{
|
|
struct net *net = dev_net(ifp->idev->dev);
|
|
struct net *net = dev_net(ifp->idev->dev);
|
|
@@ -4533,8 +4533,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
|
|
|
|
switch (event) {
|
|
switch (event) {
|
|
case RTM_NEWADDR:
|
|
case RTM_NEWADDR:
|
|
- update_valid_ll_addr_cnt(ifp, 1);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* If the address was optimistic
|
|
* If the address was optimistic
|
|
* we inserted the route at the start of
|
|
* we inserted the route at the start of
|
|
@@ -4550,8 +4548,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
ifp->idev->dev, 0, 0);
|
|
ifp->idev->dev, 0, 0);
|
|
break;
|
|
break;
|
|
case RTM_DELADDR:
|
|
case RTM_DELADDR:
|
|
- update_valid_ll_addr_cnt(ifp, -1);
|
|
|
|
-
|
|
|
|
if (ifp->idev->cnf.forwarding)
|
|
if (ifp->idev->cnf.forwarding)
|
|
addrconf_leave_anycast(ifp);
|
|
addrconf_leave_anycast(ifp);
|
|
addrconf_leave_solict(ifp->idev, &ifp->addr);
|
|
addrconf_leave_solict(ifp->idev, &ifp->addr);
|