aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c59
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
118static void addrconf_sysctl_register(struct inet6_dev *idev); 114static void addrconf_sysctl_register(struct inet6_dev *idev);
119static void addrconf_sysctl_unregister(struct inet6_dev *idev); 115static void addrconf_sysctl_unregister(struct inet6_dev *idev);
@@ -248,6 +244,9 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
248const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 244const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
249const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; 245const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
250const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 246const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
247const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
248const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
249const 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 */
253static inline bool addrconf_qdisc_ok(const struct net_device *dev) 252static 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
3319static int __net_init if6_proc_net_init(struct net *net) 3320static 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
3326static void __net_exit if6_proc_net_exit(struct net *net) 3327static 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
3331static struct pernet_operations if6_proc_net_ops = { 3332static 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++) {
3390restart: 3389restart:
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);