diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-03-27 23:21:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-27 23:26:01 -0400 |
commit | 82268da1b130f763d22d04f7d016bbf6fc8815c2 (patch) | |
tree | 9803f361556d10708313e980428e63a18162e667 /net/wireless | |
parent | 6e15cf04860074ad032e88c306bea656bbdd0f22 (diff) | |
parent | 5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (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/Kconfig | 50 | ||||
-rw-r--r-- | net/wireless/Makefile | 3 | ||||
-rw-r--r-- | net/wireless/core.c | 30 | ||||
-rw-r--r-- | net/wireless/core.h | 5 | ||||
-rw-r--r-- | net/wireless/mlme.c | 46 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 824 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 38 | ||||
-rw-r--r-- | net/wireless/reg.c | 65 | ||||
-rw-r--r-- | net/wireless/scan.c | 27 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 11 |
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 | ||
13 | config 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 | |||
26 | config WIRELESS_OLD_REGULATORY | 13 | config 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 | ||
59 | config WIRELESS_EXT | 27 | config 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 | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | cfg80211-$(CONFIG_NL80211) += nl80211.o | ||
11 | 10 | ||
12 | ccflags-y += -D__CHECK_ENDIAN__ | 11 | ccflags-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! */ |
90 | static struct cfg80211_registered_device * | 90 | struct 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 */ | ||
179 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 180 | int 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); |
232 | out_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 { | |||
97 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | 99 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); |
98 | int get_wiphy_idx(struct wiphy *wiphy); | 100 | int get_wiphy_idx(struct wiphy *wiphy); |
99 | 101 | ||
102 | struct 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 | |||
15 | void 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 | } | ||
21 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | ||
22 | |||
23 | void 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 | } | ||
29 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | ||
30 | |||
31 | void 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 | } | ||
37 | EXPORT_SYMBOL(cfg80211_send_rx_deauth); | ||
38 | |||
39 | void 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 | } | ||
46 | EXPORT_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(¶ms, 0, sizeof(params)); | 624 | memset(¶ms, 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, ¶ms); | 680 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
681 | type, flags, ¶ms); | ||
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, ¶ms); | 739 | type, err ? NULL : &flags, ¶ms); |
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, ¶ms); | 1011 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); |
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, ¶ms); | 1142 | err = call(&drv->wiphy, dev, ¶ms); |
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, ¶ms.vlan); | 1519 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.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, ¶ms); | 1528 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); |
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 | ¶ms.station_flags)) | 1576 | ¶ms.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, ¶ms.vlan); | 1585 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.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, ¶ms); | 1599 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); |
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 | } |
1744 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 1881 | static 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, ¶ms); | 2007 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); |
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 | ||
2010 | nla_put_failure: | 2171 | nla_put_failure: |
2011 | genlmsg_cancel(msg, hdr); | 2172 | genlmsg_cancel(msg, hdr); |
2012 | err = -EMSGSIZE; | 2173 | err = -EMSGSIZE; |
2013 | out: | 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 | ||
2265 | static 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(¶ms, 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, ¶ms); | ||
2293 | rtnl_unlock(); | ||
2294 | } else | ||
2295 | err = -EOPNOTSUPP; | ||
2296 | |||
2297 | cfg80211_put_dev(drv); | ||
2298 | dev_put(dev); | ||
2299 | return err; | ||
2300 | } | ||
2301 | |||
2302 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2432 | static 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 | ||
2697 | static 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 | |||
2705 | static 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 | |||
2775 | out: | ||
2776 | cfg80211_put_dev(drv); | ||
2777 | dev_put(dev); | ||
2778 | unlock_rtnl: | ||
2779 | rtnl_unlock(); | ||
2780 | return err; | ||
2781 | } | ||
2782 | |||
2783 | static 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 | |||
2843 | out: | ||
2844 | cfg80211_put_dev(drv); | ||
2845 | dev_put(dev); | ||
2846 | unlock_rtnl: | ||
2847 | rtnl_unlock(); | ||
2848 | return err; | ||
2849 | } | ||
2850 | |||
2851 | static 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 | |||
2907 | out: | ||
2908 | cfg80211_put_dev(drv); | ||
2909 | dev_put(dev); | ||
2910 | unlock_rtnl: | ||
2911 | rtnl_unlock(); | ||
2912 | return err; | ||
2913 | } | ||
2914 | |||
2915 | static 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 | |||
2971 | out: | ||
2972 | cfg80211_put_dev(drv); | ||
2973 | dev_put(dev); | ||
2974 | unlock_rtnl: | ||
2975 | rtnl_unlock(); | ||
2976 | return err; | ||
2977 | } | ||
2978 | |||
2561 | static struct genl_ops nl80211_ops[] = { | 2979 | static 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 | }; | ||
3181 | static 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 | ||
3329 | static 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 | |||
3364 | void 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 | |||
3371 | void 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 | |||
3378 | void 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 | |||
3386 | void 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 | ||
2892 | int nl80211_init(void) | 3396 | int 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 | ||
7 | extern int nl80211_init(void); | 6 | extern int nl80211_init(void); |
8 | extern void nl80211_exit(void); | 7 | extern void nl80211_exit(void); |
9 | extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); | 8 | extern 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, | |||
12 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 11 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
13 | struct net_device *netdev); | 12 | struct net_device *netdev); |
14 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); | 13 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); |
15 | #else | 14 | extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
16 | static inline int nl80211_init(void) | 15 | struct net_device *netdev, |
17 | { | 16 | const u8 *buf, size_t len); |
18 | return 0; | 17 | extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, |
19 | } | 18 | struct net_device *netdev, |
20 | static inline void nl80211_exit(void) | 19 | const u8 *buf, size_t len); |
21 | { | 20 | extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, |
22 | } | 21 | struct net_device *netdev, |
23 | static inline void nl80211_notify_dev_rename( | 22 | const u8 *buf, size_t len); |
24 | struct cfg80211_registered_device *rdev) | 23 | extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, |
25 | { | 24 | struct net_device *netdev, |
26 | } | 25 | const u8 *buf, size_t len); |
27 | static inline void | ||
28 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | ||
29 | struct net_device *netdev) | ||
30 | {} | ||
31 | static inline void nl80211_send_scan_aborted( | ||
32 | struct cfg80211_registered_device *rdev, | ||
33 | struct net_device *netdev) | ||
34 | {} | ||
35 | static inline void | ||
36 | nl80211_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 |
124 | static char *ieee80211_regdom = "US"; | 124 | static char *ieee80211_regdom = "US"; |
125 | #else | ||
126 | static char *ieee80211_regdom = "00"; | ||
127 | #endif | ||
128 | |||
125 | module_param(ieee80211_regdom, charp, 0444); | 129 | module_param(ieee80211_regdom, charp, 0444); |
126 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 130 | MODULE_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 | } |
472 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 473 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
473 | 474 | ||
475 | void 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 | } | ||
485 | EXPORT_SYMBOL(cfg80211_hold_bss); | ||
486 | |||
487 | void 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 | } | ||
497 | EXPORT_SYMBOL(cfg80211_unhold_bss); | ||
498 | |||
474 | #ifdef CONFIG_WIRELESS_EXT | 499 | #ifdef CONFIG_WIRELESS_EXT |
475 | int cfg80211_wext_siwscan(struct net_device *dev, | 500 | int 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 | } |
104 | EXPORT_SYMBOL(cfg80211_wext_siwmode); | 111 | EXPORT_SYMBOL(cfg80211_wext_siwmode); |
105 | 112 | ||