aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-03-27 23:21:18 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-27 23:26:01 -0400
commit82268da1b130f763d22d04f7d016bbf6fc8815c2 (patch)
tree9803f361556d10708313e980428e63a18162e667 /net/wireless
parent6e15cf04860074ad032e88c306bea656bbdd0f22 (diff)
parent5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (diff)
Merge branch 'linus' into percpu-cpumask-x86-for-linus-2
Conflicts: arch/sparc/kernel/time_64.c drivers/gpu/drm/drm_proc.c Manual merge to resolve build warning due to phys_addr_t type change on x86: drivers/gpu/drm/drm_info.c Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig50
-rw-r--r--net/wireless/Makefile3
-rw-r--r--net/wireless/core.c30
-rw-r--r--net/wireless/core.h5
-rw-r--r--net/wireless/mlme.c46
-rw-r--r--net/wireless/nl80211.c824
-rw-r--r--net/wireless/nl80211.h38
-rw-r--r--net/wireless/reg.c65
-rw-r--r--net/wireless/scan.c27
-rw-r--r--net/wireless/wext-compat.c11
10 files changed, 815 insertions, 284 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 092ae6faccca..3c3bc9e579ed 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -10,51 +10,19 @@ config CFG80211_REG_DEBUG
10 10
11 If unsure, say N. 11 If unsure, say N.
12 12
13config NL80211
14 bool "nl80211 new netlink interface support"
15 depends on CFG80211
16 default y
17 ---help---
18 This option turns on the new netlink interface
19 (nl80211) support in cfg80211.
20
21 If =n, drivers using mac80211 will be configured via
22 wireless extension support provided by that subsystem.
23
24 If unsure, say Y.
25
26config WIRELESS_OLD_REGULATORY 13config WIRELESS_OLD_REGULATORY
27 bool "Old wireless static regulatory definitions" 14 bool "Old wireless static regulatory definitions"
28 default y 15 default n
29 ---help--- 16 ---help---
30 This option enables the old static regulatory information 17 This option enables the old static regulatory information
31 and uses it within the new framework. This is available 18 and uses it within the new framework. This option is available
32 temporarily as an option to help prevent immediate issues 19 for historical reasons and it is advised to leave it off.
33 due to the switch to the new regulatory framework which 20
34 does require a new userspace application which has the 21 For details see:
35 database of regulatory information (CRDA) and another for 22
36 setting regulatory domains (iw). 23 http://wireless.kernel.org/en/developers/Regulatory
37 24
38 For more information see: 25 Say N and if you say Y, please tell us why. The default is N.
39
40 http://wireless.kernel.org/en/developers/Regulatory/CRDA
41 http://wireless.kernel.org/en/users/Documentation/iw
42
43 It is important to note though that if you *do* have CRDA present
44 and if this option is enabled CRDA *will* be called to update the
45 regulatory domain (for US and JP only). Support for letting the user
46 set the regulatory domain through iw is also supported. This option
47 mainly exists to leave around for a kernel release some old static
48 regulatory domains that were defined and to keep around the old
49 ieee80211_regdom module parameter. This is being phased out and you
50 should stop using them ASAP.
51
52 Note: You will need CRDA if you want 802.11d support
53
54 Say Y unless you have installed a new userspace application.
55 Also say Y if have one currently depending on the ieee80211_regdom
56 module parameter and cannot port it to use the new userspace
57 interfaces.
58 26
59config WIRELESS_EXT 27config WIRELESS_EXT
60 bool "Wireless extensions" 28 bool "Wireless extensions"
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index dad43c24f695..6d1e7b27b752 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,8 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o
9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
10cfg80211-$(CONFIG_NL80211) += nl80211.o
11 10
12ccflags-y += -D__CHECK_ENDIAN__ 11ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 17fe39049740..d1f556535f6d 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -87,7 +87,7 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
87} 87}
88 88
89/* requires cfg80211_mutex to be held! */ 89/* requires cfg80211_mutex to be held! */
90static struct cfg80211_registered_device * 90struct cfg80211_registered_device *
91__cfg80211_drv_from_info(struct genl_info *info) 91__cfg80211_drv_from_info(struct genl_info *info)
92{ 92{
93 int ifindex; 93 int ifindex;
@@ -176,13 +176,14 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
176 mutex_unlock(&drv->mtx); 176 mutex_unlock(&drv->mtx);
177} 177}
178 178
179/* requires cfg80211_mutex to be held */
179int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, 180int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
180 char *newname) 181 char *newname)
181{ 182{
182 struct cfg80211_registered_device *drv; 183 struct cfg80211_registered_device *drv;
183 int wiphy_idx, taken = -1, result, digits; 184 int wiphy_idx, taken = -1, result, digits;
184 185
185 mutex_lock(&cfg80211_mutex); 186 assert_cfg80211_lock();
186 187
187 /* prohibit calling the thing phy%d when %d is not its number */ 188 /* prohibit calling the thing phy%d when %d is not its number */
188 sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); 189 sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
@@ -195,30 +196,23 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
195 * deny the name if it is phy<idx> where <idx> is printed 196 * deny the name if it is phy<idx> where <idx> is printed
196 * without leading zeroes. taken == strlen(newname) here 197 * without leading zeroes. taken == strlen(newname) here
197 */ 198 */
198 result = -EINVAL;
199 if (taken == strlen(PHY_NAME) + digits) 199 if (taken == strlen(PHY_NAME) + digits)
200 goto out_unlock; 200 return -EINVAL;
201 } 201 }
202 202
203 203
204 /* Ignore nop renames */ 204 /* Ignore nop renames */
205 result = 0;
206 if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) 205 if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
207 goto out_unlock; 206 return 0;
208 207
209 /* Ensure another device does not already have this name. */ 208 /* Ensure another device does not already have this name. */
210 list_for_each_entry(drv, &cfg80211_drv_list, list) { 209 list_for_each_entry(drv, &cfg80211_drv_list, list)
211 result = -EINVAL;
212 if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0) 210 if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
213 goto out_unlock; 211 return -EINVAL;
214 }
215 212
216 /* this will only check for collisions in sysfs
217 * which is not even always compiled in.
218 */
219 result = device_rename(&rdev->wiphy.dev, newname); 213 result = device_rename(&rdev->wiphy.dev, newname);
220 if (result) 214 if (result)
221 goto out_unlock; 215 return result;
222 216
223 if (rdev->wiphy.debugfsdir && 217 if (rdev->wiphy.debugfsdir &&
224 !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, 218 !debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
@@ -228,13 +222,9 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
228 printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", 222 printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
229 newname); 223 newname);
230 224
231 result = 0; 225 nl80211_notify_dev_rename(rdev);
232out_unlock:
233 mutex_unlock(&cfg80211_mutex);
234 if (result == 0)
235 nl80211_notify_dev_rename(rdev);
236 226
237 return result; 227 return 0;
238} 228}
239 229
240/* exported functions */ 230/* exported functions */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6acd483a61f8..d43daa236ef9 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -90,6 +90,8 @@ struct cfg80211_internal_bss {
90 struct rb_node rbn; 90 struct rb_node rbn;
91 unsigned long ts; 91 unsigned long ts;
92 struct kref ref; 92 struct kref ref;
93 bool hold;
94
93 /* must be last because of priv member */ 95 /* must be last because of priv member */
94 struct cfg80211_bss pub; 96 struct cfg80211_bss pub;
95}; 97};
@@ -97,6 +99,9 @@ struct cfg80211_internal_bss {
97struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); 99struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
98int get_wiphy_idx(struct wiphy *wiphy); 100int get_wiphy_idx(struct wiphy *wiphy);
99 101
102struct cfg80211_registered_device *
103__cfg80211_drv_from_info(struct genl_info *info);
104
100/* 105/*
101 * This function returns a pointer to the driver 106 * This function returns a pointer to the driver
102 * that the genl_info item that is passed refers to. 107 * that the genl_info item that is passed refers to.
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
new file mode 100644
index 000000000000..bec5721b6f99
--- /dev/null
+++ b/net/wireless/mlme.c
@@ -0,0 +1,46 @@
1/*
2 * cfg80211 MLME SAP interface
3 *
4 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/netdevice.h>
10#include <linux/nl80211.h>
11#include <net/cfg80211.h>
12#include "core.h"
13#include "nl80211.h"
14
15void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
16{
17 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
18 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
19 nl80211_send_rx_auth(rdev, dev, buf, len);
20}
21EXPORT_SYMBOL(cfg80211_send_rx_auth);
22
23void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
24{
25 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
26 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
27 nl80211_send_rx_assoc(rdev, dev, buf, len);
28}
29EXPORT_SYMBOL(cfg80211_send_rx_assoc);
30
31void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len)
32{
33 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
34 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
35 nl80211_send_rx_deauth(rdev, dev, buf, len);
36}
37EXPORT_SYMBOL(cfg80211_send_rx_deauth);
38
39void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
40 size_t len)
41{
42 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
43 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
44 nl80211_send_rx_disassoc(rdev, dev, buf, len);
45}
46EXPORT_SYMBOL(cfg80211_send_rx_disassoc);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab9d8f14e151..353e1a4ece83 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -111,6 +111,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
111 .len = IEEE80211_MAX_DATA_LEN }, 111 .len = IEEE80211_MAX_DATA_LEN },
112 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, 112 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
113 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, 113 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
114
115 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
116 .len = IEEE80211_MAX_SSID_LEN },
117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
114}; 119};
115 120
116/* message building helper */ 121/* message building helper */
@@ -131,6 +136,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
131 struct nlattr *nl_freqs, *nl_freq; 136 struct nlattr *nl_freqs, *nl_freq;
132 struct nlattr *nl_rates, *nl_rate; 137 struct nlattr *nl_rates, *nl_rate;
133 struct nlattr *nl_modes; 138 struct nlattr *nl_modes;
139 struct nlattr *nl_cmds;
134 enum ieee80211_band band; 140 enum ieee80211_band band;
135 struct ieee80211_channel *chan; 141 struct ieee80211_channel *chan;
136 struct ieee80211_rate *rate; 142 struct ieee80211_rate *rate;
@@ -242,6 +248,35 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
242 } 248 }
243 nla_nest_end(msg, nl_bands); 249 nla_nest_end(msg, nl_bands);
244 250
251 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
252 if (!nl_cmds)
253 goto nla_put_failure;
254
255 i = 0;
256#define CMD(op, n) \
257 do { \
258 if (dev->ops->op) { \
259 i++; \
260 NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \
261 } \
262 } while (0)
263
264 CMD(add_virtual_intf, NEW_INTERFACE);
265 CMD(change_virtual_intf, SET_INTERFACE);
266 CMD(add_key, NEW_KEY);
267 CMD(add_beacon, NEW_BEACON);
268 CMD(add_station, NEW_STATION);
269 CMD(add_mpath, NEW_MPATH);
270 CMD(set_mesh_params, SET_MESH_PARAMS);
271 CMD(change_bss, SET_BSS);
272 CMD(auth, AUTHENTICATE);
273 CMD(assoc, ASSOCIATE);
274 CMD(deauth, DEAUTHENTICATE);
275 CMD(disassoc, DISASSOCIATE);
276
277#undef CMD
278 nla_nest_end(msg, nl_cmds);
279
245 return genlmsg_end(msg, hdr); 280 return genlmsg_end(msg, hdr);
246 281
247 nla_put_failure: 282 nla_put_failure:
@@ -331,16 +366,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
331 int result = 0, rem_txq_params = 0; 366 int result = 0, rem_txq_params = 0;
332 struct nlattr *nl_txq_params; 367 struct nlattr *nl_txq_params;
333 368
334 rdev = cfg80211_get_dev_from_info(info); 369 rtnl_lock();
335 if (IS_ERR(rdev)) 370
336 return PTR_ERR(rdev); 371 mutex_lock(&cfg80211_mutex);
337 372
338 if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { 373 rdev = __cfg80211_drv_from_info(info);
374 if (IS_ERR(rdev)) {
375 result = PTR_ERR(rdev);
376 goto unlock;
377 }
378
379 mutex_lock(&rdev->mtx);
380
381 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
339 result = cfg80211_dev_rename( 382 result = cfg80211_dev_rename(
340 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); 383 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
341 if (result) 384
342 goto bad_res; 385 mutex_unlock(&cfg80211_mutex);
343 } 386
387 if (result)
388 goto bad_res;
344 389
345 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { 390 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
346 struct ieee80211_txq_params txq_params; 391 struct ieee80211_txq_params txq_params;
@@ -436,7 +481,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
436 481
437 482
438 bad_res: 483 bad_res:
439 cfg80211_put_dev(rdev); 484 mutex_unlock(&rdev->mtx);
485 unlock:
486 rtnl_unlock();
440 return result; 487 return result;
441} 488}
442 489
@@ -572,21 +619,31 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
572 enum nl80211_iftype type; 619 enum nl80211_iftype type;
573 struct net_device *dev; 620 struct net_device *dev;
574 u32 _flags, *flags = NULL; 621 u32 _flags, *flags = NULL;
622 bool change = false;
575 623
576 memset(&params, 0, sizeof(params)); 624 memset(&params, 0, sizeof(params));
577 625
626 rtnl_lock();
627
578 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 628 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
579 if (err) 629 if (err)
580 return err; 630 goto unlock_rtnl;
631
581 ifindex = dev->ifindex; 632 ifindex = dev->ifindex;
582 type = dev->ieee80211_ptr->iftype; 633 type = dev->ieee80211_ptr->iftype;
583 dev_put(dev); 634 dev_put(dev);
584 635
585 err = -EINVAL;
586 if (info->attrs[NL80211_ATTR_IFTYPE]) { 636 if (info->attrs[NL80211_ATTR_IFTYPE]) {
587 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); 637 enum nl80211_iftype ntype;
588 if (type > NL80211_IFTYPE_MAX) 638
639 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
640 if (type != ntype)
641 change = true;
642 type = ntype;
643 if (type > NL80211_IFTYPE_MAX) {
644 err = -EINVAL;
589 goto unlock; 645 goto unlock;
646 }
590 } 647 }
591 648
592 if (!drv->ops->change_virtual_intf || 649 if (!drv->ops->change_virtual_intf ||
@@ -602,6 +659,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
602 } 659 }
603 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 660 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
604 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 661 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
662 change = true;
605 } 663 }
606 664
607 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 665 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
@@ -611,20 +669,26 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
611 } 669 }
612 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], 670 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
613 &_flags); 671 &_flags);
614 if (!err) 672 if (err)
615 flags = &_flags; 673 goto unlock;
674
675 flags = &_flags;
676 change = true;
616 } 677 }
617 rtnl_lock(); 678
618 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, 679 if (change)
619 type, flags, &params); 680 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
681 type, flags, &params);
682 else
683 err = 0;
620 684
621 dev = __dev_get_by_index(&init_net, ifindex); 685 dev = __dev_get_by_index(&init_net, ifindex);
622 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); 686 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
623 687
624 rtnl_unlock();
625
626 unlock: 688 unlock:
627 cfg80211_put_dev(drv); 689 cfg80211_put_dev(drv);
690 unlock_rtnl:
691 rtnl_unlock();
628 return err; 692 return err;
629} 693}
630 694
@@ -647,9 +711,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
647 return -EINVAL; 711 return -EINVAL;
648 } 712 }
649 713
714 rtnl_lock();
715
650 drv = cfg80211_get_dev_from_info(info); 716 drv = cfg80211_get_dev_from_info(info);
651 if (IS_ERR(drv)) 717 if (IS_ERR(drv)) {
652 return PTR_ERR(drv); 718 err = PTR_ERR(drv);
719 goto unlock_rtnl;
720 }
653 721
654 if (!drv->ops->add_virtual_intf || 722 if (!drv->ops->add_virtual_intf ||
655 !(drv->wiphy.interface_modes & (1 << type))) { 723 !(drv->wiphy.interface_modes & (1 << type))) {
@@ -663,18 +731,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
663 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 731 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
664 } 732 }
665 733
666 rtnl_lock();
667 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 734 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
668 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 735 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
669 &flags); 736 &flags);
670 err = drv->ops->add_virtual_intf(&drv->wiphy, 737 err = drv->ops->add_virtual_intf(&drv->wiphy,
671 nla_data(info->attrs[NL80211_ATTR_IFNAME]), 738 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
672 type, err ? NULL : &flags, &params); 739 type, err ? NULL : &flags, &params);
673 rtnl_unlock();
674
675 740
676 unlock: 741 unlock:
677 cfg80211_put_dev(drv); 742 cfg80211_put_dev(drv);
743 unlock_rtnl:
744 rtnl_unlock();
678 return err; 745 return err;
679} 746}
680 747
@@ -684,9 +751,11 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
684 int ifindex, err; 751 int ifindex, err;
685 struct net_device *dev; 752 struct net_device *dev;
686 753
754 rtnl_lock();
755
687 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 756 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
688 if (err) 757 if (err)
689 return err; 758 goto unlock_rtnl;
690 ifindex = dev->ifindex; 759 ifindex = dev->ifindex;
691 dev_put(dev); 760 dev_put(dev);
692 761
@@ -695,12 +764,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
695 goto out; 764 goto out;
696 } 765 }
697 766
698 rtnl_lock();
699 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); 767 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
700 rtnl_unlock();
701 768
702 out: 769 out:
703 cfg80211_put_dev(drv); 770 cfg80211_put_dev(drv);
771 unlock_rtnl:
772 rtnl_unlock();
704 return err; 773 return err;
705} 774}
706 775
@@ -752,9 +821,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
752 if (info->attrs[NL80211_ATTR_MAC]) 821 if (info->attrs[NL80211_ATTR_MAC])
753 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 822 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
754 823
824 rtnl_lock();
825
755 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 826 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
756 if (err) 827 if (err)
757 return err; 828 goto unlock_rtnl;
758 829
759 if (!drv->ops->get_key) { 830 if (!drv->ops->get_key) {
760 err = -EOPNOTSUPP; 831 err = -EOPNOTSUPP;
@@ -782,10 +853,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
782 if (mac_addr) 853 if (mac_addr)
783 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); 854 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
784 855
785 rtnl_lock();
786 err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, 856 err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
787 &cookie, get_key_callback); 857 &cookie, get_key_callback);
788 rtnl_unlock();
789 858
790 if (err) 859 if (err)
791 goto out; 860 goto out;
@@ -803,6 +872,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
803 out: 872 out:
804 cfg80211_put_dev(drv); 873 cfg80211_put_dev(drv);
805 dev_put(dev); 874 dev_put(dev);
875 unlock_rtnl:
876 rtnl_unlock();
877
806 return err; 878 return err;
807} 879}
808 880
@@ -831,9 +903,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
831 !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) 903 !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
832 return -EINVAL; 904 return -EINVAL;
833 905
906 rtnl_lock();
907
834 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 908 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
835 if (err) 909 if (err)
836 return err; 910 goto unlock_rtnl;
837 911
838 if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) 912 if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
839 func = drv->ops->set_default_key; 913 func = drv->ops->set_default_key;
@@ -845,13 +919,15 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
845 goto out; 919 goto out;
846 } 920 }
847 921
848 rtnl_lock();
849 err = func(&drv->wiphy, dev, key_idx); 922 err = func(&drv->wiphy, dev, key_idx);
850 rtnl_unlock();
851 923
852 out: 924 out:
853 cfg80211_put_dev(drv); 925 cfg80211_put_dev(drv);
854 dev_put(dev); 926 dev_put(dev);
927
928 unlock_rtnl:
929 rtnl_unlock();
930
855 return err; 931 return err;
856} 932}
857 933
@@ -921,22 +997,25 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
921 return -EINVAL; 997 return -EINVAL;
922 } 998 }
923 999
1000 rtnl_lock();
1001
924 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1002 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
925 if (err) 1003 if (err)
926 return err; 1004 goto unlock_rtnl;
927 1005
928 if (!drv->ops->add_key) { 1006 if (!drv->ops->add_key) {
929 err = -EOPNOTSUPP; 1007 err = -EOPNOTSUPP;
930 goto out; 1008 goto out;
931 } 1009 }
932 1010
933 rtnl_lock();
934 err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params); 1011 err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
935 rtnl_unlock();
936 1012
937 out: 1013 out:
938 cfg80211_put_dev(drv); 1014 cfg80211_put_dev(drv);
939 dev_put(dev); 1015 dev_put(dev);
1016 unlock_rtnl:
1017 rtnl_unlock();
1018
940 return err; 1019 return err;
941} 1020}
942 1021
@@ -957,22 +1036,26 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
957 if (info->attrs[NL80211_ATTR_MAC]) 1036 if (info->attrs[NL80211_ATTR_MAC])
958 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1037 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
959 1038
1039 rtnl_lock();
1040
960 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1041 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
961 if (err) 1042 if (err)
962 return err; 1043 goto unlock_rtnl;
963 1044
964 if (!drv->ops->del_key) { 1045 if (!drv->ops->del_key) {
965 err = -EOPNOTSUPP; 1046 err = -EOPNOTSUPP;
966 goto out; 1047 goto out;
967 } 1048 }
968 1049
969 rtnl_lock();
970 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); 1050 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
971 rtnl_unlock();
972 1051
973 out: 1052 out:
974 cfg80211_put_dev(drv); 1053 cfg80211_put_dev(drv);
975 dev_put(dev); 1054 dev_put(dev);
1055
1056 unlock_rtnl:
1057 rtnl_unlock();
1058
976 return err; 1059 return err;
977} 1060}
978 1061
@@ -986,9 +1069,16 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
986 struct beacon_parameters params; 1069 struct beacon_parameters params;
987 int haveinfo = 0; 1070 int haveinfo = 0;
988 1071
1072 rtnl_lock();
1073
989 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1074 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
990 if (err) 1075 if (err)
991 return err; 1076 goto unlock_rtnl;
1077
1078 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
1079 err = -EOPNOTSUPP;
1080 goto out;
1081 }
992 1082
993 switch (info->genlhdr->cmd) { 1083 switch (info->genlhdr->cmd) {
994 case NL80211_CMD_NEW_BEACON: 1084 case NL80211_CMD_NEW_BEACON:
@@ -1049,13 +1139,14 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
1049 goto out; 1139 goto out;
1050 } 1140 }
1051 1141
1052 rtnl_lock();
1053 err = call(&drv->wiphy, dev, &params); 1142 err = call(&drv->wiphy, dev, &params);
1054 rtnl_unlock();
1055 1143
1056 out: 1144 out:
1057 cfg80211_put_dev(drv); 1145 cfg80211_put_dev(drv);
1058 dev_put(dev); 1146 dev_put(dev);
1147 unlock_rtnl:
1148 rtnl_unlock();
1149
1059 return err; 1150 return err;
1060} 1151}
1061 1152
@@ -1065,22 +1156,29 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
1065 int err; 1156 int err;
1066 struct net_device *dev; 1157 struct net_device *dev;
1067 1158
1159 rtnl_lock();
1160
1068 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1161 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1069 if (err) 1162 if (err)
1070 return err; 1163 goto unlock_rtnl;
1071 1164
1072 if (!drv->ops->del_beacon) { 1165 if (!drv->ops->del_beacon) {
1073 err = -EOPNOTSUPP; 1166 err = -EOPNOTSUPP;
1074 goto out; 1167 goto out;
1075 } 1168 }
1076 1169
1077 rtnl_lock(); 1170 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
1171 err = -EOPNOTSUPP;
1172 goto out;
1173 }
1078 err = drv->ops->del_beacon(&drv->wiphy, dev); 1174 err = drv->ops->del_beacon(&drv->wiphy, dev);
1079 rtnl_unlock();
1080 1175
1081 out: 1176 out:
1082 cfg80211_put_dev(drv); 1177 cfg80211_put_dev(drv);
1083 dev_put(dev); 1178 dev_put(dev);
1179 unlock_rtnl:
1180 rtnl_unlock();
1181
1084 return err; 1182 return err;
1085} 1183}
1086 1184
@@ -1246,30 +1344,32 @@ static int nl80211_dump_station(struct sk_buff *skb,
1246 return -EINVAL; 1344 return -EINVAL;
1247 } 1345 }
1248 1346
1249 netdev = dev_get_by_index(&init_net, ifidx); 1347 rtnl_lock();
1250 if (!netdev) 1348
1251 return -ENODEV; 1349 netdev = __dev_get_by_index(&init_net, ifidx);
1350 if (!netdev) {
1351 err = -ENODEV;
1352 goto out_rtnl;
1353 }
1252 1354
1253 dev = cfg80211_get_dev_from_ifindex(ifidx); 1355 dev = cfg80211_get_dev_from_ifindex(ifidx);
1254 if (IS_ERR(dev)) { 1356 if (IS_ERR(dev)) {
1255 err = PTR_ERR(dev); 1357 err = PTR_ERR(dev);
1256 goto out_put_netdev; 1358 goto out_rtnl;
1257 } 1359 }
1258 1360
1259 if (!dev->ops->dump_station) { 1361 if (!dev->ops->dump_station) {
1260 err = -ENOSYS; 1362 err = -EOPNOTSUPP;
1261 goto out_err; 1363 goto out_err;
1262 } 1364 }
1263 1365
1264 rtnl_lock();
1265
1266 while (1) { 1366 while (1) {
1267 err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, 1367 err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
1268 mac_addr, &sinfo); 1368 mac_addr, &sinfo);
1269 if (err == -ENOENT) 1369 if (err == -ENOENT)
1270 break; 1370 break;
1271 if (err) 1371 if (err)
1272 goto out_err_rtnl; 1372 goto out_err;
1273 1373
1274 if (nl80211_send_station(skb, 1374 if (nl80211_send_station(skb,
1275 NETLINK_CB(cb->skb).pid, 1375 NETLINK_CB(cb->skb).pid,
@@ -1285,12 +1385,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
1285 out: 1385 out:
1286 cb->args[1] = sta_idx; 1386 cb->args[1] = sta_idx;
1287 err = skb->len; 1387 err = skb->len;
1288 out_err_rtnl:
1289 rtnl_unlock();
1290 out_err: 1388 out_err:
1291 cfg80211_put_dev(dev); 1389 cfg80211_put_dev(dev);
1292 out_put_netdev: 1390 out_rtnl:
1293 dev_put(netdev); 1391 rtnl_unlock();
1294 1392
1295 return err; 1393 return err;
1296} 1394}
@@ -1311,19 +1409,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1311 1409
1312 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1410 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1313 1411
1412 rtnl_lock();
1413
1314 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1414 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1315 if (err) 1415 if (err)
1316 return err; 1416 goto out_rtnl;
1317 1417
1318 if (!drv->ops->get_station) { 1418 if (!drv->ops->get_station) {
1319 err = -EOPNOTSUPP; 1419 err = -EOPNOTSUPP;
1320 goto out; 1420 goto out;
1321 } 1421 }
1322 1422
1323 rtnl_lock();
1324 err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); 1423 err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
1325 rtnl_unlock();
1326
1327 if (err) 1424 if (err)
1328 goto out; 1425 goto out;
1329 1426
@@ -1340,10 +1437,12 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1340 1437
1341 out_free: 1438 out_free:
1342 nlmsg_free(msg); 1439 nlmsg_free(msg);
1343
1344 out: 1440 out:
1345 cfg80211_put_dev(drv); 1441 cfg80211_put_dev(drv);
1346 dev_put(dev); 1442 dev_put(dev);
1443 out_rtnl:
1444 rtnl_unlock();
1445
1347 return err; 1446 return err;
1348} 1447}
1349 1448
@@ -1411,9 +1510,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1411 params.plink_action = 1510 params.plink_action =
1412 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); 1511 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
1413 1512
1513 rtnl_lock();
1514
1414 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1515 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1415 if (err) 1516 if (err)
1416 return err; 1517 goto out_rtnl;
1417 1518
1418 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan); 1519 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
1419 if (err) 1520 if (err)
@@ -1424,15 +1525,16 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1424 goto out; 1525 goto out;
1425 } 1526 }
1426 1527
1427 rtnl_lock();
1428 err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params); 1528 err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
1429 rtnl_unlock();
1430 1529
1431 out: 1530 out:
1432 if (params.vlan) 1531 if (params.vlan)
1433 dev_put(params.vlan); 1532 dev_put(params.vlan);
1434 cfg80211_put_dev(drv); 1533 cfg80211_put_dev(drv);
1435 dev_put(dev); 1534 dev_put(dev);
1535 out_rtnl:
1536 rtnl_unlock();
1537
1436 return err; 1538 return err;
1437} 1539}
1438 1540
@@ -1474,9 +1576,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1474 &params.station_flags)) 1576 &params.station_flags))
1475 return -EINVAL; 1577 return -EINVAL;
1476 1578
1579 rtnl_lock();
1580
1477 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1581 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1478 if (err) 1582 if (err)
1479 return err; 1583 goto out_rtnl;
1480 1584
1481 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan); 1585 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
1482 if (err) 1586 if (err)
@@ -1487,15 +1591,21 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1487 goto out; 1591 goto out;
1488 } 1592 }
1489 1593
1490 rtnl_lock(); 1594 if (!netif_running(dev)) {
1595 err = -ENETDOWN;
1596 goto out;
1597 }
1598
1491 err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params); 1599 err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
1492 rtnl_unlock();
1493 1600
1494 out: 1601 out:
1495 if (params.vlan) 1602 if (params.vlan)
1496 dev_put(params.vlan); 1603 dev_put(params.vlan);
1497 cfg80211_put_dev(drv); 1604 cfg80211_put_dev(drv);
1498 dev_put(dev); 1605 dev_put(dev);
1606 out_rtnl:
1607 rtnl_unlock();
1608
1499 return err; 1609 return err;
1500} 1610}
1501 1611
@@ -1509,22 +1619,25 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
1509 if (info->attrs[NL80211_ATTR_MAC]) 1619 if (info->attrs[NL80211_ATTR_MAC])
1510 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1620 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1511 1621
1622 rtnl_lock();
1623
1512 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1624 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1513 if (err) 1625 if (err)
1514 return err; 1626 goto out_rtnl;
1515 1627
1516 if (!drv->ops->del_station) { 1628 if (!drv->ops->del_station) {
1517 err = -EOPNOTSUPP; 1629 err = -EOPNOTSUPP;
1518 goto out; 1630 goto out;
1519 } 1631 }
1520 1632
1521 rtnl_lock();
1522 err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); 1633 err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
1523 rtnl_unlock();
1524 1634
1525 out: 1635 out:
1526 cfg80211_put_dev(drv); 1636 cfg80211_put_dev(drv);
1527 dev_put(dev); 1637 dev_put(dev);
1638 out_rtnl:
1639 rtnl_unlock();
1640
1528 return err; 1641 return err;
1529} 1642}
1530 1643
@@ -1605,22 +1718,29 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
1605 return -EINVAL; 1718 return -EINVAL;
1606 } 1719 }
1607 1720
1608 netdev = dev_get_by_index(&init_net, ifidx); 1721 rtnl_lock();
1609 if (!netdev) 1722
1610 return -ENODEV; 1723 netdev = __dev_get_by_index(&init_net, ifidx);
1724 if (!netdev) {
1725 err = -ENODEV;
1726 goto out_rtnl;
1727 }
1611 1728
1612 dev = cfg80211_get_dev_from_ifindex(ifidx); 1729 dev = cfg80211_get_dev_from_ifindex(ifidx);
1613 if (IS_ERR(dev)) { 1730 if (IS_ERR(dev)) {
1614 err = PTR_ERR(dev); 1731 err = PTR_ERR(dev);
1615 goto out_put_netdev; 1732 goto out_rtnl;
1616 } 1733 }
1617 1734
1618 if (!dev->ops->dump_mpath) { 1735 if (!dev->ops->dump_mpath) {
1619 err = -ENOSYS; 1736 err = -EOPNOTSUPP;
1620 goto out_err; 1737 goto out_err;
1621 } 1738 }
1622 1739
1623 rtnl_lock(); 1740 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
1741 err = -EOPNOTSUPP;
1742 goto out;
1743 }
1624 1744
1625 while (1) { 1745 while (1) {
1626 err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, 1746 err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
@@ -1628,7 +1748,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
1628 if (err == -ENOENT) 1748 if (err == -ENOENT)
1629 break; 1749 break;
1630 if (err) 1750 if (err)
1631 goto out_err_rtnl; 1751 goto out_err;
1632 1752
1633 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, 1753 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid,
1634 cb->nlh->nlmsg_seq, NLM_F_MULTI, 1754 cb->nlh->nlmsg_seq, NLM_F_MULTI,
@@ -1643,12 +1763,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
1643 out: 1763 out:
1644 cb->args[1] = path_idx; 1764 cb->args[1] = path_idx;
1645 err = skb->len; 1765 err = skb->len;
1646 out_err_rtnl:
1647 rtnl_unlock();
1648 out_err: 1766 out_err:
1649 cfg80211_put_dev(dev); 1767 cfg80211_put_dev(dev);
1650 out_put_netdev: 1768 out_rtnl:
1651 dev_put(netdev); 1769 rtnl_unlock();
1652 1770
1653 return err; 1771 return err;
1654} 1772}
@@ -1670,19 +1788,23 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
1670 1788
1671 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1789 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1672 1790
1791 rtnl_lock();
1792
1673 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1793 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1674 if (err) 1794 if (err)
1675 return err; 1795 goto out_rtnl;
1676 1796
1677 if (!drv->ops->get_mpath) { 1797 if (!drv->ops->get_mpath) {
1678 err = -EOPNOTSUPP; 1798 err = -EOPNOTSUPP;
1679 goto out; 1799 goto out;
1680 } 1800 }
1681 1801
1682 rtnl_lock(); 1802 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
1683 err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); 1803 err = -EOPNOTSUPP;
1684 rtnl_unlock(); 1804 goto out;
1805 }
1685 1806
1807 err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
1686 if (err) 1808 if (err)
1687 goto out; 1809 goto out;
1688 1810
@@ -1699,10 +1821,12 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
1699 1821
1700 out_free: 1822 out_free:
1701 nlmsg_free(msg); 1823 nlmsg_free(msg);
1702
1703 out: 1824 out:
1704 cfg80211_put_dev(drv); 1825 cfg80211_put_dev(drv);
1705 dev_put(dev); 1826 dev_put(dev);
1827 out_rtnl:
1828 rtnl_unlock();
1829
1706 return err; 1830 return err;
1707} 1831}
1708 1832
@@ -1723,22 +1847,35 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
1723 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1847 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1724 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1848 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1725 1849
1850 rtnl_lock();
1851
1726 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1852 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1727 if (err) 1853 if (err)
1728 return err; 1854 goto out_rtnl;
1729 1855
1730 if (!drv->ops->change_mpath) { 1856 if (!drv->ops->change_mpath) {
1731 err = -EOPNOTSUPP; 1857 err = -EOPNOTSUPP;
1732 goto out; 1858 goto out;
1733 } 1859 }
1734 1860
1735 rtnl_lock(); 1861 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
1862 err = -EOPNOTSUPP;
1863 goto out;
1864 }
1865
1866 if (!netif_running(dev)) {
1867 err = -ENETDOWN;
1868 goto out;
1869 }
1870
1736 err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); 1871 err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
1737 rtnl_unlock();
1738 1872
1739 out: 1873 out:
1740 cfg80211_put_dev(drv); 1874 cfg80211_put_dev(drv);
1741 dev_put(dev); 1875 dev_put(dev);
1876 out_rtnl:
1877 rtnl_unlock();
1878
1742 return err; 1879 return err;
1743} 1880}
1744static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) 1881static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
@@ -1758,22 +1895,35 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
1758 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1895 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1759 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1896 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1760 1897
1898 rtnl_lock();
1899
1761 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1900 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1762 if (err) 1901 if (err)
1763 return err; 1902 goto out_rtnl;
1764 1903
1765 if (!drv->ops->add_mpath) { 1904 if (!drv->ops->add_mpath) {
1766 err = -EOPNOTSUPP; 1905 err = -EOPNOTSUPP;
1767 goto out; 1906 goto out;
1768 } 1907 }
1769 1908
1770 rtnl_lock(); 1909 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
1910 err = -EOPNOTSUPP;
1911 goto out;
1912 }
1913
1914 if (!netif_running(dev)) {
1915 err = -ENETDOWN;
1916 goto out;
1917 }
1918
1771 err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); 1919 err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
1772 rtnl_unlock();
1773 1920
1774 out: 1921 out:
1775 cfg80211_put_dev(drv); 1922 cfg80211_put_dev(drv);
1776 dev_put(dev); 1923 dev_put(dev);
1924 out_rtnl:
1925 rtnl_unlock();
1926
1777 return err; 1927 return err;
1778} 1928}
1779 1929
@@ -1787,22 +1937,25 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
1787 if (info->attrs[NL80211_ATTR_MAC]) 1937 if (info->attrs[NL80211_ATTR_MAC])
1788 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1938 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1789 1939
1940 rtnl_lock();
1941
1790 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1942 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1791 if (err) 1943 if (err)
1792 return err; 1944 goto out_rtnl;
1793 1945
1794 if (!drv->ops->del_mpath) { 1946 if (!drv->ops->del_mpath) {
1795 err = -EOPNOTSUPP; 1947 err = -EOPNOTSUPP;
1796 goto out; 1948 goto out;
1797 } 1949 }
1798 1950
1799 rtnl_lock();
1800 err = drv->ops->del_mpath(&drv->wiphy, dev, dst); 1951 err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
1801 rtnl_unlock();
1802 1952
1803 out: 1953 out:
1804 cfg80211_put_dev(drv); 1954 cfg80211_put_dev(drv);
1805 dev_put(dev); 1955 dev_put(dev);
1956 out_rtnl:
1957 rtnl_unlock();
1958
1806 return err; 1959 return err;
1807} 1960}
1808 1961
@@ -1835,22 +1988,30 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
1835 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); 1988 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
1836 } 1989 }
1837 1990
1991 rtnl_lock();
1992
1838 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1993 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1839 if (err) 1994 if (err)
1840 return err; 1995 goto out_rtnl;
1841 1996
1842 if (!drv->ops->change_bss) { 1997 if (!drv->ops->change_bss) {
1843 err = -EOPNOTSUPP; 1998 err = -EOPNOTSUPP;
1844 goto out; 1999 goto out;
1845 } 2000 }
1846 2001
1847 rtnl_lock(); 2002 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
2003 err = -EOPNOTSUPP;
2004 goto out;
2005 }
2006
1848 err = drv->ops->change_bss(&drv->wiphy, dev, &params); 2007 err = drv->ops->change_bss(&drv->wiphy, dev, &params);
1849 rtnl_unlock();
1850 2008
1851 out: 2009 out:
1852 cfg80211_put_dev(drv); 2010 cfg80211_put_dev(drv);
1853 dev_put(dev); 2011 dev_put(dev);
2012 out_rtnl:
2013 rtnl_unlock();
2014
1854 return err; 2015 return err;
1855} 2016}
1856 2017
@@ -1945,10 +2106,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
1945 struct nlattr *pinfoattr; 2106 struct nlattr *pinfoattr;
1946 struct sk_buff *msg; 2107 struct sk_buff *msg;
1947 2108
2109 rtnl_lock();
2110
1948 /* Look up our device */ 2111 /* Look up our device */
1949 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2112 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1950 if (err) 2113 if (err)
1951 return err; 2114 goto out_rtnl;
1952 2115
1953 if (!drv->ops->get_mesh_params) { 2116 if (!drv->ops->get_mesh_params) {
1954 err = -EOPNOTSUPP; 2117 err = -EOPNOTSUPP;
@@ -1956,9 +2119,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
1956 } 2119 }
1957 2120
1958 /* Get the mesh params */ 2121 /* Get the mesh params */
1959 rtnl_lock();
1960 err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); 2122 err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
1961 rtnl_unlock();
1962 if (err) 2123 if (err)
1963 goto out; 2124 goto out;
1964 2125
@@ -2007,13 +2168,16 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
2007 err = genlmsg_unicast(msg, info->snd_pid); 2168 err = genlmsg_unicast(msg, info->snd_pid);
2008 goto out; 2169 goto out;
2009 2170
2010nla_put_failure: 2171 nla_put_failure:
2011 genlmsg_cancel(msg, hdr); 2172 genlmsg_cancel(msg, hdr);
2012 err = -EMSGSIZE; 2173 err = -EMSGSIZE;
2013out: 2174 out:
2014 /* Cleanup */ 2175 /* Cleanup */
2015 cfg80211_put_dev(drv); 2176 cfg80211_put_dev(drv);
2016 dev_put(dev); 2177 dev_put(dev);
2178 out_rtnl:
2179 rtnl_unlock();
2180
2017 return err; 2181 return err;
2018} 2182}
2019 2183
@@ -2060,9 +2224,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
2060 parent_attr, nl80211_meshconf_params_policy)) 2224 parent_attr, nl80211_meshconf_params_policy))
2061 return -EINVAL; 2225 return -EINVAL;
2062 2226
2227 rtnl_lock();
2228
2063 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2229 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2064 if (err) 2230 if (err)
2065 return err; 2231 goto out_rtnl;
2066 2232
2067 if (!drv->ops->set_mesh_params) { 2233 if (!drv->ops->set_mesh_params) {
2068 err = -EOPNOTSUPP; 2234 err = -EOPNOTSUPP;
@@ -2109,14 +2275,15 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
2109 nla_get_u16); 2275 nla_get_u16);
2110 2276
2111 /* Apply changes */ 2277 /* Apply changes */
2112 rtnl_lock();
2113 err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); 2278 err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
2114 rtnl_unlock();
2115 2279
2116 out: 2280 out:
2117 /* cleanup */ 2281 /* cleanup */
2118 cfg80211_put_dev(drv); 2282 cfg80211_put_dev(drv);
2119 dev_put(dev); 2283 dev_put(dev);
2284 out_rtnl:
2285 rtnl_unlock();
2286
2120 return err; 2287 return err;
2121} 2288}
2122 2289
@@ -2262,43 +2429,6 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
2262 return -EINVAL; 2429 return -EINVAL;
2263} 2430}
2264 2431
2265static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
2266 struct genl_info *info)
2267{
2268 struct cfg80211_registered_device *drv;
2269 int err;
2270 struct net_device *dev;
2271 struct mgmt_extra_ie_params params;
2272
2273 memset(&params, 0, sizeof(params));
2274
2275 if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE])
2276 return -EINVAL;
2277 params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
2278 if (params.subtype > 15)
2279 return -EINVAL; /* FC Subtype field is 4 bits (0..15) */
2280
2281 if (info->attrs[NL80211_ATTR_IE]) {
2282 params.ies = nla_data(info->attrs[NL80211_ATTR_IE]);
2283 params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2284 }
2285
2286 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2287 if (err)
2288 return err;
2289
2290 if (drv->ops->set_mgmt_extra_ie) {
2291 rtnl_lock();
2292 err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
2293 rtnl_unlock();
2294 } else
2295 err = -EOPNOTSUPP;
2296
2297 cfg80211_put_dev(drv);
2298 dev_put(dev);
2299 return err;
2300}
2301
2302static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) 2432static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2303{ 2433{
2304 struct cfg80211_registered_device *drv; 2434 struct cfg80211_registered_device *drv;
@@ -2312,9 +2442,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2312 enum ieee80211_band band; 2442 enum ieee80211_band band;
2313 size_t ie_len; 2443 size_t ie_len;
2314 2444
2445 rtnl_lock();
2446
2315 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2447 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2316 if (err) 2448 if (err)
2317 return err; 2449 goto out_rtnl;
2318 2450
2319 wiphy = &drv->wiphy; 2451 wiphy = &drv->wiphy;
2320 2452
@@ -2323,11 +2455,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2323 goto out; 2455 goto out;
2324 } 2456 }
2325 2457
2326 rtnl_lock(); 2458 if (!netif_running(dev)) {
2459 err = -ENETDOWN;
2460 goto out;
2461 }
2327 2462
2328 if (drv->scan_req) { 2463 if (drv->scan_req) {
2329 err = -EBUSY; 2464 err = -EBUSY;
2330 goto out_unlock; 2465 goto out;
2331 } 2466 }
2332 2467
2333 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 2468 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
@@ -2335,7 +2470,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2335 n_channels++; 2470 n_channels++;
2336 if (!n_channels) { 2471 if (!n_channels) {
2337 err = -EINVAL; 2472 err = -EINVAL;
2338 goto out_unlock; 2473 goto out;
2339 } 2474 }
2340 } else { 2475 } else {
2341 for (band = 0; band < IEEE80211_NUM_BANDS; band++) 2476 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
@@ -2349,7 +2484,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2349 2484
2350 if (n_ssids > wiphy->max_scan_ssids) { 2485 if (n_ssids > wiphy->max_scan_ssids) {
2351 err = -EINVAL; 2486 err = -EINVAL;
2352 goto out_unlock; 2487 goto out;
2353 } 2488 }
2354 2489
2355 if (info->attrs[NL80211_ATTR_IE]) 2490 if (info->attrs[NL80211_ATTR_IE])
@@ -2363,7 +2498,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2363 + ie_len, GFP_KERNEL); 2498 + ie_len, GFP_KERNEL);
2364 if (!request) { 2499 if (!request) {
2365 err = -ENOMEM; 2500 err = -ENOMEM;
2366 goto out_unlock; 2501 goto out;
2367 } 2502 }
2368 2503
2369 request->channels = (void *)((char *)request + sizeof(*request)); 2504 request->channels = (void *)((char *)request + sizeof(*request));
@@ -2434,11 +2569,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2434 drv->scan_req = NULL; 2569 drv->scan_req = NULL;
2435 kfree(request); 2570 kfree(request);
2436 } 2571 }
2437 out_unlock:
2438 rtnl_unlock();
2439 out: 2572 out:
2440 cfg80211_put_dev(drv); 2573 cfg80211_put_dev(drv);
2441 dev_put(dev); 2574 dev_put(dev);
2575 out_rtnl:
2576 rtnl_unlock();
2577
2442 return err; 2578 return err;
2443} 2579}
2444 2580
@@ -2558,6 +2694,288 @@ static int nl80211_dump_scan(struct sk_buff *skb,
2558 return err; 2694 return err;
2559} 2695}
2560 2696
2697static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
2698{
2699 return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM ||
2700 auth_type == NL80211_AUTHTYPE_SHARED_KEY ||
2701 auth_type == NL80211_AUTHTYPE_FT ||
2702 auth_type == NL80211_AUTHTYPE_NETWORK_EAP;
2703}
2704
2705static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
2706{
2707 struct cfg80211_registered_device *drv;
2708 struct net_device *dev;
2709 struct cfg80211_auth_request req;
2710 struct wiphy *wiphy;
2711 int err;
2712
2713 rtnl_lock();
2714
2715 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2716 if (err)
2717 goto unlock_rtnl;
2718
2719 if (!drv->ops->auth) {
2720 err = -EOPNOTSUPP;
2721 goto out;
2722 }
2723
2724 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
2725 err = -EOPNOTSUPP;
2726 goto out;
2727 }
2728
2729 if (!netif_running(dev)) {
2730 err = -ENETDOWN;
2731 goto out;
2732 }
2733
2734 if (!info->attrs[NL80211_ATTR_MAC]) {
2735 err = -EINVAL;
2736 goto out;
2737 }
2738
2739 wiphy = &drv->wiphy;
2740 memset(&req, 0, sizeof(req));
2741
2742 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2743
2744 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2745 req.chan = ieee80211_get_channel(
2746 wiphy,
2747 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
2748 if (!req.chan) {
2749 err = -EINVAL;
2750 goto out;
2751 }
2752 }
2753
2754 if (info->attrs[NL80211_ATTR_SSID]) {
2755 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2756 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
2757 }
2758
2759 if (info->attrs[NL80211_ATTR_IE]) {
2760 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2761 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2762 }
2763
2764 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2765 req.auth_type =
2766 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
2767 if (!nl80211_valid_auth_type(req.auth_type)) {
2768 err = -EINVAL;
2769 goto out;
2770 }
2771 }
2772
2773 err = drv->ops->auth(&drv->wiphy, dev, &req);
2774
2775out:
2776 cfg80211_put_dev(drv);
2777 dev_put(dev);
2778unlock_rtnl:
2779 rtnl_unlock();
2780 return err;
2781}
2782
2783static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
2784{
2785 struct cfg80211_registered_device *drv;
2786 struct net_device *dev;
2787 struct cfg80211_assoc_request req;
2788 struct wiphy *wiphy;
2789 int err;
2790
2791 rtnl_lock();
2792
2793 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2794 if (err)
2795 goto unlock_rtnl;
2796
2797 if (!drv->ops->assoc) {
2798 err = -EOPNOTSUPP;
2799 goto out;
2800 }
2801
2802 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
2803 err = -EOPNOTSUPP;
2804 goto out;
2805 }
2806
2807 if (!netif_running(dev)) {
2808 err = -ENETDOWN;
2809 goto out;
2810 }
2811
2812 if (!info->attrs[NL80211_ATTR_MAC] ||
2813 !info->attrs[NL80211_ATTR_SSID]) {
2814 err = -EINVAL;
2815 goto out;
2816 }
2817
2818 wiphy = &drv->wiphy;
2819 memset(&req, 0, sizeof(req));
2820
2821 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2822
2823 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2824 req.chan = ieee80211_get_channel(
2825 wiphy,
2826 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
2827 if (!req.chan) {
2828 err = -EINVAL;
2829 goto out;
2830 }
2831 }
2832
2833 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2834 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
2835
2836 if (info->attrs[NL80211_ATTR_IE]) {
2837 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2838 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2839 }
2840
2841 err = drv->ops->assoc(&drv->wiphy, dev, &req);
2842
2843out:
2844 cfg80211_put_dev(drv);
2845 dev_put(dev);
2846unlock_rtnl:
2847 rtnl_unlock();
2848 return err;
2849}
2850
2851static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
2852{
2853 struct cfg80211_registered_device *drv;
2854 struct net_device *dev;
2855 struct cfg80211_deauth_request req;
2856 struct wiphy *wiphy;
2857 int err;
2858
2859 rtnl_lock();
2860
2861 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2862 if (err)
2863 goto unlock_rtnl;
2864
2865 if (!drv->ops->deauth) {
2866 err = -EOPNOTSUPP;
2867 goto out;
2868 }
2869
2870 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
2871 err = -EOPNOTSUPP;
2872 goto out;
2873 }
2874
2875 if (!netif_running(dev)) {
2876 err = -ENETDOWN;
2877 goto out;
2878 }
2879
2880 if (!info->attrs[NL80211_ATTR_MAC]) {
2881 err = -EINVAL;
2882 goto out;
2883 }
2884
2885 wiphy = &drv->wiphy;
2886 memset(&req, 0, sizeof(req));
2887
2888 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2889
2890 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
2891 req.reason_code =
2892 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2893 if (req.reason_code == 0) {
2894 /* Reason Code 0 is reserved */
2895 err = -EINVAL;
2896 goto out;
2897 }
2898 }
2899
2900 if (info->attrs[NL80211_ATTR_IE]) {
2901 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2902 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2903 }
2904
2905 err = drv->ops->deauth(&drv->wiphy, dev, &req);
2906
2907out:
2908 cfg80211_put_dev(drv);
2909 dev_put(dev);
2910unlock_rtnl:
2911 rtnl_unlock();
2912 return err;
2913}
2914
2915static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
2916{
2917 struct cfg80211_registered_device *drv;
2918 struct net_device *dev;
2919 struct cfg80211_disassoc_request req;
2920 struct wiphy *wiphy;
2921 int err;
2922
2923 rtnl_lock();
2924
2925 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2926 if (err)
2927 goto unlock_rtnl;
2928
2929 if (!drv->ops->disassoc) {
2930 err = -EOPNOTSUPP;
2931 goto out;
2932 }
2933
2934 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
2935 err = -EOPNOTSUPP;
2936 goto out;
2937 }
2938
2939 if (!netif_running(dev)) {
2940 err = -ENETDOWN;
2941 goto out;
2942 }
2943
2944 if (!info->attrs[NL80211_ATTR_MAC]) {
2945 err = -EINVAL;
2946 goto out;
2947 }
2948
2949 wiphy = &drv->wiphy;
2950 memset(&req, 0, sizeof(req));
2951
2952 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2953
2954 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
2955 req.reason_code =
2956 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2957 if (req.reason_code == 0) {
2958 /* Reason Code 0 is reserved */
2959 err = -EINVAL;
2960 goto out;
2961 }
2962 }
2963
2964 if (info->attrs[NL80211_ATTR_IE]) {
2965 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2966 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2967 }
2968
2969 err = drv->ops->disassoc(&drv->wiphy, dev, &req);
2970
2971out:
2972 cfg80211_put_dev(drv);
2973 dev_put(dev);
2974unlock_rtnl:
2975 rtnl_unlock();
2976 return err;
2977}
2978
2561static struct genl_ops nl80211_ops[] = { 2979static struct genl_ops nl80211_ops[] = {
2562 { 2980 {
2563 .cmd = NL80211_CMD_GET_WIPHY, 2981 .cmd = NL80211_CMD_GET_WIPHY,
@@ -2725,12 +3143,6 @@ static struct genl_ops nl80211_ops[] = {
2725 .flags = GENL_ADMIN_PERM, 3143 .flags = GENL_ADMIN_PERM,
2726 }, 3144 },
2727 { 3145 {
2728 .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE,
2729 .doit = nl80211_set_mgmt_extra_ie,
2730 .policy = nl80211_policy,
2731 .flags = GENL_ADMIN_PERM,
2732 },
2733 {
2734 .cmd = NL80211_CMD_TRIGGER_SCAN, 3146 .cmd = NL80211_CMD_TRIGGER_SCAN,
2735 .doit = nl80211_trigger_scan, 3147 .doit = nl80211_trigger_scan,
2736 .policy = nl80211_policy, 3148 .policy = nl80211_policy,
@@ -2741,6 +3153,33 @@ static struct genl_ops nl80211_ops[] = {
2741 .policy = nl80211_policy, 3153 .policy = nl80211_policy,
2742 .dumpit = nl80211_dump_scan, 3154 .dumpit = nl80211_dump_scan,
2743 }, 3155 },
3156 {
3157 .cmd = NL80211_CMD_AUTHENTICATE,
3158 .doit = nl80211_authenticate,
3159 .policy = nl80211_policy,
3160 .flags = GENL_ADMIN_PERM,
3161 },
3162 {
3163 .cmd = NL80211_CMD_ASSOCIATE,
3164 .doit = nl80211_associate,
3165 .policy = nl80211_policy,
3166 .flags = GENL_ADMIN_PERM,
3167 },
3168 {
3169 .cmd = NL80211_CMD_DEAUTHENTICATE,
3170 .doit = nl80211_deauthenticate,
3171 .policy = nl80211_policy,
3172 .flags = GENL_ADMIN_PERM,
3173 },
3174 {
3175 .cmd = NL80211_CMD_DISASSOCIATE,
3176 .doit = nl80211_disassociate,
3177 .policy = nl80211_policy,
3178 .flags = GENL_ADMIN_PERM,
3179 },
3180};
3181static struct genl_multicast_group nl80211_mlme_mcgrp = {
3182 .name = "mlme",
2744}; 3183};
2745 3184
2746/* multicast groups */ 3185/* multicast groups */
@@ -2887,6 +3326,71 @@ nla_put_failure:
2887 nlmsg_free(msg); 3326 nlmsg_free(msg);
2888} 3327}
2889 3328
3329static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
3330 struct net_device *netdev,
3331 const u8 *buf, size_t len,
3332 enum nl80211_commands cmd)
3333{
3334 struct sk_buff *msg;
3335 void *hdr;
3336
3337 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
3338 if (!msg)
3339 return;
3340
3341 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
3342 if (!hdr) {
3343 nlmsg_free(msg);
3344 return;
3345 }
3346
3347 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
3348 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
3349 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
3350
3351 if (genlmsg_end(msg, hdr) < 0) {
3352 nlmsg_free(msg);
3353 return;
3354 }
3355
3356 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
3357 return;
3358
3359 nla_put_failure:
3360 genlmsg_cancel(msg, hdr);
3361 nlmsg_free(msg);
3362}
3363
3364void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
3365 struct net_device *netdev, const u8 *buf, size_t len)
3366{
3367 nl80211_send_mlme_event(rdev, netdev, buf, len,
3368 NL80211_CMD_AUTHENTICATE);
3369}
3370
3371void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
3372 struct net_device *netdev, const u8 *buf,
3373 size_t len)
3374{
3375 nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
3376}
3377
3378void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
3379 struct net_device *netdev, const u8 *buf,
3380 size_t len)
3381{
3382 nl80211_send_mlme_event(rdev, netdev, buf, len,
3383 NL80211_CMD_DEAUTHENTICATE);
3384}
3385
3386void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
3387 struct net_device *netdev, const u8 *buf,
3388 size_t len)
3389{
3390 nl80211_send_mlme_event(rdev, netdev, buf, len,
3391 NL80211_CMD_DISASSOCIATE);
3392}
3393
2890/* initialisation/exit functions */ 3394/* initialisation/exit functions */
2891 3395
2892int nl80211_init(void) 3396int nl80211_init(void)
@@ -2915,6 +3419,10 @@ int nl80211_init(void)
2915 if (err) 3419 if (err)
2916 goto err_out; 3420 goto err_out;
2917 3421
3422 err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp);
3423 if (err)
3424 goto err_out;
3425
2918 return 0; 3426 return 0;
2919 err_out: 3427 err_out:
2920 genl_unregister_family(&nl80211_fam); 3428 genl_unregister_family(&nl80211_fam);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e65a3c38c52f..b77af4ab80be 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -3,7 +3,6 @@
3 3
4#include "core.h" 4#include "core.h"
5 5
6#ifdef CONFIG_NL80211
7extern int nl80211_init(void); 6extern int nl80211_init(void);
8extern void nl80211_exit(void); 7extern void nl80211_exit(void);
9extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); 8extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
@@ -12,30 +11,17 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
12extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, 11extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
13 struct net_device *netdev); 12 struct net_device *netdev);
14extern void nl80211_send_reg_change_event(struct regulatory_request *request); 13extern void nl80211_send_reg_change_event(struct regulatory_request *request);
15#else 14extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
16static inline int nl80211_init(void) 15 struct net_device *netdev,
17{ 16 const u8 *buf, size_t len);
18 return 0; 17extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
19} 18 struct net_device *netdev,
20static inline void nl80211_exit(void) 19 const u8 *buf, size_t len);
21{ 20extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
22} 21 struct net_device *netdev,
23static inline void nl80211_notify_dev_rename( 22 const u8 *buf, size_t len);
24 struct cfg80211_registered_device *rdev) 23extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
25{ 24 struct net_device *netdev,
26} 25 const u8 *buf, size_t len);
27static inline void
28nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
29 struct net_device *netdev)
30{}
31static inline void nl80211_send_scan_aborted(
32 struct cfg80211_registered_device *rdev,
33 struct net_device *netdev)
34{}
35static inline void
36nl80211_send_reg_change_event(struct regulatory_request *request)
37{
38}
39#endif /* CONFIG_NL80211 */
40 26
41#endif /* __NET_WIRELESS_NL80211_H */ 27#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index eb8b8ed16155..6327e1617acb 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -122,9 +122,14 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom =
122 122
123#ifdef CONFIG_WIRELESS_OLD_REGULATORY 123#ifdef CONFIG_WIRELESS_OLD_REGULATORY
124static char *ieee80211_regdom = "US"; 124static char *ieee80211_regdom = "US";
125#else
126static char *ieee80211_regdom = "00";
127#endif
128
125module_param(ieee80211_regdom, charp, 0444); 129module_param(ieee80211_regdom, charp, 0444);
126MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); 130MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
127 131
132#ifdef CONFIG_WIRELESS_OLD_REGULATORY
128/* 133/*
129 * We assume 40 MHz bandwidth for the old regulatory work. 134 * We assume 40 MHz bandwidth for the old regulatory work.
130 * We make emphasis we are using the exact same frequencies 135 * We make emphasis we are using the exact same frequencies
@@ -1415,16 +1420,6 @@ new_request:
1415 return r; 1420 return r;
1416 } 1421 }
1417 1422
1418 /*
1419 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
1420 * AND if CRDA is NOT present nothing will happen, if someone
1421 * wants to bother with 11d with OLD_REG you can add a timer.
1422 * If after x amount of time nothing happens you can call:
1423 *
1424 * return set_regdom(country_ie_regdomain);
1425 *
1426 * to intersect with the static rd
1427 */
1428 return call_crda(last_request->alpha2); 1423 return call_crda(last_request->alpha2);
1429} 1424}
1430 1425
@@ -1601,6 +1596,10 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
1601 1596
1602 assert_cfg80211_lock(); 1597 assert_cfg80211_lock();
1603 1598
1599 if (unlikely(last_request->initiator !=
1600 NL80211_REGDOM_SET_BY_COUNTRY_IE))
1601 return false;
1602
1604 request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 1603 request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
1605 1604
1606 if (!request_wiphy) 1605 if (!request_wiphy)
@@ -1663,7 +1662,9 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1663 * we optimize an early check to exit out early if we don't have to 1662 * we optimize an early check to exit out early if we don't have to
1664 * do anything 1663 * do anything
1665 */ 1664 */
1666 if (likely(wiphy_idx_valid(last_request->wiphy_idx))) { 1665 if (likely(last_request->initiator ==
1666 NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1667 wiphy_idx_valid(last_request->wiphy_idx))) {
1667 struct cfg80211_registered_device *drv_last_ie; 1668 struct cfg80211_registered_device *drv_last_ie;
1668 1669
1669 drv_last_ie = 1670 drv_last_ie =
@@ -2022,28 +2023,21 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2022 */ 2023 */
2023 2024
2024 BUG_ON(!country_ie_regdomain); 2025 BUG_ON(!country_ie_regdomain);
2026 BUG_ON(rd == country_ie_regdomain);
2025 2027
2026 if (rd != country_ie_regdomain) { 2028 /*
2027 /* 2029 * Intersect what CRDA returned and our what we
2028 * Intersect what CRDA returned and our what we 2030 * had built from the Country IE received
2029 * had built from the Country IE received 2031 */
2030 */
2031 2032
2032 intersected_rd = regdom_intersect(rd, country_ie_regdomain); 2033 intersected_rd = regdom_intersect(rd, country_ie_regdomain);
2033 2034
2034 reg_country_ie_process_debug(rd, country_ie_regdomain, 2035 reg_country_ie_process_debug(rd,
2035 intersected_rd); 2036 country_ie_regdomain,
2037 intersected_rd);
2036 2038
2037 kfree(country_ie_regdomain); 2039 kfree(country_ie_regdomain);
2038 country_ie_regdomain = NULL; 2040 country_ie_regdomain = NULL;
2039 } else {
2040 /*
2041 * This would happen when CRDA was not present and
2042 * OLD_REGULATORY was enabled. We intersect our Country
2043 * IE rd and what was set on cfg80211 originally
2044 */
2045 intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
2046 }
2047 2041
2048 if (!intersected_rd) 2042 if (!intersected_rd)
2049 return -EINVAL; 2043 return -EINVAL;
@@ -2135,15 +2129,18 @@ int regulatory_init(void)
2135 /* 2129 /*
2136 * The old code still requests for a new regdomain and if 2130 * The old code still requests for a new regdomain and if
2137 * you have CRDA you get it updated, otherwise you get 2131 * you have CRDA you get it updated, otherwise you get
2138 * stuck with the static values. We ignore "EU" code as 2132 * stuck with the static values. Since "EU" is not a valid
2139 * that is not a valid ISO / IEC 3166 alpha2 2133 * ISO / IEC 3166 alpha2 code we can't expect userpace to
2134 * give us a regulatory domain for it. We need last_request
2135 * iniitalized though so lets just send a request which we
2136 * know will be ignored... this crap will be removed once
2137 * OLD_REG dies.
2140 */ 2138 */
2141 if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') 2139 err = regulatory_hint_core(ieee80211_regdom);
2142 err = regulatory_hint_core(ieee80211_regdom);
2143#else 2140#else
2144 cfg80211_regdomain = cfg80211_world_regdom; 2141 cfg80211_regdomain = cfg80211_world_regdom;
2145 2142
2146 err = regulatory_hint_core("00"); 2143 err = regulatory_hint_core(ieee80211_regdom);
2147#endif 2144#endif
2148 if (err) { 2145 if (err) {
2149 if (err == -ENOMEM) 2146 if (err == -ENOMEM)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 280dbcd02c15..2a00e362f5fe 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -80,7 +80,8 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
80 bool expired = false; 80 bool expired = false;
81 81
82 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { 82 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
83 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) 83 if (bss->hold ||
84 !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
84 continue; 85 continue;
85 list_del(&bss->list); 86 list_del(&bss->list);
86 rb_erase(&bss->rbn, &dev->bss_tree); 87 rb_erase(&bss->rbn, &dev->bss_tree);
@@ -471,6 +472,30 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
471} 472}
472EXPORT_SYMBOL(cfg80211_unlink_bss); 473EXPORT_SYMBOL(cfg80211_unlink_bss);
473 474
475void cfg80211_hold_bss(struct cfg80211_bss *pub)
476{
477 struct cfg80211_internal_bss *bss;
478
479 if (!pub)
480 return;
481
482 bss = container_of(pub, struct cfg80211_internal_bss, pub);
483 bss->hold = true;
484}
485EXPORT_SYMBOL(cfg80211_hold_bss);
486
487void cfg80211_unhold_bss(struct cfg80211_bss *pub)
488{
489 struct cfg80211_internal_bss *bss;
490
491 if (!pub)
492 return;
493
494 bss = container_of(pub, struct cfg80211_internal_bss, pub);
495 bss->hold = false;
496}
497EXPORT_SYMBOL(cfg80211_unhold_bss);
498
474#ifdef CONFIG_WIRELESS_EXT 499#ifdef CONFIG_WIRELESS_EXT
475int cfg80211_wext_siwscan(struct net_device *dev, 500int cfg80211_wext_siwscan(struct net_device *dev,
476 struct iw_request_info *info, 501 struct iw_request_info *info,
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index b84a9b4fe96a..0fd1db6e95bb 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -66,6 +66,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
66 struct cfg80211_registered_device *rdev; 66 struct cfg80211_registered_device *rdev;
67 struct vif_params vifparams; 67 struct vif_params vifparams;
68 enum nl80211_iftype type; 68 enum nl80211_iftype type;
69 int ret;
69 70
70 if (!wdev) 71 if (!wdev)
71 return -EOPNOTSUPP; 72 return -EOPNOTSUPP;
@@ -96,10 +97,16 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
96 return -EINVAL; 97 return -EINVAL;
97 } 98 }
98 99
100 if (type == wdev->iftype)
101 return 0;
102
99 memset(&vifparams, 0, sizeof(vifparams)); 103 memset(&vifparams, 0, sizeof(vifparams));
100 104
101 return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, 105 ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
102 NULL, &vifparams); 106 NULL, &vifparams);
107 WARN_ON(!ret && wdev->iftype != type);
108
109 return ret;
103} 110}
104EXPORT_SYMBOL(cfg80211_wext_siwmode); 111EXPORT_SYMBOL(cfg80211_wext_siwmode);
105 112