aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 10:55:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 10:55:01 -0500
commitd7fc02c7bae7b1cf69269992cf880a43a350cdaa (patch)
treea43d56fa72913a1cc98a0bbebe054d08581b3a7c /net/ipv6/addrconf.c
parentee1262dbc65ce0b6234a915d8432171e8d77f518 (diff)
parent28b4d5cc17c20786848cdc07b7ea237a309776bb (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits) mac80211: fix reorder buffer release iwmc3200wifi: Enable wimax core through module parameter iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter iwmc3200wifi: Coex table command does not expect a response iwmc3200wifi: Update wiwi priority table iwlwifi: driver version track kernel version iwlwifi: indicate uCode type when fail dump error/event log iwl3945: remove duplicated event logging code b43: fix two warnings ipw2100: fix rebooting hang with driver loaded cfg80211: indent regulatory messages with spaces iwmc3200wifi: fix NULL pointer dereference in pmkid update mac80211: Fix TX status reporting for injected data frames ath9k: enable 2GHz band only if the device supports it airo: Fix integer overflow warning rt2x00: Fix padding bug on L2PAD devices. WE: Fix set events not propagated b43legacy: avoid PPC fault during resume b43: avoid PPC fault during resume tcp: fix a timewait refcnt race ... Fix up conflicts due to sysctl cleanups (dead sysctl_check code and CTL_UNNUMBERED removed) in kernel/sysctl_check.c net/ipv4/sysctl_net_ipv4.c net/ipv6/addrconf.c net/sctp/sysctl.c
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c244
1 files changed, 143 insertions, 101 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f918399c985c..de7a194a64ab 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -481,9 +481,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
481 struct net_device *dev; 481 struct net_device *dev;
482 struct inet6_dev *idev; 482 struct inet6_dev *idev;
483 483
484 read_lock(&dev_base_lock); 484 rcu_read_lock();
485 for_each_netdev(net, dev) { 485 for_each_netdev_rcu(net, dev) {
486 rcu_read_lock();
487 idev = __in6_dev_get(dev); 486 idev = __in6_dev_get(dev);
488 if (idev) { 487 if (idev) {
489 int changed = (!idev->cnf.forwarding) ^ (!newf); 488 int changed = (!idev->cnf.forwarding) ^ (!newf);
@@ -491,9 +490,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
491 if (changed) 490 if (changed)
492 dev_forward_change(idev); 491 dev_forward_change(idev);
493 } 492 }
494 rcu_read_unlock();
495 } 493 }
496 read_unlock(&dev_base_lock); 494 rcu_read_unlock();
497} 495}
498 496
499static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) 497static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
@@ -1137,10 +1135,9 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
1137 hiscore->rule = -1; 1135 hiscore->rule = -1;
1138 hiscore->ifa = NULL; 1136 hiscore->ifa = NULL;
1139 1137
1140 read_lock(&dev_base_lock);
1141 rcu_read_lock(); 1138 rcu_read_lock();
1142 1139
1143 for_each_netdev(net, dev) { 1140 for_each_netdev_rcu(net, dev) {
1144 struct inet6_dev *idev; 1141 struct inet6_dev *idev;
1145 1142
1146 /* Candidate Source Address (section 4) 1143 /* Candidate Source Address (section 4)
@@ -1235,7 +1232,6 @@ try_nextdev:
1235 read_unlock_bh(&idev->lock); 1232 read_unlock_bh(&idev->lock);
1236 } 1233 }
1237 rcu_read_unlock(); 1234 rcu_read_unlock();
1238 read_unlock(&dev_base_lock);
1239 1235
1240 if (!hiscore->ifa) 1236 if (!hiscore->ifa)
1241 return -EADDRNOTAVAIL; 1237 return -EADDRNOTAVAIL;
@@ -3485,85 +3481,114 @@ enum addr_type_t
3485 ANYCAST_ADDR, 3481 ANYCAST_ADDR,
3486}; 3482};
3487 3483
3484/* called with rcu_read_lock() */
3485static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
3486 struct netlink_callback *cb, enum addr_type_t type,
3487 int s_ip_idx, int *p_ip_idx)
3488{
3489 struct inet6_ifaddr *ifa;
3490 struct ifmcaddr6 *ifmca;
3491 struct ifacaddr6 *ifaca;
3492 int err = 1;
3493 int ip_idx = *p_ip_idx;
3494
3495 read_lock_bh(&idev->lock);
3496 switch (type) {
3497 case UNICAST_ADDR:
3498 /* unicast address incl. temp addr */
3499 for (ifa = idev->addr_list; ifa;
3500 ifa = ifa->if_next, ip_idx++) {
3501 if (ip_idx < s_ip_idx)
3502 continue;
3503 err = inet6_fill_ifaddr(skb, ifa,
3504 NETLINK_CB(cb->skb).pid,
3505 cb->nlh->nlmsg_seq,
3506 RTM_NEWADDR,
3507 NLM_F_MULTI);
3508 if (err <= 0)
3509 break;
3510 }
3511 break;
3512 case MULTICAST_ADDR:
3513 /* multicast address */
3514 for (ifmca = idev->mc_list; ifmca;
3515 ifmca = ifmca->next, ip_idx++) {
3516 if (ip_idx < s_ip_idx)
3517 continue;
3518 err = inet6_fill_ifmcaddr(skb, ifmca,
3519 NETLINK_CB(cb->skb).pid,
3520 cb->nlh->nlmsg_seq,
3521 RTM_GETMULTICAST,
3522 NLM_F_MULTI);
3523 if (err <= 0)
3524 break;
3525 }
3526 break;
3527 case ANYCAST_ADDR:
3528 /* anycast address */
3529 for (ifaca = idev->ac_list; ifaca;
3530 ifaca = ifaca->aca_next, ip_idx++) {
3531 if (ip_idx < s_ip_idx)
3532 continue;
3533 err = inet6_fill_ifacaddr(skb, ifaca,
3534 NETLINK_CB(cb->skb).pid,
3535 cb->nlh->nlmsg_seq,
3536 RTM_GETANYCAST,
3537 NLM_F_MULTI);
3538 if (err <= 0)
3539 break;
3540 }
3541 break;
3542 default:
3543 break;
3544 }
3545 read_unlock_bh(&idev->lock);
3546 *p_ip_idx = ip_idx;
3547 return err;
3548}
3549
3488static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, 3550static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
3489 enum addr_type_t type) 3551 enum addr_type_t type)
3490{ 3552{
3553 struct net *net = sock_net(skb->sk);
3554 int h, s_h;
3491 int idx, ip_idx; 3555 int idx, ip_idx;
3492 int s_idx, s_ip_idx; 3556 int s_idx, s_ip_idx;
3493 int err = 1;
3494 struct net_device *dev; 3557 struct net_device *dev;
3495 struct inet6_dev *idev = NULL; 3558 struct inet6_dev *idev;
3496 struct inet6_ifaddr *ifa; 3559 struct hlist_head *head;
3497 struct ifmcaddr6 *ifmca; 3560 struct hlist_node *node;
3498 struct ifacaddr6 *ifaca;
3499 struct net *net = sock_net(skb->sk);
3500
3501 s_idx = cb->args[0];
3502 s_ip_idx = ip_idx = cb->args[1];
3503 3561
3504 idx = 0; 3562 s_h = cb->args[0];
3505 for_each_netdev(net, dev) { 3563 s_idx = idx = cb->args[1];
3506 if (idx < s_idx) 3564 s_ip_idx = ip_idx = cb->args[2];
3507 goto cont;
3508 if (idx > s_idx)
3509 s_ip_idx = 0;
3510 ip_idx = 0;
3511 if ((idev = in6_dev_get(dev)) == NULL)
3512 goto cont;
3513 read_lock_bh(&idev->lock);
3514 switch (type) {
3515 case UNICAST_ADDR:
3516 /* unicast address incl. temp addr */
3517 for (ifa = idev->addr_list; ifa;
3518 ifa = ifa->if_next, ip_idx++) {
3519 if (ip_idx < s_ip_idx)
3520 continue;
3521 err = inet6_fill_ifaddr(skb, ifa,
3522 NETLINK_CB(cb->skb).pid,
3523 cb->nlh->nlmsg_seq,
3524 RTM_NEWADDR,
3525 NLM_F_MULTI);
3526 }
3527 break;
3528 case MULTICAST_ADDR:
3529 /* multicast address */
3530 for (ifmca = idev->mc_list; ifmca;
3531 ifmca = ifmca->next, ip_idx++) {
3532 if (ip_idx < s_ip_idx)
3533 continue;
3534 err = inet6_fill_ifmcaddr(skb, ifmca,
3535 NETLINK_CB(cb->skb).pid,
3536 cb->nlh->nlmsg_seq,
3537 RTM_GETMULTICAST,
3538 NLM_F_MULTI);
3539 }
3540 break;
3541 case ANYCAST_ADDR:
3542 /* anycast address */
3543 for (ifaca = idev->ac_list; ifaca;
3544 ifaca = ifaca->aca_next, ip_idx++) {
3545 if (ip_idx < s_ip_idx)
3546 continue;
3547 err = inet6_fill_ifacaddr(skb, ifaca,
3548 NETLINK_CB(cb->skb).pid,
3549 cb->nlh->nlmsg_seq,
3550 RTM_GETANYCAST,
3551 NLM_F_MULTI);
3552 }
3553 break;
3554 default:
3555 break;
3556 }
3557 read_unlock_bh(&idev->lock);
3558 in6_dev_put(idev);
3559 3565
3560 if (err <= 0) 3566 rcu_read_lock();
3561 break; 3567 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
3568 idx = 0;
3569 head = &net->dev_index_head[h];
3570 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
3571 if (idx < s_idx)
3572 goto cont;
3573 if (idx > s_idx)
3574 s_ip_idx = 0;
3575 ip_idx = 0;
3576 if ((idev = __in6_dev_get(dev)) == NULL)
3577 goto cont;
3578
3579 if (in6_dump_addrs(idev, skb, cb, type,
3580 s_ip_idx, &ip_idx) <= 0)
3581 goto done;
3562cont: 3582cont:
3563 idx++; 3583 idx++;
3584 }
3564 } 3585 }
3565 cb->args[0] = idx; 3586done:
3566 cb->args[1] = ip_idx; 3587 rcu_read_unlock();
3588 cb->args[0] = h;
3589 cb->args[1] = idx;
3590 cb->args[2] = ip_idx;
3591
3567 return skb->len; 3592 return skb->len;
3568} 3593}
3569 3594
@@ -3708,6 +3733,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3708#endif 3733#endif
3709 array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; 3734 array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
3710 array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; 3735 array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
3736 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
3711} 3737}
3712 3738
3713static inline size_t inet6_if_nlmsg_size(void) 3739static inline size_t inet6_if_nlmsg_size(void)
@@ -3826,28 +3852,39 @@ nla_put_failure:
3826static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 3852static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
3827{ 3853{
3828 struct net *net = sock_net(skb->sk); 3854 struct net *net = sock_net(skb->sk);
3829 int idx, err; 3855 int h, s_h;
3830 int s_idx = cb->args[0]; 3856 int idx = 0, s_idx;
3831 struct net_device *dev; 3857 struct net_device *dev;
3832 struct inet6_dev *idev; 3858 struct inet6_dev *idev;
3859 struct hlist_head *head;
3860 struct hlist_node *node;
3833 3861
3834 read_lock(&dev_base_lock); 3862 s_h = cb->args[0];
3835 idx = 0; 3863 s_idx = cb->args[1];
3836 for_each_netdev(net, dev) { 3864
3837 if (idx < s_idx) 3865 rcu_read_lock();
3838 goto cont; 3866 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
3839 if ((idev = in6_dev_get(dev)) == NULL) 3867 idx = 0;
3840 goto cont; 3868 head = &net->dev_index_head[h];
3841 err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, 3869 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
3842 cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI); 3870 if (idx < s_idx)
3843 in6_dev_put(idev); 3871 goto cont;
3844 if (err <= 0) 3872 idev = __in6_dev_get(dev);
3845 break; 3873 if (!idev)
3874 goto cont;
3875 if (inet6_fill_ifinfo(skb, idev,
3876 NETLINK_CB(cb->skb).pid,
3877 cb->nlh->nlmsg_seq,
3878 RTM_NEWLINK, NLM_F_MULTI) <= 0)
3879 goto out;
3846cont: 3880cont:
3847 idx++; 3881 idx++;
3882 }
3848 } 3883 }
3849 read_unlock(&dev_base_lock); 3884out:
3850 cb->args[0] = idx; 3885 rcu_read_unlock();
3886 cb->args[1] = idx;
3887 cb->args[0] = h;
3851 3888
3852 return skb->len; 3889 return skb->len;
3853} 3890}
@@ -4016,9 +4053,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf)
4016 struct net_device *dev; 4053 struct net_device *dev;
4017 struct inet6_dev *idev; 4054 struct inet6_dev *idev;
4018 4055
4019 read_lock(&dev_base_lock); 4056 rcu_read_lock();
4020 for_each_netdev(net, dev) { 4057 for_each_netdev_rcu(net, dev) {
4021 rcu_read_lock();
4022 idev = __in6_dev_get(dev); 4058 idev = __in6_dev_get(dev);
4023 if (idev) { 4059 if (idev) {
4024 int changed = (!idev->cnf.disable_ipv6) ^ (!newf); 4060 int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
@@ -4026,9 +4062,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf)
4026 if (changed) 4062 if (changed)
4027 dev_disable_change(idev); 4063 dev_disable_change(idev);
4028 } 4064 }
4029 rcu_read_unlock();
4030 } 4065 }
4031 read_unlock(&dev_base_lock); 4066 rcu_read_unlock();
4032} 4067}
4033 4068
4034static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) 4069static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
@@ -4285,6 +4320,13 @@ static struct addrconf_sysctl_table
4285 .proc_handler = proc_dointvec, 4320 .proc_handler = proc_dointvec,
4286 }, 4321 },
4287 { 4322 {
4323 .procname = "force_tllao",
4324 .data = &ipv6_devconf.force_tllao,
4325 .maxlen = sizeof(int),
4326 .mode = 0644,
4327 .proc_handler = proc_dointvec
4328 },
4329 {
4288 /* sentinel */ 4330 /* sentinel */
4289 } 4331 }
4290 }, 4332 },
@@ -4385,7 +4427,7 @@ static int addrconf_init_net(struct net *net)
4385 all = &ipv6_devconf; 4427 all = &ipv6_devconf;
4386 dflt = &ipv6_devconf_dflt; 4428 dflt = &ipv6_devconf_dflt;
4387 4429
4388 if (net != &init_net) { 4430 if (!net_eq(net, &init_net)) {
4389 all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); 4431 all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL);
4390 if (all == NULL) 4432 if (all == NULL)
4391 goto err_alloc_all; 4433 goto err_alloc_all;
@@ -4431,7 +4473,7 @@ static void addrconf_exit_net(struct net *net)
4431 __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); 4473 __addrconf_sysctl_unregister(net->ipv6.devconf_dflt);
4432 __addrconf_sysctl_unregister(net->ipv6.devconf_all); 4474 __addrconf_sysctl_unregister(net->ipv6.devconf_all);
4433#endif 4475#endif
4434 if (net != &init_net) { 4476 if (!net_eq(net, &init_net)) {
4435 kfree(net->ipv6.devconf_dflt); 4477 kfree(net->ipv6.devconf_dflt);
4436 kfree(net->ipv6.devconf_all); 4478 kfree(net->ipv6.devconf_all);
4437 } 4479 }