aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 0677b9732d56..6fd4bbdc444f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1856,22 +1856,37 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
}
EXPORT_SYMBOL(ipv6_chk_addr);
+/* device argument is used to find the L3 domain of interest. If
+ * skip_dev_check is set, then the ifp device is not checked against
+ * the passed in dev argument. So the 2 cases for addresses checks are:
+ * 1. does the address exist in the L3 domain that dev is part of
+ * (skip_dev_check = true), or
+ *
+ * 2. does the address exist on the specific device
+ * (skip_dev_check = false)
+ */
int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, bool skip_dev_check,
int strict, u32 banned_flags)
{
unsigned int hash = inet6_addr_hash(net, addr);
+ const struct net_device *l3mdev;
struct inet6_ifaddr *ifp;
u32 ifp_flags;
rcu_read_lock();
+ l3mdev = l3mdev_master_dev_rcu(dev);
if (skip_dev_check)
dev = NULL;
hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
+
+ if (l3mdev_master_dev_rcu(ifp->idev->dev) != l3mdev)
+ continue;
+
/* Decouple optimistic from tentative for evaluation here.
* Ban optimistic addresses explicitly, when required.
*/