aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/Makefile3
-rw-r--r--net/wireless/chan.c88
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/ibss.c61
-rw-r--r--net/wireless/nl80211.c54
-rw-r--r--net/wireless/sme.c9
-rw-r--r--net/wireless/wext-compat.c55
-rw-r--r--net/wireless/wext-compat.h3
-rw-r--r--net/wireless/wext-sme.c65
9 files changed, 213 insertions, 131 deletions
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index d74cc77fa57a..3ecaa9179977 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,8 @@ 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 nl80211.o mlme.o ibss.o sme.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
9cfg80211-y += mlme.o ibss.o sme.o chan.o
9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 10cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o 11cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
11 12
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
new file mode 100644
index 000000000000..bc00c9a06b3d
--- /dev/null
+++ b/net/wireless/chan.c
@@ -0,0 +1,88 @@
1/*
2 * This file contains helper code to handle channel
3 * settings and keeping track of what is possible at
4 * any point in time.
5 *
6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
7 */
8
9#include <net/cfg80211.h>
10#include "core.h"
11
12struct ieee80211_channel *
13rdev_fixed_channel(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *for_wdev)
15{
16 struct wireless_dev *wdev;
17 struct ieee80211_channel *result = NULL;
18
19 WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
20
21 list_for_each_entry(wdev, &rdev->netdev_list, list) {
22 if (wdev == for_wdev)
23 continue;
24
25 /*
26 * Lock manually to tell lockdep about allowed
27 * nesting here if for_wdev->mtx is held already.
28 * This is ok as it's all under the rdev devlist
29 * mutex and as such can only be done once at any
30 * given time.
31 */
32 mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
33 if (wdev->current_bss)
34 result = wdev->current_bss->pub.channel;
35 wdev_unlock(wdev);
36
37 if (result)
38 break;
39 }
40
41 return result;
42}
43
44int rdev_set_freq(struct cfg80211_registered_device *rdev,
45 int freq, enum nl80211_channel_type channel_type)
46{
47 struct ieee80211_channel *chan;
48 struct ieee80211_sta_ht_cap *ht_cap;
49 int result;
50
51 if (rdev_fixed_channel(rdev, NULL))
52 return -EBUSY;
53
54 if (!rdev->ops->set_channel)
55 return -EOPNOTSUPP;
56
57 chan = ieee80211_get_channel(&rdev->wiphy, freq);
58
59 /* Primary channel not allowed */
60 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
61 return -EINVAL;
62
63 if (channel_type == NL80211_CHAN_HT40MINUS &&
64 chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
65 return -EINVAL;
66 else if (channel_type == NL80211_CHAN_HT40PLUS &&
67 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
68 return -EINVAL;
69
70 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
71
72 if (channel_type != NL80211_CHAN_NO_HT) {
73 if (!ht_cap->ht_supported)
74 return -EINVAL;
75
76 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
77 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
78 return -EINVAL;
79 }
80
81 result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
82 if (result)
83 return result;
84
85 rdev->channel = chan;
86
87 return 0;
88}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 325c17e6198c..5696b95af9be 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -366,4 +366,10 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx);
366void __cfg80211_scan_done(struct work_struct *wk); 366void __cfg80211_scan_done(struct work_struct *wk);
367void cfg80211_upload_connect_keys(struct wireless_dev *wdev); 367void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
368 368
369struct ieee80211_channel *
370rdev_fixed_channel(struct cfg80211_registered_device *rdev,
371 struct wireless_dev *for_wdev);
372int rdev_set_freq(struct cfg80211_registered_device *rdev,
373 int freq, enum nl80211_channel_type channel_type);
374
369#endif /* __NET_WIRELESS_CORE_H */ 375#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 4d7a084b35e2..42840a01be74 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
78 struct cfg80211_cached_keys *connkeys) 78 struct cfg80211_cached_keys *connkeys)
79{ 79{
80 struct wireless_dev *wdev = dev->ieee80211_ptr; 80 struct wireless_dev *wdev = dev->ieee80211_ptr;
81 struct ieee80211_channel *chan;
81 int err; 82 int err;
82 83
83 ASSERT_WDEV_LOCK(wdev); 84 ASSERT_WDEV_LOCK(wdev);
84 85
86 chan = rdev_fixed_channel(rdev, wdev);
87 if (chan && chan != params->channel)
88 return -EBUSY;
89
85 if (wdev->ssid_len) 90 if (wdev->ssid_len)
86 return -EALREADY; 91 return -EALREADY;
87 92
@@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
112 struct wireless_dev *wdev = dev->ieee80211_ptr; 117 struct wireless_dev *wdev = dev->ieee80211_ptr;
113 int err; 118 int err;
114 119
120 mutex_lock(&rdev->devlist_mtx);
115 wdev_lock(wdev); 121 wdev_lock(wdev);
116 err = __cfg80211_join_ibss(rdev, dev, params, connkeys); 122 err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
117 wdev_unlock(wdev); 123 wdev_unlock(wdev);
124 mutex_unlock(&rdev->devlist_mtx);
118 125
119 return err; 126 return err;
120} 127}
@@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
264 271
265int cfg80211_ibss_wext_siwfreq(struct net_device *dev, 272int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
266 struct iw_request_info *info, 273 struct iw_request_info *info,
267 struct iw_freq *freq, char *extra) 274 struct iw_freq *wextfreq, char *extra)
268{ 275{
269 struct wireless_dev *wdev = dev->ieee80211_ptr; 276 struct wireless_dev *wdev = dev->ieee80211_ptr;
270 struct ieee80211_channel *chan; 277 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
271 int err; 278 struct ieee80211_channel *chan = NULL;
279 int err, freq;
272 280
273 /* call only for ibss! */ 281 /* call only for ibss! */
274 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 282 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
275 return -EINVAL; 283 return -EINVAL;
276 284
277 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 285 if (!rdev->ops->join_ibss)
278 return -EOPNOTSUPP; 286 return -EOPNOTSUPP;
279 287
280 chan = cfg80211_wext_freq(wdev->wiphy, freq); 288 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
281 if (chan && IS_ERR(chan)) 289 if (freq < 0)
282 return PTR_ERR(chan); 290 return freq;
283 291
284 if (chan && 292 if (freq) {
285 (chan->flags & IEEE80211_CHAN_NO_IBSS || 293 chan = ieee80211_get_channel(wdev->wiphy, freq);
286 chan->flags & IEEE80211_CHAN_DISABLED)) 294 if (!chan)
287 return -EINVAL; 295 return -EINVAL;
296 if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
297 chan->flags & IEEE80211_CHAN_DISABLED)
298 return -EINVAL;
299 }
288 300
289 if (wdev->wext.ibss.channel == chan) 301 if (wdev->wext.ibss.channel == chan)
290 return 0; 302 return 0;
@@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
292 wdev_lock(wdev); 304 wdev_lock(wdev);
293 err = 0; 305 err = 0;
294 if (wdev->ssid_len) 306 if (wdev->ssid_len)
295 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 307 err = __cfg80211_leave_ibss(rdev, dev, true);
296 dev, true);
297 wdev_unlock(wdev); 308 wdev_unlock(wdev);
298 309
299 if (err) 310 if (err)
@@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
307 wdev->wext.ibss.channel_fixed = false; 318 wdev->wext.ibss.channel_fixed = false;
308 } 319 }
309 320
321 mutex_lock(&rdev->devlist_mtx);
310 wdev_lock(wdev); 322 wdev_lock(wdev);
311 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 323 err = cfg80211_ibss_wext_join(rdev, wdev);
312 wdev_unlock(wdev); 324 wdev_unlock(wdev);
325 mutex_unlock(&rdev->devlist_mtx);
313 326
314 return err; 327 return err;
315} 328}
@@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
347 struct iw_point *data, char *ssid) 360 struct iw_point *data, char *ssid)
348{ 361{
349 struct wireless_dev *wdev = dev->ieee80211_ptr; 362 struct wireless_dev *wdev = dev->ieee80211_ptr;
363 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
350 size_t len = data->length; 364 size_t len = data->length;
351 int err; 365 int err;
352 366
@@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
354 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 368 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
355 return -EINVAL; 369 return -EINVAL;
356 370
357 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 371 if (!rdev->ops->join_ibss)
358 return -EOPNOTSUPP; 372 return -EOPNOTSUPP;
359 373
360 wdev_lock(wdev); 374 wdev_lock(wdev);
361 err = 0; 375 err = 0;
362 if (wdev->ssid_len) 376 if (wdev->ssid_len)
363 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 377 err = __cfg80211_leave_ibss(rdev, dev, true);
364 dev, true);
365 wdev_unlock(wdev); 378 wdev_unlock(wdev);
366 379
367 if (err) 380 if (err)
@@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
375 memcpy(wdev->wext.ibss.ssid, ssid, len); 388 memcpy(wdev->wext.ibss.ssid, ssid, len);
376 wdev->wext.ibss.ssid_len = len; 389 wdev->wext.ibss.ssid_len = len;
377 390
391 mutex_lock(&rdev->devlist_mtx);
378 wdev_lock(wdev); 392 wdev_lock(wdev);
379 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 393 err = cfg80211_ibss_wext_join(rdev, wdev);
380 wdev_unlock(wdev); 394 wdev_unlock(wdev);
395 mutex_unlock(&rdev->devlist_mtx);
381 396
382 return err; 397 return err;
383} 398}
@@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
414 struct sockaddr *ap_addr, char *extra) 429 struct sockaddr *ap_addr, char *extra)
415{ 430{
416 struct wireless_dev *wdev = dev->ieee80211_ptr; 431 struct wireless_dev *wdev = dev->ieee80211_ptr;
432 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
417 u8 *bssid = ap_addr->sa_data; 433 u8 *bssid = ap_addr->sa_data;
418 int err; 434 int err;
419 435
@@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
421 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 437 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
422 return -EINVAL; 438 return -EINVAL;
423 439
424 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 440 if (!rdev->ops->join_ibss)
425 return -EOPNOTSUPP; 441 return -EOPNOTSUPP;
426 442
427 if (ap_addr->sa_family != ARPHRD_ETHER) 443 if (ap_addr->sa_family != ARPHRD_ETHER)
@@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
443 wdev_lock(wdev); 459 wdev_lock(wdev);
444 err = 0; 460 err = 0;
445 if (wdev->ssid_len) 461 if (wdev->ssid_len)
446 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 462 err = __cfg80211_leave_ibss(rdev, dev, true);
447 dev, true);
448 wdev_unlock(wdev); 463 wdev_unlock(wdev);
449 464
450 if (err) 465 if (err)
@@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
456 } else 471 } else
457 wdev->wext.ibss.bssid = NULL; 472 wdev->wext.ibss.bssid = NULL;
458 473
474 mutex_lock(&rdev->devlist_mtx);
459 wdev_lock(wdev); 475 wdev_lock(wdev);
460 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 476 err = cfg80211_ibss_wext_join(rdev, wdev);
461 wdev_unlock(wdev); 477 wdev_unlock(wdev);
478 mutex_unlock(&rdev->devlist_mtx);
462 479
463 return err; 480 return err;
464} 481}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0cd548267d4a..2ff7376f35a3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -701,15 +701,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
701 701
702 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 702 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
703 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 703 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
704 struct ieee80211_channel *chan;
705 struct ieee80211_sta_ht_cap *ht_cap;
706 u32 freq; 704 u32 freq;
707 705
708 if (!rdev->ops->set_channel) {
709 result = -EOPNOTSUPP;
710 goto bad_res;
711 }
712
713 result = -EINVAL; 706 result = -EINVAL;
714 707
715 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { 708 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -723,42 +716,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
723 } 716 }
724 717
725 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 718 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
726 chan = ieee80211_get_channel(&rdev->wiphy, freq);
727
728 /* Primary channel not allowed */
729 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
730 goto bad_res;
731
732 if (channel_type == NL80211_CHAN_HT40MINUS &&
733 (chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
734 goto bad_res;
735 else if (channel_type == NL80211_CHAN_HT40PLUS &&
736 (chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
737 goto bad_res;
738
739 /*
740 * At this point we know if that if HT40 was requested
741 * we are allowed to use it and the extension channel
742 * exists.
743 */
744 719
745 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; 720 mutex_lock(&rdev->devlist_mtx);
746 721 result = rdev_set_freq(rdev, freq, channel_type);
747 /* no HT capabilities or intolerant */ 722 mutex_unlock(&rdev->devlist_mtx);
748 if (channel_type != NL80211_CHAN_NO_HT) {
749 if (!ht_cap->ht_supported)
750 goto bad_res;
751 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
752 (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
753 goto bad_res;
754 }
755
756 result = rdev->ops->set_channel(&rdev->wiphy, chan,
757 channel_type);
758 if (result) 723 if (result)
759 goto bad_res; 724 goto bad_res;
760
761 rdev->channel = chan;
762 } 725 }
763 726
764 changed = 0; 727 changed = 0;
@@ -3453,7 +3416,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3453 struct cfg80211_registered_device *rdev; 3416 struct cfg80211_registered_device *rdev;
3454 struct net_device *dev; 3417 struct net_device *dev;
3455 struct cfg80211_crypto_settings crypto; 3418 struct cfg80211_crypto_settings crypto;
3456 struct ieee80211_channel *chan; 3419 struct ieee80211_channel *chan, *fixedchan;
3457 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; 3420 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3458 int err, ssid_len, ie_len = 0; 3421 int err, ssid_len, ie_len = 0;
3459 bool use_mfp = false; 3422 bool use_mfp = false;
@@ -3496,6 +3459,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3496 goto out; 3459 goto out;
3497 } 3460 }
3498 3461
3462 mutex_lock(&rdev->devlist_mtx);
3463 fixedchan = rdev_fixed_channel(rdev, NULL);
3464 if (fixedchan && chan != fixedchan) {
3465 err = -EBUSY;
3466 mutex_unlock(&rdev->devlist_mtx);
3467 goto out;
3468 }
3469 mutex_unlock(&rdev->devlist_mtx);
3470
3499 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3471 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3500 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3472 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3501 3473
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 340934f714b2..219c3bc2c37d 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -256,9 +256,11 @@ void cfg80211_sme_scan_done(struct net_device *dev)
256{ 256{
257 struct wireless_dev *wdev = dev->ieee80211_ptr; 257 struct wireless_dev *wdev = dev->ieee80211_ptr;
258 258
259 mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
259 wdev_lock(wdev); 260 wdev_lock(wdev);
260 __cfg80211_sme_scan_done(dev); 261 __cfg80211_sme_scan_done(dev);
261 wdev_unlock(wdev); 262 wdev_unlock(wdev);
263 mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
262} 264}
263 265
264void cfg80211_sme_rx_auth(struct net_device *dev, 266void cfg80211_sme_rx_auth(struct net_device *dev,
@@ -644,6 +646,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
644 struct cfg80211_cached_keys *connkeys) 646 struct cfg80211_cached_keys *connkeys)
645{ 647{
646 struct wireless_dev *wdev = dev->ieee80211_ptr; 648 struct wireless_dev *wdev = dev->ieee80211_ptr;
649 struct ieee80211_channel *chan;
647 int err; 650 int err;
648 651
649 ASSERT_WDEV_LOCK(wdev); 652 ASSERT_WDEV_LOCK(wdev);
@@ -651,6 +654,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
651 if (wdev->sme_state != CFG80211_SME_IDLE) 654 if (wdev->sme_state != CFG80211_SME_IDLE)
652 return -EALREADY; 655 return -EALREADY;
653 656
657 chan = rdev_fixed_channel(rdev, wdev);
658 if (chan && chan != connect->channel)
659 return -EBUSY;
660
654 if (WARN_ON(wdev->connect_keys)) { 661 if (WARN_ON(wdev->connect_keys)) {
655 kfree(wdev->connect_keys); 662 kfree(wdev->connect_keys);
656 wdev->connect_keys = NULL; 663 wdev->connect_keys = NULL;
@@ -785,9 +792,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
785{ 792{
786 int err; 793 int err;
787 794
795 mutex_lock(&rdev->devlist_mtx);
788 wdev_lock(dev->ieee80211_ptr); 796 wdev_lock(dev->ieee80211_ptr);
789 err = __cfg80211_connect(rdev, dev, connect, connkeys); 797 err = __cfg80211_connect(rdev, dev, connect, connkeys);
790 wdev_unlock(dev->ieee80211_ptr); 798 wdev_unlock(dev->ieee80211_ptr);
799 mutex_unlock(&rdev->devlist_mtx);
791 800
792 return err; 801 return err;
793} 802}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index e4e90e249bab..17648dc79867 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -267,39 +267,26 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
267 * @wiphy: the wiphy 267 * @wiphy: the wiphy
268 * @freq: the wext freq encoding 268 * @freq: the wext freq encoding
269 * 269 *
270 * Returns a channel, %NULL for auto, or an ERR_PTR for errors! 270 * Returns a frequency, or a negative error code, or 0 for auto.
271 */ 271 */
272struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, 272int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
273 struct iw_freq *freq)
274{ 273{
275 struct ieee80211_channel *chan;
276 int f;
277
278 /* 274 /*
279 * Parse frequency - return NULL for auto and 275 * Parse frequency - return 0 for auto and
280 * -EINVAL for impossible things. 276 * -EINVAL for impossible things.
281 */ 277 */
282 if (freq->e == 0) { 278 if (freq->e == 0) {
283 if (freq->m < 0) 279 if (freq->m < 0)
284 return NULL; 280 return 0;
285 f = ieee80211_channel_to_frequency(freq->m); 281 return ieee80211_channel_to_frequency(freq->m);
286 } else { 282 } else {
287 int i, div = 1000000; 283 int i, div = 1000000;
288 for (i = 0; i < freq->e; i++) 284 for (i = 0; i < freq->e; i++)
289 div /= 10; 285 div /= 10;
290 if (div <= 0) 286 if (div <= 0)
291 return ERR_PTR(-EINVAL); 287 return -EINVAL;
292 f = freq->m / div; 288 return freq->m / div;
293 } 289 }
294
295 /*
296 * Look up channel struct and return -EINVAL when
297 * it cannot be found.
298 */
299 chan = ieee80211_get_channel(wiphy, f);
300 if (!chan)
301 return ERR_PTR(-EINVAL);
302 return chan;
303} 290}
304 291
305int cfg80211_wext_siwrts(struct net_device *dev, 292int cfg80211_wext_siwrts(struct net_device *dev,
@@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
761 748
762int cfg80211_wext_siwfreq(struct net_device *dev, 749int cfg80211_wext_siwfreq(struct net_device *dev,
763 struct iw_request_info *info, 750 struct iw_request_info *info,
764 struct iw_freq *freq, char *extra) 751 struct iw_freq *wextfreq, char *extra)
765{ 752{
766 struct wireless_dev *wdev = dev->ieee80211_ptr; 753 struct wireless_dev *wdev = dev->ieee80211_ptr;
767 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 754 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
768 struct ieee80211_channel *chan; 755 int freq, err;
769 int err;
770 756
771 switch (wdev->iftype) { 757 switch (wdev->iftype) {
772 case NL80211_IFTYPE_STATION: 758 case NL80211_IFTYPE_STATION:
773 return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); 759 return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
774 case NL80211_IFTYPE_ADHOC: 760 case NL80211_IFTYPE_ADHOC:
775 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); 761 return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
776 default: 762 default:
777 chan = cfg80211_wext_freq(wdev->wiphy, freq); 763 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
778 if (!chan) 764 if (freq < 0)
765 return freq;
766 if (freq == 0)
779 return -EINVAL; 767 return -EINVAL;
780 if (IS_ERR(chan)) 768 mutex_lock(&rdev->devlist_mtx);
781 return PTR_ERR(chan); 769 err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
782 err = rdev->ops->set_channel(wdev->wiphy, chan, 770 mutex_unlock(&rdev->devlist_mtx);
783 NL80211_CHAN_NO_HT); 771 return err;
784 if (err)
785 return err;
786 rdev->channel = chan;
787 return 0;
788 } 772 }
789} 773}
790EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
791 774
792int cfg80211_wext_giwfreq(struct net_device *dev, 775int cfg80211_wext_giwfreq(struct net_device *dev,
793 struct iw_request_info *info, 776 struct iw_request_info *info,
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h
index 9a3774749589..20b3daef6964 100644
--- a/net/wireless/wext-compat.h
+++ b/net/wireless/wext-compat.h
@@ -42,8 +42,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
42 struct iw_request_info *info, 42 struct iw_request_info *info,
43 struct iw_point *data, char *ssid); 43 struct iw_point *data, char *ssid);
44 44
45struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, 45int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq);
46 struct iw_freq *freq);
47 46
48 47
49extern const struct iw_handler_def cfg80211_wext_handler; 48extern const struct iw_handler_def cfg80211_wext_handler;
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index e4a054aceb5a..fe1a53639122 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -52,25 +52,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
52 52
53int cfg80211_mgd_wext_siwfreq(struct net_device *dev, 53int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
54 struct iw_request_info *info, 54 struct iw_request_info *info,
55 struct iw_freq *freq, char *extra) 55 struct iw_freq *wextfreq, char *extra)
56{ 56{
57 struct wireless_dev *wdev = dev->ieee80211_ptr; 57 struct wireless_dev *wdev = dev->ieee80211_ptr;
58 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 58 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
59 struct ieee80211_channel *chan; 59 struct ieee80211_channel *chan = NULL;
60 int err; 60 int err, freq;
61 61
62 /* call only for station! */ 62 /* call only for station! */
63 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 63 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
64 return -EINVAL; 64 return -EINVAL;
65 65
66 chan = cfg80211_wext_freq(wdev->wiphy, freq); 66 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
67 if (chan && IS_ERR(chan)) 67 if (freq < 0)
68 return PTR_ERR(chan); 68 return freq;
69 69
70 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) 70 if (freq) {
71 return -EINVAL; 71 chan = ieee80211_get_channel(wdev->wiphy, freq);
72 if (!chan)
73 return -EINVAL;
74 if (chan->flags & IEEE80211_CHAN_DISABLED)
75 return -EINVAL;
76 }
72 77
73 cfg80211_lock_rdev(rdev); 78 cfg80211_lock_rdev(rdev);
79 mutex_lock(&rdev->devlist_mtx);
74 wdev_lock(wdev); 80 wdev_lock(wdev);
75 81
76 if (wdev->sme_state != CFG80211_SME_IDLE) { 82 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -84,9 +90,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
84 /* if SSID set, we'll try right again, avoid event */ 90 /* if SSID set, we'll try right again, avoid event */
85 if (wdev->wext.connect.ssid_len) 91 if (wdev->wext.connect.ssid_len)
86 event = false; 92 event = false;
87 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 93 err = __cfg80211_disconnect(rdev, dev,
88 dev, WLAN_REASON_DEAUTH_LEAVING, 94 WLAN_REASON_DEAUTH_LEAVING, event);
89 event);
90 if (err) 95 if (err)
91 goto out; 96 goto out;
92 } 97 }
@@ -95,17 +100,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
95 wdev->wext.connect.channel = chan; 100 wdev->wext.connect.channel = chan;
96 101
97 /* SSID is not set, we just want to switch channel */ 102 /* SSID is not set, we just want to switch channel */
98 if (wdev->wext.connect.ssid_len && chan) { 103 if (chan && !wdev->wext.connect.ssid_len) {
99 err = -EOPNOTSUPP; 104 err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
100 if (rdev->ops->set_channel)
101 err = rdev->ops->set_channel(wdev->wiphy, chan,
102 NL80211_CHAN_NO_HT);
103 goto out; 105 goto out;
104 } 106 }
105 107
106 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 108 err = cfg80211_mgd_wext_connect(rdev, wdev);
107 out: 109 out:
108 wdev_unlock(wdev); 110 wdev_unlock(wdev);
111 mutex_unlock(&rdev->devlist_mtx);
109 cfg80211_unlock_rdev(rdev); 112 cfg80211_unlock_rdev(rdev);
110 return err; 113 return err;
111} 114}
@@ -143,6 +146,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
143 struct iw_point *data, char *ssid) 146 struct iw_point *data, char *ssid)
144{ 147{
145 struct wireless_dev *wdev = dev->ieee80211_ptr; 148 struct wireless_dev *wdev = dev->ieee80211_ptr;
149 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
146 size_t len = data->length; 150 size_t len = data->length;
147 int err; 151 int err;
148 152
@@ -157,7 +161,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
157 if (len > 0 && ssid[len - 1] == '\0') 161 if (len > 0 && ssid[len - 1] == '\0')
158 len--; 162 len--;
159 163
160 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); 164 cfg80211_lock_rdev(rdev);
165 mutex_lock(&rdev->devlist_mtx);
161 wdev_lock(wdev); 166 wdev_lock(wdev);
162 167
163 err = 0; 168 err = 0;
@@ -173,9 +178,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
173 /* if SSID set now, we'll try to connect, avoid event */ 178 /* if SSID set now, we'll try to connect, avoid event */
174 if (len) 179 if (len)
175 event = false; 180 event = false;
176 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 181 err = __cfg80211_disconnect(rdev, dev,
177 dev, WLAN_REASON_DEAUTH_LEAVING, 182 WLAN_REASON_DEAUTH_LEAVING, event);
178 event);
179 if (err) 183 if (err)
180 goto out; 184 goto out;
181 } 185 }
@@ -186,10 +190,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
186 190
187 wdev->wext.connect.crypto.control_port = false; 191 wdev->wext.connect.crypto.control_port = false;
188 192
189 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 193 err = cfg80211_mgd_wext_connect(rdev, wdev);
190 out: 194 out:
191 wdev_unlock(wdev); 195 wdev_unlock(wdev);
192 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); 196 mutex_unlock(&rdev->devlist_mtx);
197 cfg80211_unlock_rdev(rdev);
193 return err; 198 return err;
194} 199}
195 200
@@ -230,6 +235,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
230 struct sockaddr *ap_addr, char *extra) 235 struct sockaddr *ap_addr, char *extra)
231{ 236{
232 struct wireless_dev *wdev = dev->ieee80211_ptr; 237 struct wireless_dev *wdev = dev->ieee80211_ptr;
238 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
233 u8 *bssid = ap_addr->sa_data; 239 u8 *bssid = ap_addr->sa_data;
234 int err; 240 int err;
235 241
@@ -244,7 +250,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
244 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 250 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
245 bssid = NULL; 251 bssid = NULL;
246 252
247 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); 253 cfg80211_lock_rdev(rdev);
254 mutex_lock(&rdev->devlist_mtx);
248 wdev_lock(wdev); 255 wdev_lock(wdev);
249 256
250 if (wdev->sme_state != CFG80211_SME_IDLE) { 257 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -258,9 +265,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
258 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) 265 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
259 goto out; 266 goto out;
260 267
261 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 268 err = __cfg80211_disconnect(rdev, dev,
262 dev, WLAN_REASON_DEAUTH_LEAVING, 269 WLAN_REASON_DEAUTH_LEAVING, false);
263 false);
264 if (err) 270 if (err)
265 goto out; 271 goto out;
266 } 272 }
@@ -271,10 +277,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
271 } else 277 } else
272 wdev->wext.connect.bssid = NULL; 278 wdev->wext.connect.bssid = NULL;
273 279
274 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 280 err = cfg80211_mgd_wext_connect(rdev, wdev);
275 out: 281 out:
276 wdev_unlock(wdev); 282 wdev_unlock(wdev);
277 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); 283 mutex_unlock(&rdev->devlist_mtx);
284 cfg80211_unlock_rdev(rdev);
278 return err; 285 return err;
279} 286}
280 287