diff options
-rw-r--r-- | net/wireless/Makefile | 3 | ||||
-rw-r--r-- | net/wireless/chan.c | 88 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/ibss.c | 61 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 54 | ||||
-rw-r--r-- | net/wireless/sme.c | 9 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 55 | ||||
-rw-r--r-- | net/wireless/wext-compat.h | 3 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 65 |
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 | |||
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 nl80211.o mlme.o ibss.o sme.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
9 | cfg80211-y += mlme.o ibss.o sme.o chan.o | ||
9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 10 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o | 11 | cfg80211-$(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 | |||
12 | struct ieee80211_channel * | ||
13 | rdev_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 | |||
44 | int 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); | |||
366 | void __cfg80211_scan_done(struct work_struct *wk); | 366 | void __cfg80211_scan_done(struct work_struct *wk); |
367 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 367 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
368 | 368 | ||
369 | struct ieee80211_channel * | ||
370 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
371 | struct wireless_dev *for_wdev); | ||
372 | int 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 | ||
265 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | 272 | int 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 | ||
264 | void cfg80211_sme_rx_auth(struct net_device *dev, | 266 | void 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 | */ |
272 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 272 | int 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 | ||
305 | int cfg80211_wext_siwrts(struct net_device *dev, | 292 | int cfg80211_wext_siwrts(struct net_device *dev, |
@@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | |||
761 | 748 | ||
762 | int cfg80211_wext_siwfreq(struct net_device *dev, | 749 | int 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 | } |
790 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); | ||
791 | 774 | ||
792 | int cfg80211_wext_giwfreq(struct net_device *dev, | 775 | int 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 | ||
45 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 45 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); |
46 | struct iw_freq *freq); | ||
47 | 46 | ||
48 | 47 | ||
49 | extern const struct iw_handler_def cfg80211_wext_handler; | 48 | extern 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 | ||
53 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | 53 | int 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 | ||