aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-13 18:33:35 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-27 15:24:07 -0400
commit463d018323851a608eef52a9427b0585005c647f (patch)
treeb5ad2ee6115e6b780c264022cbc20b36d22fe80c /net/wireless/core.c
parent5061b0c2b9066de426fbc63f1278d2210e789412 (diff)
cfg80211: make aware of net namespaces
In order to make cfg80211/nl80211 aware of network namespaces, we have to do the following things: * del_virtual_intf method takes an interface index rather than a netdev pointer - simply change this * nl80211 uses init_net a lot, it changes to use the sender's network namespace * scan requests use the interface index, hold a netdev pointer and reference instead * we want a wiphy and its associated virtual interfaces to be in one netns together, so - we need to be able to change ns for a given interface, so export dev_change_net_namespace() - for each virtual interface set the NETIF_F_NETNS_LOCAL flag, and clear that flag only when the wiphy changes ns, to disallow breaking this invariant * when a network namespace goes away, we need to reparent the wiphy to init_net * cfg80211 users that support creating virtual interfaces must create them in the wiphy's namespace, currently this affects only mac80211 The end result is that you can now switch an entire wiphy into a different network namespace with the new command iw phy#<idx> set netns <pid> and all virtual interfaces will follow (or the operation fails). Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6891cd0e38d5..442c9f389799 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -106,7 +106,7 @@ __cfg80211_rdev_from_info(struct genl_info *info)
106 106
107 if (info->attrs[NL80211_ATTR_IFINDEX]) { 107 if (info->attrs[NL80211_ATTR_IFINDEX]) {
108 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); 108 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
109 dev = dev_get_by_index(&init_net, ifindex); 109 dev = dev_get_by_index(genl_info_net(info), ifindex);
110 if (dev) { 110 if (dev) {
111 if (dev->ieee80211_ptr) 111 if (dev->ieee80211_ptr)
112 byifidx = 112 byifidx =
@@ -151,13 +151,13 @@ cfg80211_get_dev_from_info(struct genl_info *info)
151} 151}
152 152
153struct cfg80211_registered_device * 153struct cfg80211_registered_device *
154cfg80211_get_dev_from_ifindex(int ifindex) 154cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
155{ 155{
156 struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); 156 struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
157 struct net_device *dev; 157 struct net_device *dev;
158 158
159 mutex_lock(&cfg80211_mutex); 159 mutex_lock(&cfg80211_mutex);
160 dev = dev_get_by_index(&init_net, ifindex); 160 dev = dev_get_by_index(net, ifindex);
161 if (!dev) 161 if (!dev)
162 goto out; 162 goto out;
163 if (dev->ieee80211_ptr) { 163 if (dev->ieee80211_ptr) {
@@ -222,6 +222,42 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
222 return 0; 222 return 0;
223} 223}
224 224
225int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
226 struct net *net)
227{
228 struct wireless_dev *wdev;
229 int err = 0;
230
231 if (!rdev->wiphy.netnsok)
232 return -EOPNOTSUPP;
233
234 list_for_each_entry(wdev, &rdev->netdev_list, list) {
235 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
236 err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
237 if (err)
238 break;
239 wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
240 }
241
242 if (err) {
243 /* failed -- clean up to old netns */
244 net = wiphy_net(&rdev->wiphy);
245
246 list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list,
247 list) {
248 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
249 err = dev_change_net_namespace(wdev->netdev, net,
250 "wlan%d");
251 WARN_ON(err);
252 wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
253 }
254 }
255
256 wiphy_net_set(&rdev->wiphy, net);
257
258 return err;
259}
260
225static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) 261static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
226{ 262{
227 struct cfg80211_registered_device *rdev = data; 263 struct cfg80211_registered_device *rdev = data;
@@ -375,6 +411,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
375 rdev->wiphy.dev.class = &ieee80211_class; 411 rdev->wiphy.dev.class = &ieee80211_class;
376 rdev->wiphy.dev.platform_data = rdev; 412 rdev->wiphy.dev.platform_data = rdev;
377 413
414 wiphy_net_set(&rdev->wiphy, &init_net);
415
378 rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; 416 rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
379 rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), 417 rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
380 &rdev->wiphy.dev, RFKILL_TYPE_WLAN, 418 &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
@@ -615,6 +653,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
615 spin_lock_init(&wdev->event_lock); 653 spin_lock_init(&wdev->event_lock);
616 mutex_lock(&rdev->devlist_mtx); 654 mutex_lock(&rdev->devlist_mtx);
617 list_add(&wdev->list, &rdev->netdev_list); 655 list_add(&wdev->list, &rdev->netdev_list);
656 /* can only change netns with wiphy */
657 dev->features |= NETIF_F_NETNS_LOCAL;
658
618 if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, 659 if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
619 "phy80211")) { 660 "phy80211")) {
620 printk(KERN_ERR "wireless: failed to add phy80211 " 661 printk(KERN_ERR "wireless: failed to add phy80211 "
@@ -705,10 +746,32 @@ static struct notifier_block cfg80211_netdev_notifier = {
705 .notifier_call = cfg80211_netdev_notifier_call, 746 .notifier_call = cfg80211_netdev_notifier_call,
706}; 747};
707 748
708static int cfg80211_init(void) 749static void __net_exit cfg80211_pernet_exit(struct net *net)
750{
751 struct cfg80211_registered_device *rdev;
752
753 rtnl_lock();
754 mutex_lock(&cfg80211_mutex);
755 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
756 if (net_eq(wiphy_net(&rdev->wiphy), net))
757 WARN_ON(cfg80211_switch_netns(rdev, &init_net));
758 }
759 mutex_unlock(&cfg80211_mutex);
760 rtnl_unlock();
761}
762
763static struct pernet_operations cfg80211_pernet_ops = {
764 .exit = cfg80211_pernet_exit,
765};
766
767static int __init cfg80211_init(void)
709{ 768{
710 int err; 769 int err;
711 770
771 err = register_pernet_device(&cfg80211_pernet_ops);
772 if (err)
773 goto out_fail_pernet;
774
712 err = wiphy_sysfs_init(); 775 err = wiphy_sysfs_init();
713 if (err) 776 if (err)
714 goto out_fail_sysfs; 777 goto out_fail_sysfs;
@@ -736,9 +799,10 @@ out_fail_nl80211:
736out_fail_notifier: 799out_fail_notifier:
737 wiphy_sysfs_exit(); 800 wiphy_sysfs_exit();
738out_fail_sysfs: 801out_fail_sysfs:
802 unregister_pernet_device(&cfg80211_pernet_ops);
803out_fail_pernet:
739 return err; 804 return err;
740} 805}
741
742subsys_initcall(cfg80211_init); 806subsys_initcall(cfg80211_init);
743 807
744static void cfg80211_exit(void) 808static void cfg80211_exit(void)
@@ -748,5 +812,6 @@ static void cfg80211_exit(void)
748 unregister_netdevice_notifier(&cfg80211_netdev_notifier); 812 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
749 wiphy_sysfs_exit(); 813 wiphy_sysfs_exit();
750 regulatory_exit(); 814 regulatory_exit();
815 unregister_pernet_device(&cfg80211_pernet_ops);
751} 816}
752module_exit(cfg80211_exit); 817module_exit(cfg80211_exit);