diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 38 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 7 |
2 files changed, 22 insertions, 23 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index abe46a4228ce..4b6b720971b9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3189,6 +3189,22 @@ out: | |||
3189 | in6_ifa_put(ifp); | 3189 | in6_ifa_put(ifp); |
3190 | } | 3190 | } |
3191 | 3191 | ||
3192 | /* ifp->idev must be at least read locked */ | ||
3193 | static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp) | ||
3194 | { | ||
3195 | struct inet6_ifaddr *ifpiter; | ||
3196 | struct inet6_dev *idev = ifp->idev; | ||
3197 | |||
3198 | list_for_each_entry(ifpiter, &idev->addr_list, if_list) { | ||
3199 | if (ifp != ifpiter && ifpiter->scope == IFA_LINK && | ||
3200 | (ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE| | ||
3201 | IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) == | ||
3202 | IFA_F_PERMANENT) | ||
3203 | return false; | ||
3204 | } | ||
3205 | return true; | ||
3206 | } | ||
3207 | |||
3192 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | 3208 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp) |
3193 | { | 3209 | { |
3194 | struct net_device *dev = ifp->idev->dev; | 3210 | struct net_device *dev = ifp->idev->dev; |
@@ -3208,14 +3224,11 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
3208 | */ | 3224 | */ |
3209 | 3225 | ||
3210 | read_lock_bh(&ifp->idev->lock); | 3226 | read_lock_bh(&ifp->idev->lock); |
3211 | spin_lock(&ifp->lock); | 3227 | send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp); |
3212 | send_mld = ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL && | ||
3213 | ifp->idev->valid_ll_addr_cnt == 1; | ||
3214 | send_rs = send_mld && | 3228 | send_rs = send_mld && |
3215 | ipv6_accept_ra(ifp->idev) && | 3229 | ipv6_accept_ra(ifp->idev) && |
3216 | ifp->idev->cnf.rtr_solicits > 0 && | 3230 | ifp->idev->cnf.rtr_solicits > 0 && |
3217 | (dev->flags&IFF_LOOPBACK) == 0; | 3231 | (dev->flags&IFF_LOOPBACK) == 0; |
3218 | spin_unlock(&ifp->lock); | ||
3219 | read_unlock_bh(&ifp->idev->lock); | 3232 | read_unlock_bh(&ifp->idev->lock); |
3220 | 3233 | ||
3221 | /* While dad is in progress mld report's source address is in6_addrany. | 3234 | /* While dad is in progress mld report's source address is in6_addrany. |
@@ -4512,19 +4525,6 @@ errout: | |||
4512 | rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); | 4525 | rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); |
4513 | } | 4526 | } |
4514 | 4527 | ||
4515 | static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count) | ||
4516 | { | ||
4517 | write_lock_bh(&ifp->idev->lock); | ||
4518 | spin_lock(&ifp->lock); | ||
4519 | if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC| | ||
4520 | IFA_F_DADFAILED)) == IFA_F_PERMANENT) && | ||
4521 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) | ||
4522 | ifp->idev->valid_ll_addr_cnt += count; | ||
4523 | WARN_ON(ifp->idev->valid_ll_addr_cnt < 0); | ||
4524 | spin_unlock(&ifp->lock); | ||
4525 | write_unlock_bh(&ifp->idev->lock); | ||
4526 | } | ||
4527 | |||
4528 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 4528 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
4529 | { | 4529 | { |
4530 | struct net *net = dev_net(ifp->idev->dev); | 4530 | struct net *net = dev_net(ifp->idev->dev); |
@@ -4533,8 +4533,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4533 | 4533 | ||
4534 | switch (event) { | 4534 | switch (event) { |
4535 | case RTM_NEWADDR: | 4535 | case RTM_NEWADDR: |
4536 | update_valid_ll_addr_cnt(ifp, 1); | ||
4537 | |||
4538 | /* | 4536 | /* |
4539 | * If the address was optimistic | 4537 | * If the address was optimistic |
4540 | * we inserted the route at the start of | 4538 | * we inserted the route at the start of |
@@ -4550,8 +4548,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4550 | ifp->idev->dev, 0, 0); | 4548 | ifp->idev->dev, 0, 0); |
4551 | break; | 4549 | break; |
4552 | case RTM_DELADDR: | 4550 | case RTM_DELADDR: |
4553 | update_valid_ll_addr_cnt(ifp, -1); | ||
4554 | |||
4555 | if (ifp->idev->cnf.forwarding) | 4551 | if (ifp->idev->cnf.forwarding) |
4556 | addrconf_leave_anycast(ifp); | 4552 | addrconf_leave_anycast(ifp); |
4557 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 4553 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index f365310bfcca..0eb4038a4d63 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | |||
141 | static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, | 141 | static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, |
142 | struct mr6_table **mrt) | 142 | struct mr6_table **mrt) |
143 | { | 143 | { |
144 | struct ip6mr_result res; | ||
145 | struct fib_lookup_arg arg = { .result = &res, }; | ||
146 | int err; | 144 | int err; |
145 | struct ip6mr_result res; | ||
146 | struct fib_lookup_arg arg = { | ||
147 | .result = &res, | ||
148 | .flags = FIB_LOOKUP_NOREF, | ||
149 | }; | ||
147 | 150 | ||
148 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, | 151 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, |
149 | flowi6_to_flowi(flp6), 0, &arg); | 152 | flowi6_to_flowi(flp6), 0, &arg); |