|
@@ -1518,16 +1518,31 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
|
|
|
|
|
|
int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
|
|
|
const struct net_device *dev, int strict)
|
|
|
+{
|
|
|
+ return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(ipv6_chk_addr);
|
|
|
+
|
|
|
+int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
|
|
|
+ const struct net_device *dev, int strict,
|
|
|
+ u32 banned_flags)
|
|
|
{
|
|
|
struct inet6_ifaddr *ifp;
|
|
|
unsigned int hash = inet6_addr_hash(addr);
|
|
|
+ u32 ifp_flags;
|
|
|
|
|
|
rcu_read_lock_bh();
|
|
|
hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
|
|
|
if (!net_eq(dev_net(ifp->idev->dev), net))
|
|
|
continue;
|
|
|
+ /* Decouple optimistic from tentative for evaluation here.
|
|
|
+ * Ban optimistic addresses explicitly, when required.
|
|
|
+ */
|
|
|
+ ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC)
|
|
|
+ ? (ifp->flags&~IFA_F_TENTATIVE)
|
|
|
+ : ifp->flags;
|
|
|
if (ipv6_addr_equal(&ifp->addr, addr) &&
|
|
|
- !(ifp->flags&IFA_F_TENTATIVE) &&
|
|
|
+ !(ifp_flags&banned_flags) &&
|
|
|
(dev == NULL || ifp->idev->dev == dev ||
|
|
|
!(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
|
|
|
rcu_read_unlock_bh();
|
|
@@ -1538,7 +1553,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
|
|
|
rcu_read_unlock_bh();
|
|
|
return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(ipv6_chk_addr);
|
|
|
+EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
|
|
|
|
|
|
static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
|
|
|
struct net_device *dev)
|