diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 116 |
1 files changed, 40 insertions, 76 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1220e2c7831e..a8218bc1806a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -40,6 +40,7 @@ | |||
40 | 40 | ||
41 | #include <linux/errno.h> | 41 | #include <linux/errno.h> |
42 | #include <linux/types.h> | 42 | #include <linux/types.h> |
43 | #include <linux/kernel.h> | ||
43 | #include <linux/socket.h> | 44 | #include <linux/socket.h> |
44 | #include <linux/sockios.h> | 45 | #include <linux/sockios.h> |
45 | #include <linux/net.h> | 46 | #include <linux/net.h> |
@@ -590,6 +591,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
590 | { | 591 | { |
591 | struct inet6_ifaddr *ifa = NULL; | 592 | struct inet6_ifaddr *ifa = NULL; |
592 | struct rt6_info *rt; | 593 | struct rt6_info *rt; |
594 | struct net *net = dev_net(idev->dev); | ||
593 | int hash; | 595 | int hash; |
594 | int err = 0; | 596 | int err = 0; |
595 | int addr_type = ipv6_addr_type(addr); | 597 | int addr_type = ipv6_addr_type(addr); |
@@ -606,6 +608,11 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
606 | goto out2; | 608 | goto out2; |
607 | } | 609 | } |
608 | 610 | ||
611 | if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) { | ||
612 | err = -EACCES; | ||
613 | goto out2; | ||
614 | } | ||
615 | |||
609 | write_lock(&addrconf_hash_lock); | 616 | write_lock(&addrconf_hash_lock); |
610 | 617 | ||
611 | /* Ignore adding duplicate addresses on an interface */ | 618 | /* Ignore adding duplicate addresses on an interface */ |
@@ -1209,16 +1216,12 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, | |||
1209 | } | 1216 | } |
1210 | break; | 1217 | break; |
1211 | } else if (minihiscore < miniscore) { | 1218 | } else if (minihiscore < miniscore) { |
1212 | struct ipv6_saddr_score *tmp; | ||
1213 | |||
1214 | if (hiscore->ifa) | 1219 | if (hiscore->ifa) |
1215 | in6_ifa_put(hiscore->ifa); | 1220 | in6_ifa_put(hiscore->ifa); |
1216 | 1221 | ||
1217 | in6_ifa_hold(score->ifa); | 1222 | in6_ifa_hold(score->ifa); |
1218 | 1223 | ||
1219 | tmp = hiscore; | 1224 | swap(hiscore, score); |
1220 | hiscore = score; | ||
1221 | score = tmp; | ||
1222 | 1225 | ||
1223 | /* restore our iterator */ | 1226 | /* restore our iterator */ |
1224 | score->ifa = hiscore->ifa; | 1227 | score->ifa = hiscore->ifa; |
@@ -1367,40 +1370,6 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add | |||
1367 | return ifp; | 1370 | return ifp; |
1368 | } | 1371 | } |
1369 | 1372 | ||
1370 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | ||
1371 | { | ||
1372 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | ||
1373 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | ||
1374 | __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; | ||
1375 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | ||
1376 | int sk_ipv6only = ipv6_only_sock(sk); | ||
1377 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | ||
1378 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); | ||
1379 | int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; | ||
1380 | |||
1381 | if (!sk2_rcv_saddr && !sk_ipv6only) | ||
1382 | return 1; | ||
1383 | |||
1384 | if (addr_type2 == IPV6_ADDR_ANY && | ||
1385 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) | ||
1386 | return 1; | ||
1387 | |||
1388 | if (addr_type == IPV6_ADDR_ANY && | ||
1389 | !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) | ||
1390 | return 1; | ||
1391 | |||
1392 | if (sk2_rcv_saddr6 && | ||
1393 | ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) | ||
1394 | return 1; | ||
1395 | |||
1396 | if (addr_type == IPV6_ADDR_MAPPED && | ||
1397 | !sk2_ipv6only && | ||
1398 | (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) | ||
1399 | return 1; | ||
1400 | |||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | /* Gets referenced address, destroys ifaddr */ | 1373 | /* Gets referenced address, destroys ifaddr */ |
1405 | 1374 | ||
1406 | static void addrconf_dad_stop(struct inet6_ifaddr *ifp) | 1375 | static void addrconf_dad_stop(struct inet6_ifaddr *ifp) |
@@ -1433,6 +1402,11 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp) | |||
1433 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1402 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
1434 | { | 1403 | { |
1435 | struct inet6_dev *idev = ifp->idev; | 1404 | struct inet6_dev *idev = ifp->idev; |
1405 | |||
1406 | if (net_ratelimit()) | ||
1407 | printk(KERN_INFO "%s: IPv6 duplicate address detected!\n", | ||
1408 | ifp->idev->dev->name); | ||
1409 | |||
1436 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | 1410 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { |
1437 | struct in6_addr addr; | 1411 | struct in6_addr addr; |
1438 | 1412 | ||
@@ -1443,11 +1417,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1443 | ipv6_addr_equal(&ifp->addr, &addr)) { | 1417 | ipv6_addr_equal(&ifp->addr, &addr)) { |
1444 | /* DAD failed for link-local based on MAC address */ | 1418 | /* DAD failed for link-local based on MAC address */ |
1445 | idev->cnf.disable_ipv6 = 1; | 1419 | idev->cnf.disable_ipv6 = 1; |
1420 | |||
1421 | printk(KERN_INFO "%s: IPv6 being disabled!\n", | ||
1422 | ifp->idev->dev->name); | ||
1446 | } | 1423 | } |
1447 | } | 1424 | } |
1448 | 1425 | ||
1449 | if (net_ratelimit()) | ||
1450 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | ||
1451 | addrconf_dad_stop(ifp); | 1426 | addrconf_dad_stop(ifp); |
1452 | } | 1427 | } |
1453 | 1428 | ||
@@ -2227,10 +2202,24 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg) | |||
2227 | return err; | 2202 | return err; |
2228 | } | 2203 | } |
2229 | 2204 | ||
2205 | static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | ||
2206 | int plen, int scope) | ||
2207 | { | ||
2208 | struct inet6_ifaddr *ifp; | ||
2209 | |||
2210 | ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT); | ||
2211 | if (!IS_ERR(ifp)) { | ||
2212 | spin_lock_bh(&ifp->lock); | ||
2213 | ifp->flags &= ~IFA_F_TENTATIVE; | ||
2214 | spin_unlock_bh(&ifp->lock); | ||
2215 | ipv6_ifa_notify(RTM_NEWADDR, ifp); | ||
2216 | in6_ifa_put(ifp); | ||
2217 | } | ||
2218 | } | ||
2219 | |||
2230 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2220 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) |
2231 | static void sit_add_v4_addrs(struct inet6_dev *idev) | 2221 | static void sit_add_v4_addrs(struct inet6_dev *idev) |
2232 | { | 2222 | { |
2233 | struct inet6_ifaddr * ifp; | ||
2234 | struct in6_addr addr; | 2223 | struct in6_addr addr; |
2235 | struct net_device *dev; | 2224 | struct net_device *dev; |
2236 | struct net *net = dev_net(idev->dev); | 2225 | struct net *net = dev_net(idev->dev); |
@@ -2249,14 +2238,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) | |||
2249 | } | 2238 | } |
2250 | 2239 | ||
2251 | if (addr.s6_addr32[3]) { | 2240 | if (addr.s6_addr32[3]) { |
2252 | ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT); | 2241 | add_addr(idev, &addr, 128, scope); |
2253 | if (!IS_ERR(ifp)) { | ||
2254 | spin_lock_bh(&ifp->lock); | ||
2255 | ifp->flags &= ~IFA_F_TENTATIVE; | ||
2256 | spin_unlock_bh(&ifp->lock); | ||
2257 | ipv6_ifa_notify(RTM_NEWADDR, ifp); | ||
2258 | in6_ifa_put(ifp); | ||
2259 | } | ||
2260 | return; | 2242 | return; |
2261 | } | 2243 | } |
2262 | 2244 | ||
@@ -2284,15 +2266,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) | |||
2284 | else | 2266 | else |
2285 | plen = 96; | 2267 | plen = 96; |
2286 | 2268 | ||
2287 | ifp = ipv6_add_addr(idev, &addr, plen, flag, | 2269 | add_addr(idev, &addr, plen, flag); |
2288 | IFA_F_PERMANENT); | ||
2289 | if (!IS_ERR(ifp)) { | ||
2290 | spin_lock_bh(&ifp->lock); | ||
2291 | ifp->flags &= ~IFA_F_TENTATIVE; | ||
2292 | spin_unlock_bh(&ifp->lock); | ||
2293 | ipv6_ifa_notify(RTM_NEWADDR, ifp); | ||
2294 | in6_ifa_put(ifp); | ||
2295 | } | ||
2296 | } | 2270 | } |
2297 | } | 2271 | } |
2298 | } | 2272 | } |
@@ -2302,7 +2276,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) | |||
2302 | static void init_loopback(struct net_device *dev) | 2276 | static void init_loopback(struct net_device *dev) |
2303 | { | 2277 | { |
2304 | struct inet6_dev *idev; | 2278 | struct inet6_dev *idev; |
2305 | struct inet6_ifaddr * ifp; | ||
2306 | 2279 | ||
2307 | /* ::1 */ | 2280 | /* ::1 */ |
2308 | 2281 | ||
@@ -2313,14 +2286,7 @@ static void init_loopback(struct net_device *dev) | |||
2313 | return; | 2286 | return; |
2314 | } | 2287 | } |
2315 | 2288 | ||
2316 | ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT); | 2289 | add_addr(idev, &in6addr_loopback, 128, IFA_HOST); |
2317 | if (!IS_ERR(ifp)) { | ||
2318 | spin_lock_bh(&ifp->lock); | ||
2319 | ifp->flags &= ~IFA_F_TENTATIVE; | ||
2320 | spin_unlock_bh(&ifp->lock); | ||
2321 | ipv6_ifa_notify(RTM_NEWADDR, ifp); | ||
2322 | in6_ifa_put(ifp); | ||
2323 | } | ||
2324 | } | 2290 | } |
2325 | 2291 | ||
2326 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) | 2292 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) |
@@ -2832,11 +2798,6 @@ static void addrconf_dad_timer(unsigned long data) | |||
2832 | read_unlock_bh(&idev->lock); | 2798 | read_unlock_bh(&idev->lock); |
2833 | goto out; | 2799 | goto out; |
2834 | } | 2800 | } |
2835 | if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) { | ||
2836 | read_unlock_bh(&idev->lock); | ||
2837 | addrconf_dad_failure(ifp); | ||
2838 | return; | ||
2839 | } | ||
2840 | spin_lock_bh(&ifp->lock); | 2801 | spin_lock_bh(&ifp->lock); |
2841 | if (ifp->probes == 0) { | 2802 | if (ifp->probes == 0) { |
2842 | /* | 2803 | /* |
@@ -3647,7 +3608,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | |||
3647 | kfree_skb(skb); | 3608 | kfree_skb(skb); |
3648 | goto errout; | 3609 | goto errout; |
3649 | } | 3610 | } |
3650 | err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 3611 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3612 | return; | ||
3651 | errout: | 3613 | errout: |
3652 | if (err < 0) | 3614 | if (err < 0) |
3653 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); | 3615 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); |
@@ -3858,7 +3820,8 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | |||
3858 | kfree_skb(skb); | 3820 | kfree_skb(skb); |
3859 | goto errout; | 3821 | goto errout; |
3860 | } | 3822 | } |
3861 | err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 3823 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3824 | return; | ||
3862 | errout: | 3825 | errout: |
3863 | if (err < 0) | 3826 | if (err < 0) |
3864 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); | 3827 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); |
@@ -3928,7 +3891,8 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |||
3928 | kfree_skb(skb); | 3891 | kfree_skb(skb); |
3929 | goto errout; | 3892 | goto errout; |
3930 | } | 3893 | } |
3931 | err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); | 3894 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); |
3895 | return; | ||
3932 | errout: | 3896 | errout: |
3933 | if (err < 0) | 3897 | if (err < 0) |
3934 | rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); | 3898 | rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); |