diff options
-rw-r--r-- | include/linux/nl80211.h | 9 | ||||
-rw-r--r-- | include/net/cfg80211.h | 40 | ||||
-rw-r--r-- | net/core/dev.c | 1 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 14 | ||||
-rw-r--r-- | net/wireless/core.c | 75 | ||||
-rw-r--r-- | net/wireless/core.h | 5 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 202 | ||||
-rw-r--r-- | net/wireless/scan.c | 22 | ||||
-rw-r--r-- | net/wireless/sme.c | 3 |
9 files changed, 272 insertions, 99 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 962e2232a074..cb3dc6027fd9 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -262,6 +262,9 @@ | |||
262 | * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and | 262 | * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and |
263 | * %NL80211_ATTR_REASON_CODE attributes are used. | 263 | * %NL80211_ATTR_REASON_CODE attributes are used. |
264 | * | 264 | * |
265 | * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices | ||
266 | * associated with this wiphy must be down and will follow. | ||
267 | * | ||
265 | * @NL80211_CMD_MAX: highest used command number | 268 | * @NL80211_CMD_MAX: highest used command number |
266 | * @__NL80211_CMD_AFTER_LAST: internal use | 269 | * @__NL80211_CMD_AFTER_LAST: internal use |
267 | */ | 270 | */ |
@@ -336,6 +339,8 @@ enum nl80211_commands { | |||
336 | NL80211_CMD_ROAM, | 339 | NL80211_CMD_ROAM, |
337 | NL80211_CMD_DISCONNECT, | 340 | NL80211_CMD_DISCONNECT, |
338 | 341 | ||
342 | NL80211_CMD_SET_WIPHY_NETNS, | ||
343 | |||
339 | /* add new commands above here */ | 344 | /* add new commands above here */ |
340 | 345 | ||
341 | /* used to define NL80211_CMD_MAX below */ | 346 | /* used to define NL80211_CMD_MAX below */ |
@@ -573,6 +578,8 @@ enum nl80211_commands { | |||
573 | * and join_ibss(), key information is in a nested attribute each | 578 | * and join_ibss(), key information is in a nested attribute each |
574 | * with %NL80211_KEY_* sub-attributes | 579 | * with %NL80211_KEY_* sub-attributes |
575 | * | 580 | * |
581 | * @NL80211_ATTR_PID: Process ID of a network namespace. | ||
582 | * | ||
576 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 583 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
577 | * @__NL80211_ATTR_AFTER_LAST: internal use | 584 | * @__NL80211_ATTR_AFTER_LAST: internal use |
578 | */ | 585 | */ |
@@ -701,6 +708,8 @@ enum nl80211_attrs { | |||
701 | NL80211_ATTR_KEY, | 708 | NL80211_ATTR_KEY, |
702 | NL80211_ATTR_KEYS, | 709 | NL80211_ATTR_KEYS, |
703 | 710 | ||
711 | NL80211_ATTR_PID, | ||
712 | |||
704 | /* add attributes here, update the policy in nl80211.c */ | 713 | /* add attributes here, update the policy in nl80211.c */ |
705 | 714 | ||
706 | __NL80211_ATTR_AFTER_LAST, | 715 | __NL80211_ATTR_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a981ca8a5701..0d278777e39c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -542,7 +542,7 @@ struct cfg80211_ssid { | |||
542 | * @ie: optional information element(s) to add into Probe Request or %NULL | 542 | * @ie: optional information element(s) to add into Probe Request or %NULL |
543 | * @ie_len: length of ie in octets | 543 | * @ie_len: length of ie in octets |
544 | * @wiphy: the wiphy this was for | 544 | * @wiphy: the wiphy this was for |
545 | * @ifidx: the interface index | 545 | * @dev: the interface |
546 | */ | 546 | */ |
547 | struct cfg80211_scan_request { | 547 | struct cfg80211_scan_request { |
548 | struct cfg80211_ssid *ssids; | 548 | struct cfg80211_ssid *ssids; |
@@ -554,7 +554,7 @@ struct cfg80211_scan_request { | |||
554 | 554 | ||
555 | /* internal */ | 555 | /* internal */ |
556 | struct wiphy *wiphy; | 556 | struct wiphy *wiphy; |
557 | int ifidx; | 557 | struct net_device *dev; |
558 | bool aborted; | 558 | bool aborted; |
559 | }; | 559 | }; |
560 | 560 | ||
@@ -845,7 +845,8 @@ struct cfg80211_bitrate_mask { | |||
845 | * @resume: wiphy device needs to be resumed | 845 | * @resume: wiphy device needs to be resumed |
846 | * | 846 | * |
847 | * @add_virtual_intf: create a new virtual interface with the given name, | 847 | * @add_virtual_intf: create a new virtual interface with the given name, |
848 | * must set the struct wireless_dev's iftype. | 848 | * must set the struct wireless_dev's iftype. Beware: You must create |
849 | * the new netdev in the wiphy's network namespace! | ||
849 | * | 850 | * |
850 | * @del_virtual_intf: remove the virtual interface determined by ifindex. | 851 | * @del_virtual_intf: remove the virtual interface determined by ifindex. |
851 | * | 852 | * |
@@ -937,7 +938,7 @@ struct cfg80211_ops { | |||
937 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 938 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
938 | enum nl80211_iftype type, u32 *flags, | 939 | enum nl80211_iftype type, u32 *flags, |
939 | struct vif_params *params); | 940 | struct vif_params *params); |
940 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); | 941 | int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); |
941 | int (*change_virtual_intf)(struct wiphy *wiphy, | 942 | int (*change_virtual_intf)(struct wiphy *wiphy, |
942 | struct net_device *dev, | 943 | struct net_device *dev, |
943 | enum nl80211_iftype type, u32 *flags, | 944 | enum nl80211_iftype type, u32 *flags, |
@@ -1088,6 +1089,9 @@ struct cfg80211_ops { | |||
1088 | * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); | 1089 | * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); |
1089 | * -1 = fragmentation disabled, only odd values >= 256 used | 1090 | * -1 = fragmentation disabled, only odd values >= 256 used |
1090 | * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled | 1091 | * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled |
1092 | * @net: the network namespace this wiphy currently lives in | ||
1093 | * @netnsok: if set to false, do not allow changing the netns of this | ||
1094 | * wiphy at all | ||
1091 | */ | 1095 | */ |
1092 | struct wiphy { | 1096 | struct wiphy { |
1093 | /* assign these fields before you register the wiphy */ | 1097 | /* assign these fields before you register the wiphy */ |
@@ -1101,6 +1105,8 @@ struct wiphy { | |||
1101 | bool custom_regulatory; | 1105 | bool custom_regulatory; |
1102 | bool strict_regulatory; | 1106 | bool strict_regulatory; |
1103 | 1107 | ||
1108 | bool netnsok; | ||
1109 | |||
1104 | enum cfg80211_signal_type signal_type; | 1110 | enum cfg80211_signal_type signal_type; |
1105 | 1111 | ||
1106 | int bss_priv_size; | 1112 | int bss_priv_size; |
@@ -1139,9 +1145,35 @@ struct wiphy { | |||
1139 | /* dir in debugfs: ieee80211/<wiphyname> */ | 1145 | /* dir in debugfs: ieee80211/<wiphyname> */ |
1140 | struct dentry *debugfsdir; | 1146 | struct dentry *debugfsdir; |
1141 | 1147 | ||
1148 | #ifdef CONFIG_NET_NS | ||
1149 | /* the network namespace this phy lives in currently */ | ||
1150 | struct net *_net; | ||
1151 | #endif | ||
1152 | |||
1142 | char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); | 1153 | char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); |
1143 | }; | 1154 | }; |
1144 | 1155 | ||
1156 | #ifdef CONFIG_NET_NS | ||
1157 | static inline struct net *wiphy_net(struct wiphy *wiphy) | ||
1158 | { | ||
1159 | return wiphy->_net; | ||
1160 | } | ||
1161 | |||
1162 | static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) | ||
1163 | { | ||
1164 | wiphy->_net = net; | ||
1165 | } | ||
1166 | #else | ||
1167 | static inline struct net *wiphy_net(struct wiphy *wiphy) | ||
1168 | { | ||
1169 | return &init_net; | ||
1170 | } | ||
1171 | |||
1172 | static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) | ||
1173 | { | ||
1174 | } | ||
1175 | #endif | ||
1176 | |||
1145 | /** | 1177 | /** |
1146 | * wiphy_priv - return priv from wiphy | 1178 | * wiphy_priv - return priv from wiphy |
1147 | * | 1179 | * |
diff --git a/net/core/dev.c b/net/core/dev.c index d6c657ee413d..71347668c506 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -5344,6 +5344,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
5344 | out: | 5344 | out: |
5345 | return err; | 5345 | return err; |
5346 | } | 5346 | } |
5347 | EXPORT_SYMBOL_GPL(dev_change_net_namespace); | ||
5347 | 5348 | ||
5348 | static int dev_cpu_callback(struct notifier_block *nfb, | 5349 | static int dev_cpu_callback(struct notifier_block *nfb, |
5349 | unsigned long action, | 5350 | unsigned long action, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 52928ad90570..4bbf5007799b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
57 | return 0; | 57 | return 0; |
58 | } | 58 | } |
59 | 59 | ||
60 | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | 60 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) |
61 | { | 61 | { |
62 | struct net_device *dev; | 62 | ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); |
63 | struct ieee80211_sub_if_data *sdata; | ||
64 | |||
65 | /* we're under RTNL */ | ||
66 | dev = __dev_get_by_index(&init_net, ifindex); | ||
67 | if (!dev) | ||
68 | return -ENODEV; | ||
69 | |||
70 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
71 | |||
72 | ieee80211_if_remove(sdata); | ||
73 | 63 | ||
74 | return 0; | 64 | return 0; |
75 | } | 65 | } |
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 | ||
153 | struct cfg80211_registered_device * | 153 | struct cfg80211_registered_device * |
154 | cfg80211_get_dev_from_ifindex(int ifindex) | 154 | cfg80211_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 | ||
225 | int 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 | |||
225 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | 261 | static 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 | ||
708 | static int cfg80211_init(void) | 749 | static 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 | |||
763 | static struct pernet_operations cfg80211_pernet_ops = { | ||
764 | .exit = cfg80211_pernet_exit, | ||
765 | }; | ||
766 | |||
767 | static 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: | |||
736 | out_fail_notifier: | 799 | out_fail_notifier: |
737 | wiphy_sysfs_exit(); | 800 | wiphy_sysfs_exit(); |
738 | out_fail_sysfs: | 801 | out_fail_sysfs: |
802 | unregister_pernet_device(&cfg80211_pernet_ops); | ||
803 | out_fail_pernet: | ||
739 | return err; | 804 | return err; |
740 | } | 805 | } |
741 | |||
742 | subsys_initcall(cfg80211_init); | 806 | subsys_initcall(cfg80211_init); |
743 | 807 | ||
744 | static void cfg80211_exit(void) | 808 | static 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 | } |
752 | module_exit(cfg80211_exit); | 817 | module_exit(cfg80211_exit); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 2ec8ddbe57de..4276b70cd975 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -170,7 +170,10 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | |||
170 | 170 | ||
171 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ | 171 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ |
172 | extern struct cfg80211_registered_device * | 172 | extern struct cfg80211_registered_device * |
173 | cfg80211_get_dev_from_ifindex(int ifindex); | 173 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); |
174 | |||
175 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | ||
176 | struct net *net); | ||
174 | 177 | ||
175 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) | 178 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) |
176 | { | 179 | { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index da450ef1fc7e..7880a9c4cdda 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -14,8 +14,10 @@ | |||
14 | #include <linux/rtnetlink.h> | 14 | #include <linux/rtnetlink.h> |
15 | #include <linux/netlink.h> | 15 | #include <linux/netlink.h> |
16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
17 | #include <net/net_namespace.h> | ||
17 | #include <net/genetlink.h> | 18 | #include <net/genetlink.h> |
18 | #include <net/cfg80211.h> | 19 | #include <net/cfg80211.h> |
20 | #include <net/sock.h> | ||
19 | #include "core.h" | 21 | #include "core.h" |
20 | #include "nl80211.h" | 22 | #include "nl80211.h" |
21 | #include "reg.h" | 23 | #include "reg.h" |
@@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = { | |||
27 | .hdrsize = 0, /* no private header */ | 29 | .hdrsize = 0, /* no private header */ |
28 | .version = 1, /* no particular meaning now */ | 30 | .version = 1, /* no particular meaning now */ |
29 | .maxattr = NL80211_ATTR_MAX, | 31 | .maxattr = NL80211_ATTR_MAX, |
32 | .netnsok = true, | ||
30 | }; | 33 | }; |
31 | 34 | ||
32 | /* internal helper: get rdev and dev */ | 35 | /* internal helper: get rdev and dev */ |
33 | static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, | 36 | static int get_rdev_dev_by_info_ifindex(struct genl_info *info, |
34 | struct cfg80211_registered_device **rdev, | 37 | struct cfg80211_registered_device **rdev, |
35 | struct net_device **dev) | 38 | struct net_device **dev) |
36 | { | 39 | { |
40 | struct nlattr **attrs = info->attrs; | ||
37 | int ifindex; | 41 | int ifindex; |
38 | 42 | ||
39 | if (!attrs[NL80211_ATTR_IFINDEX]) | 43 | if (!attrs[NL80211_ATTR_IFINDEX]) |
40 | return -EINVAL; | 44 | return -EINVAL; |
41 | 45 | ||
42 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 46 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
43 | *dev = dev_get_by_index(&init_net, ifindex); | 47 | *dev = dev_get_by_index(genl_info_net(info), ifindex); |
44 | if (!*dev) | 48 | if (!*dev) |
45 | return -ENODEV; | 49 | return -ENODEV; |
46 | 50 | ||
47 | *rdev = cfg80211_get_dev_from_ifindex(ifindex); | 51 | *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); |
48 | if (IS_ERR(*rdev)) { | 52 | if (IS_ERR(*rdev)) { |
49 | dev_put(*dev); | 53 | dev_put(*dev); |
50 | return PTR_ERR(*rdev); | 54 | return PTR_ERR(*rdev); |
@@ -133,6 +137,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
133 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | 137 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, |
134 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
135 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | ||
136 | }; | 141 | }; |
137 | 142 | ||
138 | /* policy for the attributes */ | 143 | /* policy for the attributes */ |
@@ -532,6 +537,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
532 | CMD(deauth, DEAUTHENTICATE); | 537 | CMD(deauth, DEAUTHENTICATE); |
533 | CMD(disassoc, DISASSOCIATE); | 538 | CMD(disassoc, DISASSOCIATE); |
534 | CMD(join_ibss, JOIN_IBSS); | 539 | CMD(join_ibss, JOIN_IBSS); |
540 | if (dev->wiphy.netnsok) { | ||
541 | i++; | ||
542 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | ||
543 | } | ||
535 | 544 | ||
536 | #undef CMD | 545 | #undef CMD |
537 | 546 | ||
@@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
562 | 571 | ||
563 | mutex_lock(&cfg80211_mutex); | 572 | mutex_lock(&cfg80211_mutex); |
564 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 573 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
574 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | ||
575 | continue; | ||
565 | if (++idx <= start) | 576 | if (++idx <= start) |
566 | continue; | 577 | continue; |
567 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, | 578 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, |
@@ -867,6 +878,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
867 | 878 | ||
868 | mutex_lock(&cfg80211_mutex); | 879 | mutex_lock(&cfg80211_mutex); |
869 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 880 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
881 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | ||
882 | continue; | ||
870 | if (wp_idx < wp_start) { | 883 | if (wp_idx < wp_start) { |
871 | wp_idx++; | 884 | wp_idx++; |
872 | continue; | 885 | continue; |
@@ -907,7 +920,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
907 | struct net_device *netdev; | 920 | struct net_device *netdev; |
908 | int err; | 921 | int err; |
909 | 922 | ||
910 | err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); | 923 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); |
911 | if (err) | 924 | if (err) |
912 | return err; | 925 | return err; |
913 | 926 | ||
@@ -975,7 +988,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
975 | 988 | ||
976 | rtnl_lock(); | 989 | rtnl_lock(); |
977 | 990 | ||
978 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 991 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
979 | if (err) | 992 | if (err) |
980 | goto unlock_rtnl; | 993 | goto unlock_rtnl; |
981 | 994 | ||
@@ -1098,26 +1111,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1098 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1111 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1099 | { | 1112 | { |
1100 | struct cfg80211_registered_device *rdev; | 1113 | struct cfg80211_registered_device *rdev; |
1101 | int ifindex, err; | 1114 | int err; |
1102 | struct net_device *dev; | 1115 | struct net_device *dev; |
1103 | 1116 | ||
1104 | rtnl_lock(); | 1117 | rtnl_lock(); |
1105 | 1118 | ||
1106 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1119 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1107 | if (err) | 1120 | if (err) |
1108 | goto unlock_rtnl; | 1121 | goto unlock_rtnl; |
1109 | ifindex = dev->ifindex; | ||
1110 | dev_put(dev); | ||
1111 | 1122 | ||
1112 | if (!rdev->ops->del_virtual_intf) { | 1123 | if (!rdev->ops->del_virtual_intf) { |
1113 | err = -EOPNOTSUPP; | 1124 | err = -EOPNOTSUPP; |
1114 | goto out; | 1125 | goto out; |
1115 | } | 1126 | } |
1116 | 1127 | ||
1117 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); | 1128 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1118 | 1129 | ||
1119 | out: | 1130 | out: |
1120 | cfg80211_unlock_rdev(rdev); | 1131 | cfg80211_unlock_rdev(rdev); |
1132 | dev_put(dev); | ||
1121 | unlock_rtnl: | 1133 | unlock_rtnl: |
1122 | rtnl_unlock(); | 1134 | rtnl_unlock(); |
1123 | return err; | 1135 | return err; |
@@ -1195,7 +1207,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1195 | 1207 | ||
1196 | rtnl_lock(); | 1208 | rtnl_lock(); |
1197 | 1209 | ||
1198 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1210 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1199 | if (err) | 1211 | if (err) |
1200 | goto unlock_rtnl; | 1212 | goto unlock_rtnl; |
1201 | 1213 | ||
@@ -1274,7 +1286,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1274 | 1286 | ||
1275 | rtnl_lock(); | 1287 | rtnl_lock(); |
1276 | 1288 | ||
1277 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1289 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1278 | if (err) | 1290 | if (err) |
1279 | goto unlock_rtnl; | 1291 | goto unlock_rtnl; |
1280 | 1292 | ||
@@ -1333,7 +1345,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1333 | 1345 | ||
1334 | rtnl_lock(); | 1346 | rtnl_lock(); |
1335 | 1347 | ||
1336 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1348 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1337 | if (err) | 1349 | if (err) |
1338 | goto unlock_rtnl; | 1350 | goto unlock_rtnl; |
1339 | 1351 | ||
@@ -1380,7 +1392,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1380 | 1392 | ||
1381 | rtnl_lock(); | 1393 | rtnl_lock(); |
1382 | 1394 | ||
1383 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1395 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1384 | if (err) | 1396 | if (err) |
1385 | goto unlock_rtnl; | 1397 | goto unlock_rtnl; |
1386 | 1398 | ||
@@ -1429,7 +1441,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1429 | 1441 | ||
1430 | rtnl_lock(); | 1442 | rtnl_lock(); |
1431 | 1443 | ||
1432 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1444 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1433 | if (err) | 1445 | if (err) |
1434 | goto unlock_rtnl; | 1446 | goto unlock_rtnl; |
1435 | 1447 | ||
@@ -1516,7 +1528,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1516 | 1528 | ||
1517 | rtnl_lock(); | 1529 | rtnl_lock(); |
1518 | 1530 | ||
1519 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1531 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1520 | if (err) | 1532 | if (err) |
1521 | goto unlock_rtnl; | 1533 | goto unlock_rtnl; |
1522 | 1534 | ||
@@ -1726,13 +1738,13 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1726 | 1738 | ||
1727 | rtnl_lock(); | 1739 | rtnl_lock(); |
1728 | 1740 | ||
1729 | netdev = __dev_get_by_index(&init_net, ifidx); | 1741 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
1730 | if (!netdev) { | 1742 | if (!netdev) { |
1731 | err = -ENODEV; | 1743 | err = -ENODEV; |
1732 | goto out_rtnl; | 1744 | goto out_rtnl; |
1733 | } | 1745 | } |
1734 | 1746 | ||
1735 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1747 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
1736 | if (IS_ERR(dev)) { | 1748 | if (IS_ERR(dev)) { |
1737 | err = PTR_ERR(dev); | 1749 | err = PTR_ERR(dev); |
1738 | goto out_rtnl; | 1750 | goto out_rtnl; |
@@ -1791,7 +1803,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1791 | 1803 | ||
1792 | rtnl_lock(); | 1804 | rtnl_lock(); |
1793 | 1805 | ||
1794 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1806 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1795 | if (err) | 1807 | if (err) |
1796 | goto out_rtnl; | 1808 | goto out_rtnl; |
1797 | 1809 | ||
@@ -1829,14 +1841,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1829 | /* | 1841 | /* |
1830 | * Get vlan interface making sure it is on the right wiphy. | 1842 | * Get vlan interface making sure it is on the right wiphy. |
1831 | */ | 1843 | */ |
1832 | static int get_vlan(struct nlattr *vlanattr, | 1844 | static int get_vlan(struct genl_info *info, |
1833 | struct cfg80211_registered_device *rdev, | 1845 | struct cfg80211_registered_device *rdev, |
1834 | struct net_device **vlan) | 1846 | struct net_device **vlan) |
1835 | { | 1847 | { |
1848 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; | ||
1836 | *vlan = NULL; | 1849 | *vlan = NULL; |
1837 | 1850 | ||
1838 | if (vlanattr) { | 1851 | if (vlanattr) { |
1839 | *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); | 1852 | *vlan = dev_get_by_index(genl_info_net(info), |
1853 | nla_get_u32(vlanattr)); | ||
1840 | if (!*vlan) | 1854 | if (!*vlan) |
1841 | return -ENODEV; | 1855 | return -ENODEV; |
1842 | if (!(*vlan)->ieee80211_ptr) | 1856 | if (!(*vlan)->ieee80211_ptr) |
@@ -1891,11 +1905,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1891 | 1905 | ||
1892 | rtnl_lock(); | 1906 | rtnl_lock(); |
1893 | 1907 | ||
1894 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1908 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1895 | if (err) | 1909 | if (err) |
1896 | goto out_rtnl; | 1910 | goto out_rtnl; |
1897 | 1911 | ||
1898 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); | 1912 | err = get_vlan(info, rdev, ¶ms.vlan); |
1899 | if (err) | 1913 | if (err) |
1900 | goto out; | 1914 | goto out; |
1901 | 1915 | ||
@@ -2004,11 +2018,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2004 | 2018 | ||
2005 | rtnl_lock(); | 2019 | rtnl_lock(); |
2006 | 2020 | ||
2007 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2021 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2008 | if (err) | 2022 | if (err) |
2009 | goto out_rtnl; | 2023 | goto out_rtnl; |
2010 | 2024 | ||
2011 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); | 2025 | err = get_vlan(info, rdev, ¶ms.vlan); |
2012 | if (err) | 2026 | if (err) |
2013 | goto out; | 2027 | goto out; |
2014 | 2028 | ||
@@ -2079,7 +2093,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
2079 | 2093 | ||
2080 | rtnl_lock(); | 2094 | rtnl_lock(); |
2081 | 2095 | ||
2082 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2096 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2083 | if (err) | 2097 | if (err) |
2084 | goto out_rtnl; | 2098 | goto out_rtnl; |
2085 | 2099 | ||
@@ -2185,13 +2199,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2185 | 2199 | ||
2186 | rtnl_lock(); | 2200 | rtnl_lock(); |
2187 | 2201 | ||
2188 | netdev = __dev_get_by_index(&init_net, ifidx); | 2202 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
2189 | if (!netdev) { | 2203 | if (!netdev) { |
2190 | err = -ENODEV; | 2204 | err = -ENODEV; |
2191 | goto out_rtnl; | 2205 | goto out_rtnl; |
2192 | } | 2206 | } |
2193 | 2207 | ||
2194 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 2208 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
2195 | if (IS_ERR(dev)) { | 2209 | if (IS_ERR(dev)) { |
2196 | err = PTR_ERR(dev); | 2210 | err = PTR_ERR(dev); |
2197 | goto out_rtnl; | 2211 | goto out_rtnl; |
@@ -2255,7 +2269,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2255 | 2269 | ||
2256 | rtnl_lock(); | 2270 | rtnl_lock(); |
2257 | 2271 | ||
2258 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2272 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2259 | if (err) | 2273 | if (err) |
2260 | goto out_rtnl; | 2274 | goto out_rtnl; |
2261 | 2275 | ||
@@ -2314,7 +2328,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2314 | 2328 | ||
2315 | rtnl_lock(); | 2329 | rtnl_lock(); |
2316 | 2330 | ||
2317 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2331 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2318 | if (err) | 2332 | if (err) |
2319 | goto out_rtnl; | 2333 | goto out_rtnl; |
2320 | 2334 | ||
@@ -2362,7 +2376,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2362 | 2376 | ||
2363 | rtnl_lock(); | 2377 | rtnl_lock(); |
2364 | 2378 | ||
2365 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2379 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2366 | if (err) | 2380 | if (err) |
2367 | goto out_rtnl; | 2381 | goto out_rtnl; |
2368 | 2382 | ||
@@ -2404,7 +2418,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2404 | 2418 | ||
2405 | rtnl_lock(); | 2419 | rtnl_lock(); |
2406 | 2420 | ||
2407 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2421 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2408 | if (err) | 2422 | if (err) |
2409 | goto out_rtnl; | 2423 | goto out_rtnl; |
2410 | 2424 | ||
@@ -2455,7 +2469,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2455 | 2469 | ||
2456 | rtnl_lock(); | 2470 | rtnl_lock(); |
2457 | 2471 | ||
2458 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2472 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2459 | if (err) | 2473 | if (err) |
2460 | goto out_rtnl; | 2474 | goto out_rtnl; |
2461 | 2475 | ||
@@ -2574,7 +2588,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2574 | rtnl_lock(); | 2588 | rtnl_lock(); |
2575 | 2589 | ||
2576 | /* Look up our device */ | 2590 | /* Look up our device */ |
2577 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2591 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2578 | if (err) | 2592 | if (err) |
2579 | goto out_rtnl; | 2593 | goto out_rtnl; |
2580 | 2594 | ||
@@ -2691,7 +2705,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2691 | 2705 | ||
2692 | rtnl_lock(); | 2706 | rtnl_lock(); |
2693 | 2707 | ||
2694 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2708 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2695 | if (err) | 2709 | if (err) |
2696 | goto out_rtnl; | 2710 | goto out_rtnl; |
2697 | 2711 | ||
@@ -2947,7 +2961,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2947 | 2961 | ||
2948 | rtnl_lock(); | 2962 | rtnl_lock(); |
2949 | 2963 | ||
2950 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2964 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2951 | if (err) | 2965 | if (err) |
2952 | goto out_rtnl; | 2966 | goto out_rtnl; |
2953 | 2967 | ||
@@ -3069,14 +3083,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3069 | request->ie_len); | 3083 | request->ie_len); |
3070 | } | 3084 | } |
3071 | 3085 | ||
3072 | request->ifidx = dev->ifindex; | 3086 | request->dev = dev; |
3073 | request->wiphy = &rdev->wiphy; | 3087 | request->wiphy = &rdev->wiphy; |
3074 | 3088 | ||
3075 | rdev->scan_req = request; | 3089 | rdev->scan_req = request; |
3076 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 3090 | err = rdev->ops->scan(&rdev->wiphy, dev, request); |
3077 | 3091 | ||
3078 | if (!err) | 3092 | if (!err) { |
3079 | nl80211_send_scan_start(rdev, dev); | 3093 | nl80211_send_scan_start(rdev, dev); |
3094 | dev_hold(dev); | ||
3095 | } | ||
3080 | 3096 | ||
3081 | out_free: | 3097 | out_free: |
3082 | if (err) { | 3098 | if (err) { |
@@ -3198,11 +3214,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3198 | cb->args[0] = ifidx; | 3214 | cb->args[0] = ifidx; |
3199 | } | 3215 | } |
3200 | 3216 | ||
3201 | dev = dev_get_by_index(&init_net, ifidx); | 3217 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); |
3202 | if (!dev) | 3218 | if (!dev) |
3203 | return -ENODEV; | 3219 | return -ENODEV; |
3204 | 3220 | ||
3205 | rdev = cfg80211_get_dev_from_ifindex(ifidx); | 3221 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
3206 | if (IS_ERR(rdev)) { | 3222 | if (IS_ERR(rdev)) { |
3207 | err = PTR_ERR(rdev); | 3223 | err = PTR_ERR(rdev); |
3208 | goto out_put_netdev; | 3224 | goto out_put_netdev; |
@@ -3312,7 +3328,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3312 | 3328 | ||
3313 | rtnl_lock(); | 3329 | rtnl_lock(); |
3314 | 3330 | ||
3315 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3331 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3316 | if (err) | 3332 | if (err) |
3317 | goto unlock_rtnl; | 3333 | goto unlock_rtnl; |
3318 | 3334 | ||
@@ -3448,7 +3464,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3448 | 3464 | ||
3449 | rtnl_lock(); | 3465 | rtnl_lock(); |
3450 | 3466 | ||
3451 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3467 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3452 | if (err) | 3468 | if (err) |
3453 | goto unlock_rtnl; | 3469 | goto unlock_rtnl; |
3454 | 3470 | ||
@@ -3531,7 +3547,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3531 | 3547 | ||
3532 | rtnl_lock(); | 3548 | rtnl_lock(); |
3533 | 3549 | ||
3534 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3550 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3535 | if (err) | 3551 | if (err) |
3536 | goto unlock_rtnl; | 3552 | goto unlock_rtnl; |
3537 | 3553 | ||
@@ -3593,7 +3609,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3593 | 3609 | ||
3594 | rtnl_lock(); | 3610 | rtnl_lock(); |
3595 | 3611 | ||
3596 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3612 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3597 | if (err) | 3613 | if (err) |
3598 | goto unlock_rtnl; | 3614 | goto unlock_rtnl; |
3599 | 3615 | ||
@@ -3666,7 +3682,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3666 | 3682 | ||
3667 | rtnl_lock(); | 3683 | rtnl_lock(); |
3668 | 3684 | ||
3669 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3685 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3670 | if (err) | 3686 | if (err) |
3671 | goto unlock_rtnl; | 3687 | goto unlock_rtnl; |
3672 | 3688 | ||
@@ -3739,7 +3755,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3739 | 3755 | ||
3740 | rtnl_lock(); | 3756 | rtnl_lock(); |
3741 | 3757 | ||
3742 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3758 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3743 | if (err) | 3759 | if (err) |
3744 | goto unlock_rtnl; | 3760 | goto unlock_rtnl; |
3745 | 3761 | ||
@@ -3924,7 +3940,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
3924 | return err; | 3940 | return err; |
3925 | rtnl_lock(); | 3941 | rtnl_lock(); |
3926 | 3942 | ||
3927 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3943 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3928 | if (err) | 3944 | if (err) |
3929 | goto unlock_rtnl; | 3945 | goto unlock_rtnl; |
3930 | 3946 | ||
@@ -4000,7 +4016,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4000 | 4016 | ||
4001 | rtnl_lock(); | 4017 | rtnl_lock(); |
4002 | 4018 | ||
4003 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 4019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4004 | if (err) | 4020 | if (err) |
4005 | goto unlock_rtnl; | 4021 | goto unlock_rtnl; |
4006 | 4022 | ||
@@ -4024,6 +4040,47 @@ unlock_rtnl: | |||
4024 | return err; | 4040 | return err; |
4025 | } | 4041 | } |
4026 | 4042 | ||
4043 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | ||
4044 | { | ||
4045 | struct cfg80211_registered_device *rdev; | ||
4046 | struct net *net; | ||
4047 | int err; | ||
4048 | u32 pid; | ||
4049 | |||
4050 | if (!info->attrs[NL80211_ATTR_PID]) | ||
4051 | return -EINVAL; | ||
4052 | |||
4053 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | ||
4054 | |||
4055 | rtnl_lock(); | ||
4056 | |||
4057 | rdev = cfg80211_get_dev_from_info(info); | ||
4058 | if (IS_ERR(rdev)) { | ||
4059 | err = PTR_ERR(rdev); | ||
4060 | goto out; | ||
4061 | } | ||
4062 | |||
4063 | net = get_net_ns_by_pid(pid); | ||
4064 | if (IS_ERR(net)) { | ||
4065 | err = PTR_ERR(net); | ||
4066 | goto out; | ||
4067 | } | ||
4068 | |||
4069 | err = 0; | ||
4070 | |||
4071 | /* check if anything to do */ | ||
4072 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | ||
4073 | goto out_put_net; | ||
4074 | |||
4075 | err = cfg80211_switch_netns(rdev, net); | ||
4076 | out_put_net: | ||
4077 | put_net(net); | ||
4078 | out: | ||
4079 | cfg80211_unlock_rdev(rdev); | ||
4080 | rtnl_unlock(); | ||
4081 | return err; | ||
4082 | } | ||
4083 | |||
4027 | static struct genl_ops nl80211_ops[] = { | 4084 | static struct genl_ops nl80211_ops[] = { |
4028 | { | 4085 | { |
4029 | .cmd = NL80211_CMD_GET_WIPHY, | 4086 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4257,6 +4314,12 @@ static struct genl_ops nl80211_ops[] = { | |||
4257 | .policy = nl80211_policy, | 4314 | .policy = nl80211_policy, |
4258 | .flags = GENL_ADMIN_PERM, | 4315 | .flags = GENL_ADMIN_PERM, |
4259 | }, | 4316 | }, |
4317 | { | ||
4318 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | ||
4319 | .doit = nl80211_wiphy_netns, | ||
4320 | .policy = nl80211_policy, | ||
4321 | .flags = GENL_ADMIN_PERM, | ||
4322 | }, | ||
4260 | }; | 4323 | }; |
4261 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4324 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4262 | .name = "mlme", | 4325 | .name = "mlme", |
@@ -4288,7 +4351,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
4288 | return; | 4351 | return; |
4289 | } | 4352 | } |
4290 | 4353 | ||
4291 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 4354 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4355 | nl80211_config_mcgrp.id, GFP_KERNEL); | ||
4292 | } | 4356 | } |
4293 | 4357 | ||
4294 | static int nl80211_add_scan_req(struct sk_buff *msg, | 4358 | static int nl80211_add_scan_req(struct sk_buff *msg, |
@@ -4365,7 +4429,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
4365 | return; | 4429 | return; |
4366 | } | 4430 | } |
4367 | 4431 | ||
4368 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4432 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4433 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4369 | } | 4434 | } |
4370 | 4435 | ||
4371 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 4436 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
@@ -4383,7 +4448,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
4383 | return; | 4448 | return; |
4384 | } | 4449 | } |
4385 | 4450 | ||
4386 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4451 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4452 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4387 | } | 4453 | } |
4388 | 4454 | ||
4389 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 4455 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
@@ -4401,7 +4467,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
4401 | return; | 4467 | return; |
4402 | } | 4468 | } |
4403 | 4469 | ||
4404 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4470 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4471 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4405 | } | 4472 | } |
4406 | 4473 | ||
4407 | /* | 4474 | /* |
@@ -4450,7 +4517,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
4450 | return; | 4517 | return; |
4451 | } | 4518 | } |
4452 | 4519 | ||
4453 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); | 4520 | rtnl_lock(); |
4521 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | ||
4522 | GFP_KERNEL); | ||
4523 | rtnl_unlock(); | ||
4454 | 4524 | ||
4455 | return; | 4525 | return; |
4456 | 4526 | ||
@@ -4486,7 +4556,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
4486 | return; | 4556 | return; |
4487 | } | 4557 | } |
4488 | 4558 | ||
4489 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4559 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4560 | nl80211_mlme_mcgrp.id, gfp); | ||
4490 | return; | 4561 | return; |
4491 | 4562 | ||
4492 | nla_put_failure: | 4563 | nla_put_failure: |
@@ -4553,7 +4624,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | |||
4553 | return; | 4624 | return; |
4554 | } | 4625 | } |
4555 | 4626 | ||
4556 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4627 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4628 | nl80211_mlme_mcgrp.id, gfp); | ||
4557 | return; | 4629 | return; |
4558 | 4630 | ||
4559 | nla_put_failure: | 4631 | nla_put_failure: |
@@ -4611,7 +4683,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
4611 | return; | 4683 | return; |
4612 | } | 4684 | } |
4613 | 4685 | ||
4614 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4686 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4687 | nl80211_mlme_mcgrp.id, gfp); | ||
4615 | return; | 4688 | return; |
4616 | 4689 | ||
4617 | nla_put_failure: | 4690 | nla_put_failure: |
@@ -4651,7 +4724,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
4651 | return; | 4724 | return; |
4652 | } | 4725 | } |
4653 | 4726 | ||
4654 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4727 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4728 | nl80211_mlme_mcgrp.id, gfp); | ||
4655 | return; | 4729 | return; |
4656 | 4730 | ||
4657 | nla_put_failure: | 4731 | nla_put_failure: |
@@ -4691,7 +4765,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
4691 | return; | 4765 | return; |
4692 | } | 4766 | } |
4693 | 4767 | ||
4694 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | 4768 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4769 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
4695 | return; | 4770 | return; |
4696 | 4771 | ||
4697 | nla_put_failure: | 4772 | nla_put_failure: |
@@ -4726,7 +4801,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
4726 | return; | 4801 | return; |
4727 | } | 4802 | } |
4728 | 4803 | ||
4729 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4804 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4805 | nl80211_mlme_mcgrp.id, gfp); | ||
4730 | return; | 4806 | return; |
4731 | 4807 | ||
4732 | nla_put_failure: | 4808 | nla_put_failure: |
@@ -4766,7 +4842,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
4766 | return; | 4842 | return; |
4767 | } | 4843 | } |
4768 | 4844 | ||
4769 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4845 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4846 | nl80211_mlme_mcgrp.id, gfp); | ||
4770 | return; | 4847 | return; |
4771 | 4848 | ||
4772 | nla_put_failure: | 4849 | nla_put_failure: |
@@ -4819,7 +4896,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
4819 | return; | 4896 | return; |
4820 | } | 4897 | } |
4821 | 4898 | ||
4822 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); | 4899 | rcu_read_lock(); |
4900 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | ||
4901 | GFP_ATOMIC); | ||
4902 | rcu_read_unlock(); | ||
4823 | 4903 | ||
4824 | return; | 4904 | return; |
4825 | 4905 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index decc59fe0ee8..1b578b8cb1c9 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -32,9 +32,7 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
32 | mutex_lock(&rdev->mtx); | 32 | mutex_lock(&rdev->mtx); |
33 | request = rdev->scan_req; | 33 | request = rdev->scan_req; |
34 | 34 | ||
35 | dev = dev_get_by_index(&init_net, request->ifidx); | 35 | dev = request->dev; |
36 | if (!dev) | ||
37 | goto out; | ||
38 | 36 | ||
39 | /* | 37 | /* |
40 | * This must be before sending the other events! | 38 | * This must be before sending the other events! |
@@ -58,7 +56,6 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
58 | 56 | ||
59 | dev_put(dev); | 57 | dev_put(dev); |
60 | 58 | ||
61 | out: | ||
62 | cfg80211_unlock_rdev(rdev); | 59 | cfg80211_unlock_rdev(rdev); |
63 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | 60 | wiphy_to_dev(request->wiphy)->scan_req = NULL; |
64 | kfree(request); | 61 | kfree(request); |
@@ -66,17 +63,10 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
66 | 63 | ||
67 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 64 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
68 | { | 65 | { |
69 | struct net_device *dev = dev_get_by_index(&init_net, request->ifidx); | ||
70 | if (WARN_ON(!dev)) { | ||
71 | kfree(request); | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 66 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
76 | 67 | ||
77 | request->aborted = aborted; | 68 | request->aborted = aborted; |
78 | schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); | 69 | schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); |
79 | dev_put(dev); | ||
80 | } | 70 | } |
81 | EXPORT_SYMBOL(cfg80211_scan_done); | 71 | EXPORT_SYMBOL(cfg80211_scan_done); |
82 | 72 | ||
@@ -592,7 +582,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
592 | if (!netif_running(dev)) | 582 | if (!netif_running(dev)) |
593 | return -ENETDOWN; | 583 | return -ENETDOWN; |
594 | 584 | ||
595 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | 585 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
596 | 586 | ||
597 | if (IS_ERR(rdev)) | 587 | if (IS_ERR(rdev)) |
598 | return PTR_ERR(rdev); | 588 | return PTR_ERR(rdev); |
@@ -617,7 +607,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
617 | } | 607 | } |
618 | 608 | ||
619 | creq->wiphy = wiphy; | 609 | creq->wiphy = wiphy; |
620 | creq->ifidx = dev->ifindex; | 610 | creq->dev = dev; |
621 | creq->ssids = (void *)(creq + 1); | 611 | creq->ssids = (void *)(creq + 1); |
622 | creq->channels = (void *)(creq->ssids + 1); | 612 | creq->channels = (void *)(creq->ssids + 1); |
623 | creq->n_channels = n_channels; | 613 | creq->n_channels = n_channels; |
@@ -654,8 +644,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
654 | if (err) { | 644 | if (err) { |
655 | rdev->scan_req = NULL; | 645 | rdev->scan_req = NULL; |
656 | kfree(creq); | 646 | kfree(creq); |
657 | } else | 647 | } else { |
658 | nl80211_send_scan_start(rdev, dev); | 648 | nl80211_send_scan_start(rdev, dev); |
649 | dev_hold(dev); | ||
650 | } | ||
659 | out: | 651 | out: |
660 | cfg80211_unlock_rdev(rdev); | 652 | cfg80211_unlock_rdev(rdev); |
661 | return err; | 653 | return err; |
@@ -948,7 +940,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
948 | if (!netif_running(dev)) | 940 | if (!netif_running(dev)) |
949 | return -ENETDOWN; | 941 | return -ENETDOWN; |
950 | 942 | ||
951 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | 943 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
952 | 944 | ||
953 | if (IS_ERR(rdev)) | 945 | if (IS_ERR(rdev)) |
954 | return PTR_ERR(rdev); | 946 | return PTR_ERR(rdev); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 82de2d9795f4..a19741097989 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -86,7 +86,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
86 | wdev->conn->params.ssid_len); | 86 | wdev->conn->params.ssid_len); |
87 | request->ssids[0].ssid_len = wdev->conn->params.ssid_len; | 87 | request->ssids[0].ssid_len = wdev->conn->params.ssid_len; |
88 | 88 | ||
89 | request->ifidx = wdev->netdev->ifindex; | 89 | request->dev = wdev->netdev; |
90 | request->wiphy = &rdev->wiphy; | 90 | request->wiphy = &rdev->wiphy; |
91 | 91 | ||
92 | rdev->scan_req = request; | 92 | rdev->scan_req = request; |
@@ -95,6 +95,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
95 | if (!err) { | 95 | if (!err) { |
96 | wdev->conn->state = CFG80211_CONN_SCANNING; | 96 | wdev->conn->state = CFG80211_CONN_SCANNING; |
97 | nl80211_send_scan_start(rdev, wdev->netdev); | 97 | nl80211_send_scan_start(rdev, wdev->netdev); |
98 | dev_hold(wdev->netdev); | ||
98 | } else { | 99 | } else { |
99 | rdev->scan_req = NULL; | 100 | rdev->scan_req = NULL; |
100 | kfree(request); | 101 | kfree(request); |