diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Makefile | 3 | ||||
-rw-r--r-- | net/wireless/chan.c | 89 | ||||
-rw-r--r-- | net/wireless/core.c | 21 | ||||
-rw-r--r-- | net/wireless/core.h | 14 | ||||
-rw-r--r-- | net/wireless/ibss.c | 61 | ||||
-rw-r--r-- | net/wireless/mlme.c | 17 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 88 | ||||
-rw-r--r-- | net/wireless/reg.c | 5 | ||||
-rw-r--r-- | net/wireless/scan.c | 31 | ||||
-rw-r--r-- | net/wireless/sme.c | 104 | ||||
-rw-r--r-- | net/wireless/util.c | 16 | ||||
-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 | 83 |
14 files changed, 403 insertions, 187 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..a46ac6c9b365 --- /dev/null +++ b/net/wireless/chan.c | |||
@@ -0,0 +1,89 @@ | |||
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 | struct wireless_dev *for_wdev, | ||
46 | int freq, enum nl80211_channel_type channel_type) | ||
47 | { | ||
48 | struct ieee80211_channel *chan; | ||
49 | struct ieee80211_sta_ht_cap *ht_cap; | ||
50 | int result; | ||
51 | |||
52 | if (rdev_fixed_channel(rdev, for_wdev)) | ||
53 | return -EBUSY; | ||
54 | |||
55 | if (!rdev->ops->set_channel) | ||
56 | return -EOPNOTSUPP; | ||
57 | |||
58 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
59 | |||
60 | /* Primary channel not allowed */ | ||
61 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (channel_type == NL80211_CHAN_HT40MINUS && | ||
65 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
66 | return -EINVAL; | ||
67 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
68 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
69 | return -EINVAL; | ||
70 | |||
71 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
72 | |||
73 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
74 | if (!ht_cap->ht_supported) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
78 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); | ||
83 | if (result) | ||
84 | return result; | ||
85 | |||
86 | rdev->channel = chan; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 1e189306560d..bc99e4ec7463 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -32,6 +32,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
32 | * only read the list, and that can happen quite | 32 | * only read the list, and that can happen quite |
33 | * often because we need to do it for each command */ | 33 | * often because we need to do it for each command */ |
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | int cfg80211_rdev_list_generation; | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This is used to protect the cfg80211_rdev_list | 38 | * This is used to protect the cfg80211_rdev_list |
@@ -411,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
411 | rdev->wiphy.dev.class = &ieee80211_class; | 412 | rdev->wiphy.dev.class = &ieee80211_class; |
412 | rdev->wiphy.dev.platform_data = rdev; | 413 | rdev->wiphy.dev.platform_data = rdev; |
413 | 414 | ||
415 | rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; | ||
416 | |||
414 | wiphy_net_set(&rdev->wiphy, &init_net); | 417 | wiphy_net_set(&rdev->wiphy, &init_net); |
415 | 418 | ||
416 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; | 419 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; |
@@ -511,6 +514,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
511 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 514 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
512 | 515 | ||
513 | list_add(&rdev->list, &cfg80211_rdev_list); | 516 | list_add(&rdev->list, &cfg80211_rdev_list); |
517 | cfg80211_rdev_list_generation++; | ||
514 | 518 | ||
515 | mutex_unlock(&cfg80211_mutex); | 519 | mutex_unlock(&cfg80211_mutex); |
516 | 520 | ||
@@ -593,13 +597,14 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
593 | reg_device_remove(wiphy); | 597 | reg_device_remove(wiphy); |
594 | 598 | ||
595 | list_del(&rdev->list); | 599 | list_del(&rdev->list); |
600 | cfg80211_rdev_list_generation++; | ||
596 | device_del(&rdev->wiphy.dev); | 601 | device_del(&rdev->wiphy.dev); |
597 | debugfs_remove(rdev->wiphy.debugfsdir); | 602 | debugfs_remove(rdev->wiphy.debugfsdir); |
598 | 603 | ||
599 | mutex_unlock(&cfg80211_mutex); | 604 | mutex_unlock(&cfg80211_mutex); |
600 | 605 | ||
606 | flush_work(&rdev->scan_done_wk); | ||
601 | cancel_work_sync(&rdev->conn_work); | 607 | cancel_work_sync(&rdev->conn_work); |
602 | cancel_work_sync(&rdev->scan_done_wk); | ||
603 | kfree(rdev->scan_req); | 608 | kfree(rdev->scan_req); |
604 | flush_work(&rdev->event_work); | 609 | flush_work(&rdev->event_work); |
605 | } | 610 | } |
@@ -653,6 +658,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
653 | spin_lock_init(&wdev->event_lock); | 658 | spin_lock_init(&wdev->event_lock); |
654 | mutex_lock(&rdev->devlist_mtx); | 659 | mutex_lock(&rdev->devlist_mtx); |
655 | list_add(&wdev->list, &rdev->netdev_list); | 660 | list_add(&wdev->list, &rdev->netdev_list); |
661 | rdev->devlist_generation++; | ||
656 | /* can only change netns with wiphy */ | 662 | /* can only change netns with wiphy */ |
657 | dev->features |= NETIF_F_NETNS_LOCAL; | 663 | dev->features |= NETIF_F_NETNS_LOCAL; |
658 | 664 | ||
@@ -670,7 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
670 | wdev->wext.default_key = -1; | 676 | wdev->wext.default_key = -1; |
671 | wdev->wext.default_mgmt_key = -1; | 677 | wdev->wext.default_mgmt_key = -1; |
672 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 678 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
673 | wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; | 679 | wdev->wext.ps = wdev->wiphy->ps_default; |
674 | wdev->wext.ps_timeout = 100; | 680 | wdev->wext.ps_timeout = 100; |
675 | if (rdev->ops->set_power_mgmt) | 681 | if (rdev->ops->set_power_mgmt) |
676 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 682 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
@@ -706,6 +712,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
706 | case NETDEV_UP: | 712 | case NETDEV_UP: |
707 | #ifdef CONFIG_WIRELESS_EXT | 713 | #ifdef CONFIG_WIRELESS_EXT |
708 | cfg80211_lock_rdev(rdev); | 714 | cfg80211_lock_rdev(rdev); |
715 | mutex_lock(&rdev->devlist_mtx); | ||
709 | wdev_lock(wdev); | 716 | wdev_lock(wdev); |
710 | switch (wdev->iftype) { | 717 | switch (wdev->iftype) { |
711 | case NL80211_IFTYPE_ADHOC: | 718 | case NL80211_IFTYPE_ADHOC: |
@@ -718,10 +725,18 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
718 | break; | 725 | break; |
719 | } | 726 | } |
720 | wdev_unlock(wdev); | 727 | wdev_unlock(wdev); |
728 | mutex_unlock(&rdev->devlist_mtx); | ||
721 | cfg80211_unlock_rdev(rdev); | 729 | cfg80211_unlock_rdev(rdev); |
722 | #endif | 730 | #endif |
723 | break; | 731 | break; |
724 | case NETDEV_UNREGISTER: | 732 | case NETDEV_UNREGISTER: |
733 | cfg80211_lock_rdev(rdev); | ||
734 | |||
735 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { | ||
736 | rdev->scan_req->aborted = true; | ||
737 | ___cfg80211_scan_done(rdev); | ||
738 | } | ||
739 | |||
725 | mutex_lock(&rdev->devlist_mtx); | 740 | mutex_lock(&rdev->devlist_mtx); |
726 | /* | 741 | /* |
727 | * It is possible to get NETDEV_UNREGISTER | 742 | * It is possible to get NETDEV_UNREGISTER |
@@ -733,12 +748,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
733 | if (!list_empty(&wdev->list)) { | 748 | if (!list_empty(&wdev->list)) { |
734 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 749 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
735 | list_del_init(&wdev->list); | 750 | list_del_init(&wdev->list); |
751 | rdev->devlist_generation++; | ||
736 | mutex_destroy(&wdev->mtx); | 752 | mutex_destroy(&wdev->mtx); |
737 | #ifdef CONFIG_WIRELESS_EXT | 753 | #ifdef CONFIG_WIRELESS_EXT |
738 | kfree(wdev->wext.keys); | 754 | kfree(wdev->wext.keys); |
739 | #endif | 755 | #endif |
740 | } | 756 | } |
741 | mutex_unlock(&rdev->devlist_mtx); | 757 | mutex_unlock(&rdev->devlist_mtx); |
758 | cfg80211_unlock_rdev(rdev); | ||
742 | break; | 759 | break; |
743 | case NETDEV_PRE_UP: | 760 | case NETDEV_PRE_UP: |
744 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 761 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 325c17e6198c..c603f5286326 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -49,6 +49,7 @@ struct cfg80211_registered_device { | |||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | struct list_head netdev_list; | 51 | struct list_head netdev_list; |
52 | int devlist_generation; | ||
52 | 53 | ||
53 | /* BSSes/scanning */ | 54 | /* BSSes/scanning */ |
54 | spinlock_t bss_lock; | 55 | spinlock_t bss_lock; |
@@ -101,6 +102,7 @@ bool wiphy_idx_valid(int wiphy_idx) | |||
101 | 102 | ||
102 | extern struct mutex cfg80211_mutex; | 103 | extern struct mutex cfg80211_mutex; |
103 | extern struct list_head cfg80211_rdev_list; | 104 | extern struct list_head cfg80211_rdev_list; |
105 | extern int cfg80211_rdev_list_generation; | ||
104 | 106 | ||
105 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 107 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) |
106 | 108 | ||
@@ -335,7 +337,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 337 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
336 | struct net_device *dev, | 338 | struct net_device *dev, |
337 | struct cfg80211_connect_params *connect, | 339 | struct cfg80211_connect_params *connect, |
338 | struct cfg80211_cached_keys *connkeys); | 340 | struct cfg80211_cached_keys *connkeys, |
341 | const u8 *prev_bssid); | ||
339 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 342 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, | 343 | struct net_device *dev, |
341 | struct cfg80211_connect_params *connect, | 344 | struct cfg80211_connect_params *connect, |
@@ -353,6 +356,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
353 | struct wireless_dev *wdev); | 356 | struct wireless_dev *wdev); |
354 | 357 | ||
355 | void cfg80211_conn_work(struct work_struct *work); | 358 | void cfg80211_conn_work(struct work_struct *work); |
359 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | ||
356 | 360 | ||
357 | /* internal helpers */ | 361 | /* internal helpers */ |
358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 362 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
@@ -364,6 +368,14 @@ void cfg80211_sme_scan_done(struct net_device *dev); | |||
364 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 368 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
365 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 369 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
366 | void __cfg80211_scan_done(struct work_struct *wk); | 370 | void __cfg80211_scan_done(struct work_struct *wk); |
371 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); | ||
367 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 372 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
368 | 373 | ||
374 | struct ieee80211_channel * | ||
375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
376 | struct wireless_dev *for_wdev); | ||
377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
378 | struct wireless_dev *for_wdev, | ||
379 | int freq, enum nl80211_channel_type channel_type); | ||
380 | |||
369 | #endif /* __NET_WIRELESS_CORE_H */ | 381 | #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/mlme.c b/net/wireless/mlme.c index 525e8e247b30..da64071ceb84 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -67,6 +67,16 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
67 | 67 | ||
68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
69 | 69 | ||
70 | /* | ||
71 | * This is a bit of a hack, we don't notify userspace of | ||
72 | * a (re-)association reply if we tried to send a reassoc | ||
73 | * and got a reject -- we only try again with an assoc | ||
74 | * frame instead of reassoc. | ||
75 | */ | ||
76 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | ||
77 | cfg80211_sme_failed_reassoc(wdev)) | ||
78 | goto out; | ||
79 | |||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 80 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 81 | ||
72 | if (status_code == WLAN_STATUS_SUCCESS) { | 82 | if (status_code == WLAN_STATUS_SUCCESS) { |
@@ -97,6 +107,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
97 | cfg80211_put_bss(&bss->pub); | 107 | cfg80211_put_bss(&bss->pub); |
98 | } | 108 | } |
99 | 109 | ||
110 | out: | ||
100 | wdev_unlock(wdev); | 111 | wdev_unlock(wdev); |
101 | } | 112 | } |
102 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 113 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
@@ -149,7 +160,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
149 | 160 | ||
150 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 161 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
151 | 162 | ||
152 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 163 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
153 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 164 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
154 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 165 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
155 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 166 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
@@ -198,7 +209,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
198 | return; | 209 | return; |
199 | 210 | ||
200 | if (wdev->current_bss && | 211 | if (wdev->current_bss && |
201 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { | 212 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { |
202 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | 213 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
203 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) | 214 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) |
204 | continue; | 215 | continue; |
@@ -215,7 +226,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
215 | 226 | ||
216 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 227 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
217 | 228 | ||
218 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 229 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
219 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 230 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
220 | } | 231 | } |
221 | 232 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0cd548267d4a..a8aaadeb6773 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
410 | 410 | ||
411 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
412 | cfg80211_rdev_list_generation); | ||
413 | |||
411 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 414 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
412 | dev->wiphy.retry_short); | 415 | dev->wiphy.retry_short); |
413 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | 416 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, |
@@ -701,15 +704,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
701 | 704 | ||
702 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 705 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
703 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 706 | 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; | 707 | u32 freq; |
707 | 708 | ||
708 | if (!rdev->ops->set_channel) { | ||
709 | result = -EOPNOTSUPP; | ||
710 | goto bad_res; | ||
711 | } | ||
712 | |||
713 | result = -EINVAL; | 709 | result = -EINVAL; |
714 | 710 | ||
715 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 711 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -723,42 +719,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
723 | } | 719 | } |
724 | 720 | ||
725 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 721 | 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 | |||
745 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
746 | |||
747 | /* no HT capabilities or intolerant */ | ||
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 | 722 | ||
756 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 723 | mutex_lock(&rdev->devlist_mtx); |
757 | channel_type); | 724 | result = rdev_set_freq(rdev, NULL, freq, channel_type); |
725 | mutex_unlock(&rdev->devlist_mtx); | ||
758 | if (result) | 726 | if (result) |
759 | goto bad_res; | 727 | goto bad_res; |
760 | |||
761 | rdev->channel = chan; | ||
762 | } | 728 | } |
763 | 729 | ||
764 | changed = 0; | 730 | changed = 0; |
@@ -862,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
862 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 828 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
863 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 829 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
864 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 830 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
831 | |||
832 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
833 | rdev->devlist_generation ^ | ||
834 | (cfg80211_rdev_list_generation << 2)); | ||
835 | |||
865 | return genlmsg_end(msg, hdr); | 836 | return genlmsg_end(msg, hdr); |
866 | 837 | ||
867 | nla_put_failure: | 838 | nla_put_failure: |
@@ -875,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
875 | int if_idx = 0; | 846 | int if_idx = 0; |
876 | int wp_start = cb->args[0]; | 847 | int wp_start = cb->args[0]; |
877 | int if_start = cb->args[1]; | 848 | int if_start = cb->args[1]; |
878 | struct cfg80211_registered_device *dev; | 849 | struct cfg80211_registered_device *rdev; |
879 | struct wireless_dev *wdev; | 850 | struct wireless_dev *wdev; |
880 | 851 | ||
881 | mutex_lock(&cfg80211_mutex); | 852 | mutex_lock(&cfg80211_mutex); |
882 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 853 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
883 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 854 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
884 | continue; | 855 | continue; |
885 | if (wp_idx < wp_start) { | 856 | if (wp_idx < wp_start) { |
886 | wp_idx++; | 857 | wp_idx++; |
@@ -888,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
888 | } | 859 | } |
889 | if_idx = 0; | 860 | if_idx = 0; |
890 | 861 | ||
891 | mutex_lock(&dev->devlist_mtx); | 862 | mutex_lock(&rdev->devlist_mtx); |
892 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 863 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
893 | if (if_idx < if_start) { | 864 | if (if_idx < if_start) { |
894 | if_idx++; | 865 | if_idx++; |
895 | continue; | 866 | continue; |
896 | } | 867 | } |
897 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 868 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
898 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 869 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
899 | dev, wdev->netdev) < 0) { | 870 | rdev, wdev->netdev) < 0) { |
900 | mutex_unlock(&dev->devlist_mtx); | 871 | mutex_unlock(&rdev->devlist_mtx); |
901 | goto out; | 872 | goto out; |
902 | } | 873 | } |
903 | if_idx++; | 874 | if_idx++; |
904 | } | 875 | } |
905 | mutex_unlock(&dev->devlist_mtx); | 876 | mutex_unlock(&rdev->devlist_mtx); |
906 | 877 | ||
907 | wp_idx++; | 878 | wp_idx++; |
908 | } | 879 | } |
@@ -1653,6 +1624,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1653 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1624 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1654 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1625 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1655 | 1626 | ||
1627 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); | ||
1628 | |||
1656 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1629 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1657 | if (!sinfoattr) | 1630 | if (!sinfoattr) |
1658 | goto nla_put_failure; | 1631 | goto nla_put_failure; |
@@ -2138,6 +2111,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2138 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 2111 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
2139 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 2112 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
2140 | 2113 | ||
2114 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); | ||
2115 | |||
2141 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 2116 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
2142 | if (!pinfoattr) | 2117 | if (!pinfoattr) |
2143 | goto nla_put_failure; | 2118 | goto nla_put_failure; |
@@ -3027,10 +3002,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3027 | goto out; | 3002 | goto out; |
3028 | } | 3003 | } |
3029 | 3004 | ||
3030 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
3031 | request->n_channels = n_channels; | 3005 | request->n_channels = n_channels; |
3032 | if (n_ssids) | 3006 | if (n_ssids) |
3033 | request->ssids = (void *)(request->channels + n_channels); | 3007 | request->ssids = (void *)&request->channels[n_channels]; |
3034 | request->n_ssids = n_ssids; | 3008 | request->n_ssids = n_ssids; |
3035 | if (ie_len) { | 3009 | if (ie_len) { |
3036 | if (request->ssids) | 3010 | if (request->ssids) |
@@ -3127,8 +3101,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3127 | if (!hdr) | 3101 | if (!hdr) |
3128 | return -1; | 3102 | return -1; |
3129 | 3103 | ||
3130 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, | 3104 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3131 | rdev->bss_generation); | ||
3132 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3105 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3133 | 3106 | ||
3134 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 3107 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
@@ -3453,7 +3426,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3453 | struct cfg80211_registered_device *rdev; | 3426 | struct cfg80211_registered_device *rdev; |
3454 | struct net_device *dev; | 3427 | struct net_device *dev; |
3455 | struct cfg80211_crypto_settings crypto; | 3428 | struct cfg80211_crypto_settings crypto; |
3456 | struct ieee80211_channel *chan; | 3429 | struct ieee80211_channel *chan, *fixedchan; |
3457 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3430 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
3458 | int err, ssid_len, ie_len = 0; | 3431 | int err, ssid_len, ie_len = 0; |
3459 | bool use_mfp = false; | 3432 | bool use_mfp = false; |
@@ -3496,6 +3469,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3496 | goto out; | 3469 | goto out; |
3497 | } | 3470 | } |
3498 | 3471 | ||
3472 | mutex_lock(&rdev->devlist_mtx); | ||
3473 | fixedchan = rdev_fixed_channel(rdev, NULL); | ||
3474 | if (fixedchan && chan != fixedchan) { | ||
3475 | err = -EBUSY; | ||
3476 | mutex_unlock(&rdev->devlist_mtx); | ||
3477 | goto out; | ||
3478 | } | ||
3479 | mutex_unlock(&rdev->devlist_mtx); | ||
3480 | |||
3499 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3481 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3500 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3482 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3501 | 3483 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0f61ae613f3b..f256dfffbf46 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1018,7 +1018,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1018 | map_regdom_flags(reg_rule->flags) | bw_flags; | 1018 | map_regdom_flags(reg_rule->flags) | bw_flags; |
1019 | chan->max_antenna_gain = chan->orig_mag = | 1019 | chan->max_antenna_gain = chan->orig_mag = |
1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1021 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1022 | chan->max_power = chan->orig_mpwr = | 1021 | chan->max_power = chan->orig_mpwr = |
1023 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1022 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1024 | return; | 1023 | return; |
@@ -1027,7 +1026,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1027 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 1026 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
1028 | chan->max_antenna_gain = min(chan->orig_mag, | 1027 | chan->max_antenna_gain = min(chan->orig_mag, |
1029 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 1028 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
1030 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1031 | if (chan->orig_mpwr) | 1029 | if (chan->orig_mpwr) |
1032 | chan->max_power = min(chan->orig_mpwr, | 1030 | chan->max_power = min(chan->orig_mpwr, |
1033 | (int) MBM_TO_DBM(power_rule->max_eirp)); | 1031 | (int) MBM_TO_DBM(power_rule->max_eirp)); |
@@ -1329,7 +1327,6 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1329 | 1327 | ||
1330 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1328 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1331 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1329 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1332 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1333 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 1330 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
1334 | } | 1331 | } |
1335 | 1332 | ||
@@ -1427,7 +1424,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1427 | if (last_wiphy != wiphy) { | 1424 | if (last_wiphy != wiphy) { |
1428 | /* | 1425 | /* |
1429 | * Two cards with two APs claiming different | 1426 | * Two cards with two APs claiming different |
1430 | * different Country IE alpha2s. We could | 1427 | * Country IE alpha2s. We could |
1431 | * intersect them, but that seems unlikely | 1428 | * intersect them, but that seems unlikely |
1432 | * to be correct. Reject second one for now. | 1429 | * to be correct. Reject second one for now. |
1433 | */ | 1430 | */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0ccf3a07dc02..fe575a24c95c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -18,19 +18,14 @@ | |||
18 | 18 | ||
19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) | 19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) |
20 | 20 | ||
21 | void __cfg80211_scan_done(struct work_struct *wk) | 21 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) |
22 | { | 22 | { |
23 | struct cfg80211_registered_device *rdev; | ||
24 | struct cfg80211_scan_request *request; | 23 | struct cfg80211_scan_request *request; |
25 | struct net_device *dev; | 24 | struct net_device *dev; |
26 | #ifdef CONFIG_WIRELESS_EXT | 25 | #ifdef CONFIG_WIRELESS_EXT |
27 | union iwreq_data wrqu; | 26 | union iwreq_data wrqu; |
28 | #endif | 27 | #endif |
29 | 28 | ||
30 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
31 | scan_done_wk); | ||
32 | |||
33 | mutex_lock(&rdev->mtx); | ||
34 | request = rdev->scan_req; | 29 | request = rdev->scan_req; |
35 | 30 | ||
36 | dev = request->dev; | 31 | dev = request->dev; |
@@ -43,9 +38,9 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
43 | cfg80211_sme_scan_done(dev); | 38 | cfg80211_sme_scan_done(dev); |
44 | 39 | ||
45 | if (request->aborted) | 40 | if (request->aborted) |
46 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | 41 | nl80211_send_scan_aborted(rdev, dev); |
47 | else | 42 | else |
48 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | 43 | nl80211_send_scan_done(rdev, dev); |
49 | 44 | ||
50 | #ifdef CONFIG_WIRELESS_EXT | 45 | #ifdef CONFIG_WIRELESS_EXT |
51 | if (!request->aborted) { | 46 | if (!request->aborted) { |
@@ -57,11 +52,22 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
57 | 52 | ||
58 | dev_put(dev); | 53 | dev_put(dev); |
59 | 54 | ||
60 | cfg80211_unlock_rdev(rdev); | 55 | rdev->scan_req = NULL; |
61 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
62 | kfree(request); | 56 | kfree(request); |
63 | } | 57 | } |
64 | 58 | ||
59 | void __cfg80211_scan_done(struct work_struct *wk) | ||
60 | { | ||
61 | struct cfg80211_registered_device *rdev; | ||
62 | |||
63 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
64 | scan_done_wk); | ||
65 | |||
66 | cfg80211_lock_rdev(rdev); | ||
67 | ___cfg80211_scan_done(rdev); | ||
68 | cfg80211_unlock_rdev(rdev); | ||
69 | } | ||
70 | |||
65 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 71 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
66 | { | 72 | { |
67 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 73 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
@@ -562,6 +568,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
562 | spin_lock_bh(&dev->bss_lock); | 568 | spin_lock_bh(&dev->bss_lock); |
563 | 569 | ||
564 | list_del(&bss->list); | 570 | list_del(&bss->list); |
571 | dev->bss_generation++; | ||
565 | rb_erase(&bss->rbn, &dev->bss_tree); | 572 | rb_erase(&bss->rbn, &dev->bss_tree); |
566 | 573 | ||
567 | spin_unlock_bh(&dev->bss_lock); | 574 | spin_unlock_bh(&dev->bss_lock); |
@@ -611,8 +618,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
611 | 618 | ||
612 | creq->wiphy = wiphy; | 619 | creq->wiphy = wiphy; |
613 | creq->dev = dev; | 620 | creq->dev = dev; |
614 | creq->ssids = (void *)(creq + 1); | 621 | /* SSIDs come after channels */ |
615 | creq->channels = (void *)(creq->ssids + 1); | 622 | creq->ssids = (void *)&creq->channels[n_channels]; |
616 | creq->n_channels = n_channels; | 623 | creq->n_channels = n_channels; |
617 | creq->n_ssids = 1; | 624 | creq->n_ssids = 1; |
618 | 625 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8a7dcbf90602..8e2ef54ea714 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -27,10 +27,10 @@ struct cfg80211_conn { | |||
27 | CFG80211_CONN_ASSOCIATE_NEXT, | 27 | CFG80211_CONN_ASSOCIATE_NEXT, |
28 | CFG80211_CONN_ASSOCIATING, | 28 | CFG80211_CONN_ASSOCIATING, |
29 | } state; | 29 | } state; |
30 | u8 bssid[ETH_ALEN]; | 30 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
31 | u8 *ie; | 31 | u8 *ie; |
32 | size_t ie_len; | 32 | size_t ie_len; |
33 | bool auto_auth; | 33 | bool auto_auth, prev_bssid_valid; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | 36 | ||
@@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
65 | if (!request) | 65 | if (!request) |
66 | return -ENOMEM; | 66 | return -ENOMEM; |
67 | 67 | ||
68 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
69 | if (wdev->conn->params.channel) | 68 | if (wdev->conn->params.channel) |
70 | request->channels[0] = wdev->conn->params.channel; | 69 | request->channels[0] = wdev->conn->params.channel; |
71 | else { | 70 | else { |
@@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
82 | } | 81 | } |
83 | } | 82 | } |
84 | request->n_channels = n_channels; | 83 | request->n_channels = n_channels; |
85 | request->ssids = (void *)(request->channels + n_channels); | 84 | request->ssids = (void *)&request->channels[n_channels]; |
86 | request->n_ssids = 1; | 85 | request->n_ssids = 1; |
87 | 86 | ||
88 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, | 87 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, |
@@ -110,6 +109,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
110 | { | 109 | { |
111 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 110 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
112 | struct cfg80211_connect_params *params; | 111 | struct cfg80211_connect_params *params; |
112 | const u8 *prev_bssid = NULL; | ||
113 | int err; | 113 | int err; |
114 | 114 | ||
115 | ASSERT_WDEV_LOCK(wdev); | 115 | ASSERT_WDEV_LOCK(wdev); |
@@ -135,15 +135,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
135 | case CFG80211_CONN_ASSOCIATE_NEXT: | 135 | case CFG80211_CONN_ASSOCIATE_NEXT: |
136 | BUG_ON(!rdev->ops->assoc); | 136 | BUG_ON(!rdev->ops->assoc); |
137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
138 | /* | 138 | if (wdev->conn->prev_bssid_valid) |
139 | * We could, later, implement roaming here and then actually | 139 | prev_bssid = wdev->conn->prev_bssid; |
140 | * set prev_bssid to non-NULL. But then we need to be aware | ||
141 | * that some APs don't like that -- so we'd need to retry | ||
142 | * the association. | ||
143 | */ | ||
144 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 140 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, |
145 | params->channel, params->bssid, | 141 | params->channel, params->bssid, |
146 | NULL, | 142 | prev_bssid, |
147 | params->ssid, params->ssid_len, | 143 | params->ssid, params->ssid_len, |
148 | params->ie, params->ie_len, | 144 | params->ie, params->ie_len, |
149 | false, ¶ms->crypto); | 145 | false, ¶ms->crypto); |
@@ -256,9 +252,11 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
256 | { | 252 | { |
257 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 253 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
258 | 254 | ||
255 | mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
259 | wdev_lock(wdev); | 256 | wdev_lock(wdev); |
260 | __cfg80211_sme_scan_done(dev); | 257 | __cfg80211_sme_scan_done(dev); |
261 | wdev_unlock(wdev); | 258 | wdev_unlock(wdev); |
259 | mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
262 | } | 260 | } |
263 | 261 | ||
264 | void cfg80211_sme_rx_auth(struct net_device *dev, | 262 | void cfg80211_sme_rx_auth(struct net_device *dev, |
@@ -314,6 +312,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
314 | } | 312 | } |
315 | } | 313 | } |
316 | 314 | ||
315 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | ||
316 | { | ||
317 | struct wiphy *wiphy = wdev->wiphy; | ||
318 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
319 | |||
320 | if (WARN_ON(!wdev->conn)) | ||
321 | return false; | ||
322 | |||
323 | if (!wdev->conn->prev_bssid_valid) | ||
324 | return false; | ||
325 | |||
326 | /* | ||
327 | * Some stupid APs don't accept reassoc, so we | ||
328 | * need to fall back to trying regular assoc. | ||
329 | */ | ||
330 | wdev->conn->prev_bssid_valid = false; | ||
331 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
332 | schedule_work(&rdev->conn_work); | ||
333 | |||
334 | return true; | ||
335 | } | ||
336 | |||
317 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 337 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
318 | const u8 *req_ie, size_t req_ie_len, | 338 | const u8 *req_ie, size_t req_ie_len, |
319 | const u8 *resp_ie, size_t resp_ie_len, | 339 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -357,8 +377,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
357 | 377 | ||
358 | memset(&wrqu, 0, sizeof(wrqu)); | 378 | memset(&wrqu, 0, sizeof(wrqu)); |
359 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 379 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
360 | if (bssid && status == WLAN_STATUS_SUCCESS) | 380 | if (bssid && status == WLAN_STATUS_SUCCESS) { |
361 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 381 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
382 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
383 | wdev->wext.prev_bssid_valid = true; | ||
384 | } | ||
362 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 385 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
363 | } | 386 | } |
364 | #endif | 387 | #endif |
@@ -509,6 +532,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
509 | memset(&wrqu, 0, sizeof(wrqu)); | 532 | memset(&wrqu, 0, sizeof(wrqu)); |
510 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 533 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
511 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 534 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
535 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
536 | wdev->wext.prev_bssid_valid = true; | ||
512 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); | 537 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
513 | #endif | 538 | #endif |
514 | } | 539 | } |
@@ -570,10 +595,30 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
570 | wdev->ssid_len = 0; | 595 | wdev->ssid_len = 0; |
571 | 596 | ||
572 | if (wdev->conn) { | 597 | if (wdev->conn) { |
598 | const u8 *bssid; | ||
599 | int ret; | ||
600 | |||
573 | kfree(wdev->conn->ie); | 601 | kfree(wdev->conn->ie); |
574 | wdev->conn->ie = NULL; | 602 | wdev->conn->ie = NULL; |
575 | kfree(wdev->conn); | 603 | kfree(wdev->conn); |
576 | wdev->conn = NULL; | 604 | wdev->conn = NULL; |
605 | |||
606 | /* | ||
607 | * If this disconnect was due to a disassoc, we | ||
608 | * we might still have an auth BSS around. For | ||
609 | * the userspace SME that's currently expected, | ||
610 | * but for the kernel SME (nl80211 CONNECT or | ||
611 | * wireless extensions) we want to clear up all | ||
612 | * state. | ||
613 | */ | ||
614 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
615 | if (!wdev->auth_bsses[i]) | ||
616 | continue; | ||
617 | bssid = wdev->auth_bsses[i]->pub.bssid; | ||
618 | ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | ||
619 | WLAN_REASON_DEAUTH_LEAVING); | ||
620 | WARN(ret, "deauth failed: %d\n", ret); | ||
621 | } | ||
577 | } | 622 | } |
578 | 623 | ||
579 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); | 624 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
@@ -621,9 +666,11 @@ EXPORT_SYMBOL(cfg80211_disconnected); | |||
621 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 666 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
622 | struct net_device *dev, | 667 | struct net_device *dev, |
623 | struct cfg80211_connect_params *connect, | 668 | struct cfg80211_connect_params *connect, |
624 | struct cfg80211_cached_keys *connkeys) | 669 | struct cfg80211_cached_keys *connkeys, |
670 | const u8 *prev_bssid) | ||
625 | { | 671 | { |
626 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 672 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
673 | struct ieee80211_channel *chan; | ||
627 | int err; | 674 | int err; |
628 | 675 | ||
629 | ASSERT_WDEV_LOCK(wdev); | 676 | ASSERT_WDEV_LOCK(wdev); |
@@ -631,6 +678,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
631 | if (wdev->sme_state != CFG80211_SME_IDLE) | 678 | if (wdev->sme_state != CFG80211_SME_IDLE) |
632 | return -EALREADY; | 679 | return -EALREADY; |
633 | 680 | ||
681 | chan = rdev_fixed_channel(rdev, wdev); | ||
682 | if (chan && chan != connect->channel) | ||
683 | return -EBUSY; | ||
684 | |||
634 | if (WARN_ON(wdev->connect_keys)) { | 685 | if (WARN_ON(wdev->connect_keys)) { |
635 | kfree(wdev->connect_keys); | 686 | kfree(wdev->connect_keys); |
636 | wdev->connect_keys = NULL; | 687 | wdev->connect_keys = NULL; |
@@ -638,14 +689,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
638 | 689 | ||
639 | if (connkeys && connkeys->def >= 0) { | 690 | if (connkeys && connkeys->def >= 0) { |
640 | int idx; | 691 | int idx; |
692 | u32 cipher; | ||
641 | 693 | ||
642 | idx = connkeys->def; | 694 | idx = connkeys->def; |
695 | cipher = connkeys->params[idx].cipher; | ||
643 | /* If given a WEP key we may need it for shared key auth */ | 696 | /* If given a WEP key we may need it for shared key auth */ |
644 | if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || | 697 | if (cipher == WLAN_CIPHER_SUITE_WEP40 || |
645 | connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { | 698 | cipher == WLAN_CIPHER_SUITE_WEP104) { |
646 | connect->key_idx = idx; | 699 | connect->key_idx = idx; |
647 | connect->key = connkeys->params[idx].key; | 700 | connect->key = connkeys->params[idx].key; |
648 | connect->key_len = connkeys->params[idx].key_len; | 701 | connect->key_len = connkeys->params[idx].key_len; |
702 | |||
703 | /* | ||
704 | * If ciphers are not set (e.g. when going through | ||
705 | * iwconfig), we have to set them appropriately here. | ||
706 | */ | ||
707 | if (connect->crypto.cipher_group == 0) | ||
708 | connect->crypto.cipher_group = cipher; | ||
709 | |||
710 | if (connect->crypto.n_ciphers_pairwise == 0) { | ||
711 | connect->crypto.n_ciphers_pairwise = 1; | ||
712 | connect->crypto.ciphers_pairwise[0] = cipher; | ||
713 | } | ||
649 | } | 714 | } |
650 | } | 715 | } |
651 | 716 | ||
@@ -701,6 +766,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
701 | wdev->sme_state = CFG80211_SME_CONNECTING; | 766 | wdev->sme_state = CFG80211_SME_CONNECTING; |
702 | wdev->connect_keys = connkeys; | 767 | wdev->connect_keys = connkeys; |
703 | 768 | ||
769 | if (prev_bssid) { | ||
770 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
771 | wdev->conn->prev_bssid_valid = true; | ||
772 | } | ||
773 | |||
704 | /* we're good if we have both BSSID and channel */ | 774 | /* we're good if we have both BSSID and channel */ |
705 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { | 775 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { |
706 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 776 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
@@ -751,9 +821,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
751 | { | 821 | { |
752 | int err; | 822 | int err; |
753 | 823 | ||
824 | mutex_lock(&rdev->devlist_mtx); | ||
754 | wdev_lock(dev->ieee80211_ptr); | 825 | wdev_lock(dev->ieee80211_ptr); |
755 | err = __cfg80211_connect(rdev, dev, connect, connkeys); | 826 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); |
756 | wdev_unlock(dev->ieee80211_ptr); | 827 | wdev_unlock(dev->ieee80211_ptr); |
828 | mutex_unlock(&rdev->devlist_mtx); | ||
757 | 829 | ||
758 | return err; | 830 | return err; |
759 | } | 831 | } |
diff --git a/net/wireless/util.c b/net/wireless/util.c index ba387d85dcfd..693275a16a26 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
274 | switch (ae) { | 274 | switch (ae) { |
275 | case 0: | 275 | case 0: |
276 | return 6; | 276 | return 6; |
277 | case 1: | 277 | case MESH_FLAGS_AE_A4: |
278 | return 12; | 278 | return 12; |
279 | case 2: | 279 | case MESH_FLAGS_AE_A5_A6: |
280 | return 18; | 280 | return 18; |
281 | case 3: | 281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): |
282 | return 24; | 282 | return 24; |
283 | default: | 283 | default: |
284 | return 6; | 284 | return 6; |
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
333 | } | 333 | } |
334 | break; | 334 | break; |
335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
336 | if (iftype != NL80211_IFTYPE_STATION || | 336 | if ((iftype != NL80211_IFTYPE_STATION && |
337 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
337 | (is_multicast_ether_addr(dst) && | 338 | (is_multicast_ether_addr(dst) && |
338 | !compare_ether_addr(src, addr))) | 339 | !compare_ether_addr(src, addr))) |
339 | return -1; | 340 | return -1; |
341 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||
342 | struct ieee80211s_hdr *meshdr = | ||
343 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
344 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
345 | if (meshdr->flags & MESH_FLAGS_AE_A4) | ||
346 | memcpy(src, meshdr->eaddr1, ETH_ALEN); | ||
347 | } | ||
340 | break; | 348 | break; |
341 | case cpu_to_le16(0): | 349 | case cpu_to_le16(0): |
342 | if (iftype != NL80211_IFTYPE_ADHOC) | 350 | if (iftype != NL80211_IFTYPE_ADHOC) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e4e90e249bab..c44917492210 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, NULL, 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 7bacbd1c2af6..d16cd9ea4d00 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -15,6 +15,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
15 | struct wireless_dev *wdev) | 15 | struct wireless_dev *wdev) |
16 | { | 16 | { |
17 | struct cfg80211_cached_keys *ck = NULL; | 17 | struct cfg80211_cached_keys *ck = NULL; |
18 | const u8 *prev_bssid = NULL; | ||
18 | int err, i; | 19 | int err, i; |
19 | 20 | ||
20 | ASSERT_RDEV_LOCK(rdev); | 21 | ASSERT_RDEV_LOCK(rdev); |
@@ -42,8 +43,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
42 | for (i = 0; i < 6; i++) | 43 | for (i = 0; i < 6; i++) |
43 | ck->params[i].key = ck->data[i]; | 44 | ck->params[i].key = ck->data[i]; |
44 | } | 45 | } |
46 | |||
47 | if (wdev->wext.prev_bssid_valid) | ||
48 | prev_bssid = wdev->wext.prev_bssid; | ||
49 | |||
45 | err = __cfg80211_connect(rdev, wdev->netdev, | 50 | err = __cfg80211_connect(rdev, wdev->netdev, |
46 | &wdev->wext.connect, ck); | 51 | &wdev->wext.connect, ck, prev_bssid); |
47 | if (err) | 52 | if (err) |
48 | kfree(ck); | 53 | kfree(ck); |
49 | 54 | ||
@@ -52,25 +57,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
52 | 57 | ||
53 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | 58 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, |
54 | struct iw_request_info *info, | 59 | struct iw_request_info *info, |
55 | struct iw_freq *freq, char *extra) | 60 | struct iw_freq *wextfreq, char *extra) |
56 | { | 61 | { |
57 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 62 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
58 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 63 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
59 | struct ieee80211_channel *chan; | 64 | struct ieee80211_channel *chan = NULL; |
60 | int err; | 65 | int err, freq; |
61 | 66 | ||
62 | /* call only for station! */ | 67 | /* call only for station! */ |
63 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 68 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
64 | return -EINVAL; | 69 | return -EINVAL; |
65 | 70 | ||
66 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 71 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
67 | if (chan && IS_ERR(chan)) | 72 | if (freq < 0) |
68 | return PTR_ERR(chan); | 73 | return freq; |
69 | 74 | ||
70 | if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) | 75 | if (freq) { |
71 | return -EINVAL; | 76 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
77 | if (!chan) | ||
78 | return -EINVAL; | ||
79 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
80 | return -EINVAL; | ||
81 | } | ||
72 | 82 | ||
73 | cfg80211_lock_rdev(rdev); | 83 | cfg80211_lock_rdev(rdev); |
84 | mutex_lock(&rdev->devlist_mtx); | ||
74 | wdev_lock(wdev); | 85 | wdev_lock(wdev); |
75 | 86 | ||
76 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 87 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -84,9 +95,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
84 | /* if SSID set, we'll try right again, avoid event */ | 95 | /* if SSID set, we'll try right again, avoid event */ |
85 | if (wdev->wext.connect.ssid_len) | 96 | if (wdev->wext.connect.ssid_len) |
86 | event = false; | 97 | event = false; |
87 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 98 | err = __cfg80211_disconnect(rdev, dev, |
88 | dev, WLAN_REASON_DEAUTH_LEAVING, | 99 | WLAN_REASON_DEAUTH_LEAVING, event); |
89 | event); | ||
90 | if (err) | 100 | if (err) |
91 | goto out; | 101 | goto out; |
92 | } | 102 | } |
@@ -95,17 +105,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
95 | wdev->wext.connect.channel = chan; | 105 | wdev->wext.connect.channel = chan; |
96 | 106 | ||
97 | /* SSID is not set, we just want to switch channel */ | 107 | /* SSID is not set, we just want to switch channel */ |
98 | if (wdev->wext.connect.ssid_len && chan) { | 108 | if (chan && !wdev->wext.connect.ssid_len) { |
99 | err = -EOPNOTSUPP; | 109 | err = rdev_set_freq(rdev, wdev, 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; | 110 | goto out; |
104 | } | 111 | } |
105 | 112 | ||
106 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 113 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
107 | out: | 114 | out: |
108 | wdev_unlock(wdev); | 115 | wdev_unlock(wdev); |
116 | mutex_unlock(&rdev->devlist_mtx); | ||
109 | cfg80211_unlock_rdev(rdev); | 117 | cfg80211_unlock_rdev(rdev); |
110 | return err; | 118 | return err; |
111 | } | 119 | } |
@@ -143,6 +151,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
143 | struct iw_point *data, char *ssid) | 151 | struct iw_point *data, char *ssid) |
144 | { | 152 | { |
145 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 153 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
154 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
146 | size_t len = data->length; | 155 | size_t len = data->length; |
147 | int err; | 156 | int err; |
148 | 157 | ||
@@ -157,7 +166,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
157 | if (len > 0 && ssid[len - 1] == '\0') | 166 | if (len > 0 && ssid[len - 1] == '\0') |
158 | len--; | 167 | len--; |
159 | 168 | ||
160 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 169 | cfg80211_lock_rdev(rdev); |
170 | mutex_lock(&rdev->devlist_mtx); | ||
161 | wdev_lock(wdev); | 171 | wdev_lock(wdev); |
162 | 172 | ||
163 | err = 0; | 173 | err = 0; |
@@ -173,23 +183,24 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
173 | /* if SSID set now, we'll try to connect, avoid event */ | 183 | /* if SSID set now, we'll try to connect, avoid event */ |
174 | if (len) | 184 | if (len) |
175 | event = false; | 185 | event = false; |
176 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 186 | err = __cfg80211_disconnect(rdev, dev, |
177 | dev, WLAN_REASON_DEAUTH_LEAVING, | 187 | WLAN_REASON_DEAUTH_LEAVING, event); |
178 | event); | ||
179 | if (err) | 188 | if (err) |
180 | goto out; | 189 | goto out; |
181 | } | 190 | } |
182 | 191 | ||
192 | wdev->wext.prev_bssid_valid = false; | ||
183 | wdev->wext.connect.ssid = wdev->wext.ssid; | 193 | wdev->wext.connect.ssid = wdev->wext.ssid; |
184 | memcpy(wdev->wext.ssid, ssid, len); | 194 | memcpy(wdev->wext.ssid, ssid, len); |
185 | wdev->wext.connect.ssid_len = len; | 195 | wdev->wext.connect.ssid_len = len; |
186 | 196 | ||
187 | wdev->wext.connect.crypto.control_port = false; | 197 | wdev->wext.connect.crypto.control_port = false; |
188 | 198 | ||
189 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 199 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
190 | out: | 200 | out: |
191 | wdev_unlock(wdev); | 201 | wdev_unlock(wdev); |
192 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 202 | mutex_unlock(&rdev->devlist_mtx); |
203 | cfg80211_unlock_rdev(rdev); | ||
193 | return err; | 204 | return err; |
194 | } | 205 | } |
195 | 206 | ||
@@ -206,7 +217,15 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, | |||
206 | data->flags = 0; | 217 | data->flags = 0; |
207 | 218 | ||
208 | wdev_lock(wdev); | 219 | wdev_lock(wdev); |
209 | if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | 220 | if (wdev->current_bss) { |
221 | const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, | ||
222 | WLAN_EID_SSID); | ||
223 | if (ie) { | ||
224 | data->flags = 1; | ||
225 | data->length = ie[1]; | ||
226 | memcpy(ssid, ie + 2, data->length); | ||
227 | } | ||
228 | } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | ||
210 | data->flags = 1; | 229 | data->flags = 1; |
211 | data->length = wdev->wext.connect.ssid_len; | 230 | data->length = wdev->wext.connect.ssid_len; |
212 | memcpy(ssid, wdev->wext.connect.ssid, data->length); | 231 | memcpy(ssid, wdev->wext.connect.ssid, data->length); |
@@ -222,6 +241,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
222 | struct sockaddr *ap_addr, char *extra) | 241 | struct sockaddr *ap_addr, char *extra) |
223 | { | 242 | { |
224 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 243 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
244 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
225 | u8 *bssid = ap_addr->sa_data; | 245 | u8 *bssid = ap_addr->sa_data; |
226 | int err; | 246 | int err; |
227 | 247 | ||
@@ -236,7 +256,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
236 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) | 256 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) |
237 | bssid = NULL; | 257 | bssid = NULL; |
238 | 258 | ||
239 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 259 | cfg80211_lock_rdev(rdev); |
260 | mutex_lock(&rdev->devlist_mtx); | ||
240 | wdev_lock(wdev); | 261 | wdev_lock(wdev); |
241 | 262 | ||
242 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 263 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -250,9 +271,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
250 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) | 271 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) |
251 | goto out; | 272 | goto out; |
252 | 273 | ||
253 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 274 | err = __cfg80211_disconnect(rdev, dev, |
254 | dev, WLAN_REASON_DEAUTH_LEAVING, | 275 | WLAN_REASON_DEAUTH_LEAVING, false); |
255 | false); | ||
256 | if (err) | 276 | if (err) |
257 | goto out; | 277 | goto out; |
258 | } | 278 | } |
@@ -263,10 +283,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
263 | } else | 283 | } else |
264 | wdev->wext.connect.bssid = NULL; | 284 | wdev->wext.connect.bssid = NULL; |
265 | 285 | ||
266 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 286 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
267 | out: | 287 | out: |
268 | wdev_unlock(wdev); | 288 | wdev_unlock(wdev); |
269 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 289 | mutex_unlock(&rdev->devlist_mtx); |
290 | cfg80211_unlock_rdev(rdev); | ||
270 | return err; | 291 | return err; |
271 | } | 292 | } |
272 | 293 | ||