diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 59 |
1 files changed, 28 insertions, 31 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1b5d8cb9b123..f2c7e615f902 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -110,10 +110,6 @@ static inline u32 cstamp_delta(unsigned long cstamp) | |||
110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | 110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; |
111 | } | 111 | } |
112 | 112 | ||
113 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | ||
114 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | ||
115 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | ||
116 | |||
117 | #ifdef CONFIG_SYSCTL | 113 | #ifdef CONFIG_SYSCTL |
118 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 114 | static void addrconf_sysctl_register(struct inet6_dev *idev); |
119 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 115 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); |
@@ -248,6 +244,9 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |||
248 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | 244 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; |
249 | const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | 245 | const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
250 | const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; | 246 | const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; |
247 | const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; | ||
248 | const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; | ||
249 | const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; | ||
251 | 250 | ||
252 | /* Check if a valid qdisc is available */ | 251 | /* Check if a valid qdisc is available */ |
253 | static inline bool addrconf_qdisc_ok(const struct net_device *dev) | 252 | static inline bool addrconf_qdisc_ok(const struct net_device *dev) |
@@ -432,6 +431,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
432 | /* protected by rtnl_lock */ | 431 | /* protected by rtnl_lock */ |
433 | rcu_assign_pointer(dev->ip6_ptr, ndev); | 432 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
434 | 433 | ||
434 | /* Join interface-local all-node multicast group */ | ||
435 | ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes); | ||
436 | |||
435 | /* Join all-node multicast group */ | 437 | /* Join all-node multicast group */ |
436 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); | 438 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); |
437 | 439 | ||
@@ -615,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
615 | if (idev->cnf.forwarding) | 617 | if (idev->cnf.forwarding) |
616 | dev_disable_lro(dev); | 618 | dev_disable_lro(dev); |
617 | if (dev->flags & IFF_MULTICAST) { | 619 | if (dev->flags & IFF_MULTICAST) { |
618 | if (idev->cnf.forwarding) | 620 | if (idev->cnf.forwarding) { |
619 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); | 621 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); |
620 | else | 622 | ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters); |
623 | ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters); | ||
624 | } else { | ||
621 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); | 625 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); |
626 | ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters); | ||
627 | ipv6_dev_mc_dec(dev, &in6addr_sitelocal_allrouters); | ||
628 | } | ||
622 | } | 629 | } |
623 | 630 | ||
624 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 631 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
@@ -1051,7 +1058,7 @@ retry: | |||
1051 | ipv6_add_addr(idev, &addr, tmp_plen, | 1058 | ipv6_add_addr(idev, &addr, tmp_plen, |
1052 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, | 1059 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, |
1053 | addr_flags) : NULL; | 1060 | addr_flags) : NULL; |
1054 | if (!ift || IS_ERR(ift)) { | 1061 | if (IS_ERR_OR_NULL(ift)) { |
1055 | in6_ifa_put(ifp); | 1062 | in6_ifa_put(ifp); |
1056 | in6_dev_put(idev); | 1063 | in6_dev_put(idev); |
1057 | pr_info("%s: retry temporary address regeneration\n", __func__); | 1064 | pr_info("%s: retry temporary address regeneration\n", __func__); |
@@ -1412,11 +1419,10 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | |||
1412 | struct net_device *dev, int strict) | 1419 | struct net_device *dev, int strict) |
1413 | { | 1420 | { |
1414 | struct inet6_ifaddr *ifp; | 1421 | struct inet6_ifaddr *ifp; |
1415 | struct hlist_node *node; | ||
1416 | unsigned int hash = inet6_addr_hash(addr); | 1422 | unsigned int hash = inet6_addr_hash(addr); |
1417 | 1423 | ||
1418 | rcu_read_lock_bh(); | 1424 | rcu_read_lock_bh(); |
1419 | hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1425 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
1420 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1426 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1421 | continue; | 1427 | continue; |
1422 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1428 | if (ipv6_addr_equal(&ifp->addr, addr) && |
@@ -1438,9 +1444,8 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | |||
1438 | { | 1444 | { |
1439 | unsigned int hash = inet6_addr_hash(addr); | 1445 | unsigned int hash = inet6_addr_hash(addr); |
1440 | struct inet6_ifaddr *ifp; | 1446 | struct inet6_ifaddr *ifp; |
1441 | struct hlist_node *node; | ||
1442 | 1447 | ||
1443 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1448 | hlist_for_each_entry(ifp, &inet6_addr_lst[hash], addr_lst) { |
1444 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1449 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1445 | continue; | 1450 | continue; |
1446 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1451 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
@@ -1480,10 +1485,9 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add | |||
1480 | { | 1485 | { |
1481 | struct inet6_ifaddr *ifp, *result = NULL; | 1486 | struct inet6_ifaddr *ifp, *result = NULL; |
1482 | unsigned int hash = inet6_addr_hash(addr); | 1487 | unsigned int hash = inet6_addr_hash(addr); |
1483 | struct hlist_node *node; | ||
1484 | 1488 | ||
1485 | rcu_read_lock_bh(); | 1489 | rcu_read_lock_bh(); |
1486 | hlist_for_each_entry_rcu_bh(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1490 | hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { |
1487 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1491 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1488 | continue; | 1492 | continue; |
1489 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1493 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
@@ -2080,7 +2084,7 @@ ok: | |||
2080 | addr_type&IPV6_ADDR_SCOPE_MASK, | 2084 | addr_type&IPV6_ADDR_SCOPE_MASK, |
2081 | addr_flags); | 2085 | addr_flags); |
2082 | 2086 | ||
2083 | if (!ifp || IS_ERR(ifp)) { | 2087 | if (IS_ERR_OR_NULL(ifp)) { |
2084 | in6_dev_put(in6_dev); | 2088 | in6_dev_put(in6_dev); |
2085 | return; | 2089 | return; |
2086 | } | 2090 | } |
@@ -2900,11 +2904,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2900 | /* Step 2: clear hash table */ | 2904 | /* Step 2: clear hash table */ |
2901 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | 2905 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
2902 | struct hlist_head *h = &inet6_addr_lst[i]; | 2906 | struct hlist_head *h = &inet6_addr_lst[i]; |
2903 | struct hlist_node *n; | ||
2904 | 2907 | ||
2905 | spin_lock_bh(&addrconf_hash_lock); | 2908 | spin_lock_bh(&addrconf_hash_lock); |
2906 | restart: | 2909 | restart: |
2907 | hlist_for_each_entry_rcu(ifa, n, h, addr_lst) { | 2910 | hlist_for_each_entry_rcu(ifa, h, addr_lst) { |
2908 | if (ifa->idev == idev) { | 2911 | if (ifa->idev == idev) { |
2909 | hlist_del_init_rcu(&ifa->addr_lst); | 2912 | hlist_del_init_rcu(&ifa->addr_lst); |
2910 | addrconf_del_timer(ifa); | 2913 | addrconf_del_timer(ifa); |
@@ -3211,8 +3214,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos) | |||
3211 | } | 3214 | } |
3212 | 3215 | ||
3213 | for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { | 3216 | for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { |
3214 | struct hlist_node *n; | 3217 | hlist_for_each_entry_rcu_bh(ifa, &inet6_addr_lst[state->bucket], |
3215 | hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], | ||
3216 | addr_lst) { | 3218 | addr_lst) { |
3217 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3219 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3218 | continue; | 3220 | continue; |
@@ -3237,9 +3239,8 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, | |||
3237 | { | 3239 | { |
3238 | struct if6_iter_state *state = seq->private; | 3240 | struct if6_iter_state *state = seq->private; |
3239 | struct net *net = seq_file_net(seq); | 3241 | struct net *net = seq_file_net(seq); |
3240 | struct hlist_node *n = &ifa->addr_lst; | ||
3241 | 3242 | ||
3242 | hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { | 3243 | hlist_for_each_entry_continue_rcu_bh(ifa, addr_lst) { |
3243 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3244 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3244 | continue; | 3245 | continue; |
3245 | state->offset++; | 3246 | state->offset++; |
@@ -3248,7 +3249,7 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, | |||
3248 | 3249 | ||
3249 | while (++state->bucket < IN6_ADDR_HSIZE) { | 3250 | while (++state->bucket < IN6_ADDR_HSIZE) { |
3250 | state->offset = 0; | 3251 | state->offset = 0; |
3251 | hlist_for_each_entry_rcu_bh(ifa, n, | 3252 | hlist_for_each_entry_rcu_bh(ifa, |
3252 | &inet6_addr_lst[state->bucket], addr_lst) { | 3253 | &inet6_addr_lst[state->bucket], addr_lst) { |
3253 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3254 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3254 | continue; | 3255 | continue; |
@@ -3318,14 +3319,14 @@ static const struct file_operations if6_fops = { | |||
3318 | 3319 | ||
3319 | static int __net_init if6_proc_net_init(struct net *net) | 3320 | static int __net_init if6_proc_net_init(struct net *net) |
3320 | { | 3321 | { |
3321 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3322 | if (!proc_create("if_inet6", S_IRUGO, net->proc_net, &if6_fops)) |
3322 | return -ENOMEM; | 3323 | return -ENOMEM; |
3323 | return 0; | 3324 | return 0; |
3324 | } | 3325 | } |
3325 | 3326 | ||
3326 | static void __net_exit if6_proc_net_exit(struct net *net) | 3327 | static void __net_exit if6_proc_net_exit(struct net *net) |
3327 | { | 3328 | { |
3328 | proc_net_remove(net, "if_inet6"); | 3329 | remove_proc_entry("if_inet6", net->proc_net); |
3329 | } | 3330 | } |
3330 | 3331 | ||
3331 | static struct pernet_operations if6_proc_net_ops = { | 3332 | static struct pernet_operations if6_proc_net_ops = { |
@@ -3350,11 +3351,10 @@ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) | |||
3350 | { | 3351 | { |
3351 | int ret = 0; | 3352 | int ret = 0; |
3352 | struct inet6_ifaddr *ifp = NULL; | 3353 | struct inet6_ifaddr *ifp = NULL; |
3353 | struct hlist_node *n; | ||
3354 | unsigned int hash = inet6_addr_hash(addr); | 3354 | unsigned int hash = inet6_addr_hash(addr); |
3355 | 3355 | ||
3356 | rcu_read_lock_bh(); | 3356 | rcu_read_lock_bh(); |
3357 | hlist_for_each_entry_rcu_bh(ifp, n, &inet6_addr_lst[hash], addr_lst) { | 3357 | hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { |
3358 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 3358 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
3359 | continue; | 3359 | continue; |
3360 | if (ipv6_addr_equal(&ifp->addr, addr) && | 3360 | if (ipv6_addr_equal(&ifp->addr, addr) && |
@@ -3376,7 +3376,6 @@ static void addrconf_verify(unsigned long foo) | |||
3376 | { | 3376 | { |
3377 | unsigned long now, next, next_sec, next_sched; | 3377 | unsigned long now, next, next_sec, next_sched; |
3378 | struct inet6_ifaddr *ifp; | 3378 | struct inet6_ifaddr *ifp; |
3379 | struct hlist_node *node; | ||
3380 | int i; | 3379 | int i; |
3381 | 3380 | ||
3382 | rcu_read_lock_bh(); | 3381 | rcu_read_lock_bh(); |
@@ -3388,7 +3387,7 @@ static void addrconf_verify(unsigned long foo) | |||
3388 | 3387 | ||
3389 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | 3388 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
3390 | restart: | 3389 | restart: |
3391 | hlist_for_each_entry_rcu_bh(ifp, node, | 3390 | hlist_for_each_entry_rcu_bh(ifp, |
3392 | &inet6_addr_lst[i], addr_lst) { | 3391 | &inet6_addr_lst[i], addr_lst) { |
3393 | unsigned long age; | 3392 | unsigned long age; |
3394 | 3393 | ||
@@ -3859,7 +3858,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3859 | struct net_device *dev; | 3858 | struct net_device *dev; |
3860 | struct inet6_dev *idev; | 3859 | struct inet6_dev *idev; |
3861 | struct hlist_head *head; | 3860 | struct hlist_head *head; |
3862 | struct hlist_node *node; | ||
3863 | 3861 | ||
3864 | s_h = cb->args[0]; | 3862 | s_h = cb->args[0]; |
3865 | s_idx = idx = cb->args[1]; | 3863 | s_idx = idx = cb->args[1]; |
@@ -3869,7 +3867,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3869 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 3867 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3870 | idx = 0; | 3868 | idx = 0; |
3871 | head = &net->dev_index_head[h]; | 3869 | head = &net->dev_index_head[h]; |
3872 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { | 3870 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
3873 | if (idx < s_idx) | 3871 | if (idx < s_idx) |
3874 | goto cont; | 3872 | goto cont; |
3875 | if (h > s_h || idx > s_idx) | 3873 | if (h > s_h || idx > s_idx) |
@@ -4215,7 +4213,6 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4215 | struct net_device *dev; | 4213 | struct net_device *dev; |
4216 | struct inet6_dev *idev; | 4214 | struct inet6_dev *idev; |
4217 | struct hlist_head *head; | 4215 | struct hlist_head *head; |
4218 | struct hlist_node *node; | ||
4219 | 4216 | ||
4220 | s_h = cb->args[0]; | 4217 | s_h = cb->args[0]; |
4221 | s_idx = cb->args[1]; | 4218 | s_idx = cb->args[1]; |
@@ -4224,7 +4221,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4224 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 4221 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
4225 | idx = 0; | 4222 | idx = 0; |
4226 | head = &net->dev_index_head[h]; | 4223 | head = &net->dev_index_head[h]; |
4227 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { | 4224 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
4228 | if (idx < s_idx) | 4225 | if (idx < s_idx) |
4229 | goto cont; | 4226 | goto cont; |
4230 | idev = __in6_dev_get(dev); | 4227 | idev = __in6_dev_get(dev); |