diff options
| -rw-r--r-- | include/net/addrconf.h | 3 | ||||
| -rw-r--r-- | net/ipv6/addrconf.c | 19 | ||||
| -rw-r--r-- | net/ipv6/ndisc.c | 4 |
3 files changed, 23 insertions, 3 deletions
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index d13573bb879e..80456f72d70a 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
| @@ -62,6 +62,9 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg); | |||
| 62 | 62 | ||
| 63 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | 63 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, |
| 64 | const struct net_device *dev, int strict); | 64 | const struct net_device *dev, int strict); |
| 65 | int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, | ||
| 66 | const struct net_device *dev, int strict, | ||
| 67 | u32 banned_flags); | ||
| 65 | 68 | ||
| 66 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 69 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
| 67 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); | 70 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f7c8bbeb27b7..62900aee4c58 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -1519,15 +1519,30 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
| 1519 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | 1519 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, |
| 1520 | const struct net_device *dev, int strict) | 1520 | const struct net_device *dev, int strict) |
| 1521 | { | 1521 | { |
| 1522 | return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE); | ||
| 1523 | } | ||
| 1524 | EXPORT_SYMBOL(ipv6_chk_addr); | ||
| 1525 | |||
| 1526 | int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, | ||
| 1527 | const struct net_device *dev, int strict, | ||
| 1528 | u32 banned_flags) | ||
| 1529 | { | ||
| 1522 | struct inet6_ifaddr *ifp; | 1530 | struct inet6_ifaddr *ifp; |
| 1523 | unsigned int hash = inet6_addr_hash(addr); | 1531 | unsigned int hash = inet6_addr_hash(addr); |
| 1532 | u32 ifp_flags; | ||
| 1524 | 1533 | ||
| 1525 | rcu_read_lock_bh(); | 1534 | rcu_read_lock_bh(); |
| 1526 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { | 1535 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
| 1527 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1536 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1528 | continue; | 1537 | continue; |
| 1538 | /* Decouple optimistic from tentative for evaluation here. | ||
| 1539 | * Ban optimistic addresses explicitly, when required. | ||
| 1540 | */ | ||
| 1541 | ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC) | ||
| 1542 | ? (ifp->flags&~IFA_F_TENTATIVE) | ||
| 1543 | : ifp->flags; | ||
| 1529 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1544 | if (ipv6_addr_equal(&ifp->addr, addr) && |
| 1530 | !(ifp->flags&IFA_F_TENTATIVE) && | 1545 | !(ifp_flags&banned_flags) && |
| 1531 | (dev == NULL || ifp->idev->dev == dev || | 1546 | (dev == NULL || ifp->idev->dev == dev || |
| 1532 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { | 1547 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { |
| 1533 | rcu_read_unlock_bh(); | 1548 | rcu_read_unlock_bh(); |
| @@ -1538,7 +1553,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | |||
| 1538 | rcu_read_unlock_bh(); | 1553 | rcu_read_unlock_bh(); |
| 1539 | return 0; | 1554 | return 0; |
| 1540 | } | 1555 | } |
| 1541 | EXPORT_SYMBOL(ipv6_chk_addr); | 1556 | EXPORT_SYMBOL(ipv6_chk_addr_and_flags); |
| 1542 | 1557 | ||
| 1543 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | 1558 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, |
| 1544 | struct net_device *dev) | 1559 | struct net_device *dev) |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 682866777d53..113fc6cd5a0c 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -655,7 +655,9 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 655 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; | 655 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; |
| 656 | int probes = atomic_read(&neigh->probes); | 656 | int probes = atomic_read(&neigh->probes); |
| 657 | 657 | ||
| 658 | if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) | 658 | if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, |
| 659 | dev, 1, | ||
| 660 | IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) | ||
| 659 | saddr = &ipv6_hdr(skb)->saddr; | 661 | saddr = &ipv6_hdr(skb)->saddr; |
| 660 | probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); | 662 | probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); |
| 661 | if (probes < 0) { | 663 | if (probes < 0) { |
