aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-02 11:20:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:53 -0400
commit19957bb399e2722719c0e20c9ae91cf8b6aaff04 (patch)
tree9c4d53fe5938ceee41333a1afd5be0ed5c1ce313 /net/wireless
parent517357c685ccc4b5783cc7dbdae8824ada19a97f (diff)
cfg80211: keep track of BSSes
In order to avoid problems with BSS structs going away while they're in use, I've long wanted to make cfg80211 keep track of them. Without the SME, that wasn't doable but now that we have the SME we can do this too. It can keep track of up to four separate authentications and one association, regardless of whether it's controlled by the cfg80211 SME or the userspace SME. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c5
-rw-r--r--net/wireless/core.h41
-rw-r--r--net/wireless/ibss.c12
-rw-r--r--net/wireless/mlme.c357
-rw-r--r--net/wireless/nl80211.c144
-rw-r--r--net/wireless/scan.c31
-rw-r--r--net/wireless/sme.c156
-rw-r--r--net/wireless/wext-sme.c4
8 files changed, 557 insertions, 193 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 5f6a8322bcb3..7b66cf15349a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -583,15 +583,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
583#endif 583#endif
584 cfg80211_disconnect(rdev, dev, 584 cfg80211_disconnect(rdev, dev,
585 WLAN_REASON_DEAUTH_LEAVING, true); 585 WLAN_REASON_DEAUTH_LEAVING, true);
586 cfg80211_mlme_down(rdev, dev);
586 break; 587 break;
587 default: 588 default:
588 break; 589 break;
589 } 590 }
590 break; 591 break;
591 case NETDEV_DOWN:
592 kfree(wdev->conn);
593 wdev->conn = NULL;
594 break;
595 case NETDEV_UP: 592 case NETDEV_UP:
596#ifdef CONFIG_WIRELESS_EXT 593#ifdef CONFIG_WIRELESS_EXT
597 switch (wdev->iftype) { 594 switch (wdev->iftype) {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5209acb0ff7e..82918f5896a5 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -110,12 +110,30 @@ struct cfg80211_internal_bss {
110 struct rb_node rbn; 110 struct rb_node rbn;
111 unsigned long ts; 111 unsigned long ts;
112 struct kref ref; 112 struct kref ref;
113 bool hold, ies_allocated; 113 atomic_t hold;
114 bool ies_allocated;
114 115
115 /* must be last because of priv member */ 116 /* must be last because of priv member */
116 struct cfg80211_bss pub; 117 struct cfg80211_bss pub;
117}; 118};
118 119
120static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub)
121{
122 return container_of(pub, struct cfg80211_internal_bss, pub);
123}
124
125static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
126{
127 atomic_inc(&bss->hold);
128}
129
130static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
131{
132 int r = atomic_dec_return(&bss->hold);
133 WARN_ON(r < 0);
134}
135
136
119struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); 137struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
120int get_wiphy_idx(struct wiphy *wiphy); 138int get_wiphy_idx(struct wiphy *wiphy);
121 139
@@ -176,6 +194,26 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
176int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 194int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
177 struct net_device *dev, bool nowext); 195 struct net_device *dev, bool nowext);
178 196
197/* MLME */
198int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
199 struct net_device *dev, struct ieee80211_channel *chan,
200 enum nl80211_auth_type auth_type, const u8 *bssid,
201 const u8 *ssid, int ssid_len,
202 const u8 *ie, int ie_len);
203int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
204 struct net_device *dev, struct ieee80211_channel *chan,
205 const u8 *bssid, const u8 *ssid, int ssid_len,
206 const u8 *ie, int ie_len, bool use_mfp,
207 struct cfg80211_crypto_settings *crypt);
208int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
209 struct net_device *dev, const u8 *bssid,
210 const u8 *ie, int ie_len, u16 reason);
211int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
212 struct net_device *dev, const u8 *bssid,
213 const u8 *ie, int ie_len, u16 reason);
214void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
215 struct net_device *dev);
216
179/* SME */ 217/* SME */
180int cfg80211_connect(struct cfg80211_registered_device *rdev, 218int cfg80211_connect(struct cfg80211_registered_device *rdev,
181 struct net_device *dev, 219 struct net_device *dev,
@@ -193,5 +231,6 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
193 size_t ie_len, u16 reason, bool from_ap); 231 size_t ie_len, u16 reason, bool from_ap);
194void cfg80211_sme_scan_done(struct net_device *dev); 232void cfg80211_sme_scan_done(struct net_device *dev);
195void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 233void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
234void cfg80211_sme_disassoc(struct net_device *dev, int idx);
196 235
197#endif /* __NET_WIRELESS_CORE_H */ 236#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 34b11eae30c8..c92b542d54b0 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -33,11 +33,11 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
33 33
34 if (wdev->current_bss) { 34 if (wdev->current_bss) {
35 cfg80211_unhold_bss(wdev->current_bss); 35 cfg80211_unhold_bss(wdev->current_bss);
36 cfg80211_put_bss(wdev->current_bss); 36 cfg80211_put_bss(&wdev->current_bss->pub);
37 } 37 }
38 38
39 cfg80211_hold_bss(bss); 39 cfg80211_hold_bss(bss_from_pub(bss));
40 wdev->current_bss = bss; 40 wdev->current_bss = bss_from_pub(bss);
41 41
42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); 42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp);
43#ifdef CONFIG_WIRELESS_EXT 43#ifdef CONFIG_WIRELESS_EXT
@@ -78,7 +78,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
78 78
79 if (wdev->current_bss) { 79 if (wdev->current_bss) {
80 cfg80211_unhold_bss(wdev->current_bss); 80 cfg80211_unhold_bss(wdev->current_bss);
81 cfg80211_put_bss(wdev->current_bss); 81 cfg80211_put_bss(&wdev->current_bss->pub);
82 } 82 }
83 83
84 wdev->current_bss = NULL; 84 wdev->current_bss = NULL;
@@ -212,7 +212,7 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
212 return -EINVAL; 212 return -EINVAL;
213 213
214 if (wdev->current_bss) 214 if (wdev->current_bss)
215 chan = wdev->current_bss->channel; 215 chan = wdev->current_bss->pub.channel;
216 else if (wdev->wext.ibss.channel) 216 else if (wdev->wext.ibss.channel)
217 chan = wdev->wext.ibss.channel; 217 chan = wdev->wext.ibss.channel;
218 218
@@ -352,7 +352,7 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
352 ap_addr->sa_family = ARPHRD_ETHER; 352 ap_addr->sa_family = ARPHRD_ETHER;
353 353
354 if (wdev->current_bss) 354 if (wdev->current_bss)
355 memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); 355 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
356 else 356 else
357 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); 357 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
358 return 0; 358 return 0;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3427fe73d3c3..1a92bf7597bf 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -14,8 +14,32 @@
14 14
15void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) 15void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
16{ 16{
17 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 17 struct wireless_dev *wdev = dev->ieee80211_ptr;
18 struct wiphy *wiphy = wdev->wiphy;
18 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 19 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
20 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
21 u8 *bssid = mgmt->bssid;
22 int i;
23 u16 status = le16_to_cpu(mgmt->u.auth.status_code);
24 bool done = false;
25
26 for (i = 0; i < MAX_AUTH_BSSES; i++) {
27 if (wdev->authtry_bsses[i] &&
28 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
29 ETH_ALEN) == 0) {
30 if (status == WLAN_STATUS_SUCCESS) {
31 wdev->auth_bsses[i] = wdev->authtry_bsses[i];
32 } else {
33 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
34 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
35 }
36 wdev->authtry_bsses[i] = NULL;
37 done = true;
38 break;
39 }
40 }
41
42 WARN_ON(!done);
19 43
20 nl80211_send_rx_auth(rdev, dev, buf, len, gfp); 44 nl80211_send_rx_auth(rdev, dev, buf, len, gfp);
21 cfg80211_sme_rx_auth(dev, buf, len); 45 cfg80211_sme_rx_auth(dev, buf, len);
@@ -30,7 +54,8 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g
30 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 54 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
31 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 55 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
32 u8 *ie = mgmt->u.assoc_resp.variable; 56 u8 *ie = mgmt->u.assoc_resp.variable;
33 int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 57 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
58 bool done;
34 59
35 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); 60 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
36 61
@@ -38,6 +63,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g
38 63
39 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, 64 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
40 status_code, gfp); 65 status_code, gfp);
66
67 if (status_code == WLAN_STATUS_SUCCESS) {
68 for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
69 if (wdev->auth_bsses[i] == wdev->current_bss) {
70 cfg80211_unhold_bss(wdev->auth_bsses[i]);
71 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
72 wdev->auth_bsses[i] = NULL;
73 done = true;
74 break;
75 }
76 }
77
78 WARN_ON(!done);
79 }
41} 80}
42EXPORT_SYMBOL(cfg80211_send_rx_assoc); 81EXPORT_SYMBOL(cfg80211_send_rx_assoc);
43 82
@@ -47,9 +86,45 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp
47 struct wiphy *wiphy = wdev->wiphy; 86 struct wiphy *wiphy = wdev->wiphy;
48 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 87 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
49 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 88 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
89 const u8 *bssid = mgmt->bssid;
90 int i;
91 bool done = false;
50 92
51 nl80211_send_deauth(rdev, dev, buf, len, gfp); 93 nl80211_send_deauth(rdev, dev, buf, len, gfp);
52 94
95 if (wdev->current_bss &&
96 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
97 done = true;
98 cfg80211_unhold_bss(wdev->current_bss);
99 cfg80211_put_bss(&wdev->current_bss->pub);
100 wdev->current_bss = NULL;
101 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
102 if (wdev->auth_bsses[i] &&
103 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
104 cfg80211_unhold_bss(wdev->auth_bsses[i]);
105 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
106 wdev->auth_bsses[i] = NULL;
107 done = true;
108 break;
109 }
110 if (wdev->authtry_bsses[i] &&
111 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
112 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
113 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
114 wdev->authtry_bsses[i] = NULL;
115 done = true;
116 break;
117 }
118 }
119/*
120 * mac80211 currently triggers this warning,
121 * so disable for now (it's harmless, just
122 * means that we got a spurious event)
123
124 WARN_ON(!done);
125
126 */
127
53 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 128 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
54 u16 reason_code; 129 u16 reason_code;
55 bool from_ap; 130 bool from_ap;
@@ -59,8 +134,6 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp
59 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; 134 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
60 __cfg80211_disconnected(dev, gfp, NULL, 0, 135 __cfg80211_disconnected(dev, gfp, NULL, 0,
61 reason_code, from_ap); 136 reason_code, from_ap);
62
63 wdev->sme_state = CFG80211_SME_IDLE;
64 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { 137 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
65 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, 138 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
66 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); 139 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
@@ -74,21 +147,38 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g
74 struct wiphy *wiphy = wdev->wiphy; 147 struct wiphy *wiphy = wdev->wiphy;
75 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 148 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
76 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 149 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
150 const u8 *bssid = mgmt->bssid;
151 int i;
152 u16 reason_code;
153 bool from_ap;
154 bool done = false;
77 155
78 nl80211_send_disassoc(rdev, dev, buf, len, gfp); 156 nl80211_send_disassoc(rdev, dev, buf, len, gfp);
79 157
80 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 158 if (!wdev->sme_state == CFG80211_SME_CONNECTED)
81 u16 reason_code; 159 return;
82 bool from_ap;
83 160
84 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); 161 if (wdev->current_bss &&
162 memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
163 for (i = 0; i < MAX_AUTH_BSSES; i++) {
164 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
165 continue;
166 wdev->auth_bsses[i] = wdev->current_bss;
167 wdev->current_bss = NULL;
168 done = true;
169 cfg80211_sme_disassoc(dev, i);
170 break;
171 }
172 WARN_ON(!done);
173 } else
174 WARN_ON(1);
85 175
86 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
87 __cfg80211_disconnected(dev, gfp, NULL, 0,
88 reason_code, from_ap);
89 176
90 wdev->sme_state = CFG80211_SME_IDLE; 177 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
91 } 178
179 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
180 __cfg80211_disconnected(dev, gfp, NULL, 0,
181 reason_code, from_ap);
92} 182}
93EXPORT_SYMBOL(cfg80211_send_disassoc); 183EXPORT_SYMBOL(cfg80211_send_disassoc);
94 184
@@ -97,11 +187,27 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf
97 struct wireless_dev *wdev = dev->ieee80211_ptr; 187 struct wireless_dev *wdev = dev->ieee80211_ptr;
98 struct wiphy *wiphy = wdev->wiphy; 188 struct wiphy *wiphy = wdev->wiphy;
99 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 189 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
190 int i;
191 bool done = false;
192
100 nl80211_send_auth_timeout(rdev, dev, addr, gfp); 193 nl80211_send_auth_timeout(rdev, dev, addr, gfp);
101 if (wdev->sme_state == CFG80211_SME_CONNECTING) 194 if (wdev->sme_state == CFG80211_SME_CONNECTING)
102 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, 195 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
103 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); 196 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
104 wdev->sme_state = CFG80211_SME_IDLE; 197
198 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
199 if (wdev->authtry_bsses[i] &&
200 memcmp(wdev->authtry_bsses[i]->pub.bssid,
201 addr, ETH_ALEN) == 0) {
202 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
203 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
204 wdev->authtry_bsses[i] = NULL;
205 done = true;
206 break;
207 }
208 }
209
210 WARN_ON(!done);
105} 211}
106EXPORT_SYMBOL(cfg80211_send_auth_timeout); 212EXPORT_SYMBOL(cfg80211_send_auth_timeout);
107 213
@@ -110,11 +216,27 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g
110 struct wireless_dev *wdev = dev->ieee80211_ptr; 216 struct wireless_dev *wdev = dev->ieee80211_ptr;
111 struct wiphy *wiphy = wdev->wiphy; 217 struct wiphy *wiphy = wdev->wiphy;
112 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 218 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
219 int i;
220 bool done = false;
221
113 nl80211_send_assoc_timeout(rdev, dev, addr, gfp); 222 nl80211_send_assoc_timeout(rdev, dev, addr, gfp);
114 if (wdev->sme_state == CFG80211_SME_CONNECTING) 223 if (wdev->sme_state == CFG80211_SME_CONNECTING)
115 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, 224 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
116 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); 225 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
117 wdev->sme_state = CFG80211_SME_IDLE; 226
227 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
228 if (wdev->auth_bsses[i] &&
229 memcmp(wdev->auth_bsses[i]->pub.bssid,
230 addr, ETH_ALEN) == 0) {
231 cfg80211_unhold_bss(wdev->auth_bsses[i]);
232 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
233 wdev->auth_bsses[i] = NULL;
234 done = true;
235 break;
236 }
237 }
238
239 WARN_ON(!done);
118} 240}
119EXPORT_SYMBOL(cfg80211_send_assoc_timeout); 241EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
120 242
@@ -143,3 +265,208 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
143 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); 265 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
144} 266}
145EXPORT_SYMBOL(cfg80211_michael_mic_failure); 267EXPORT_SYMBOL(cfg80211_michael_mic_failure);
268
269/* some MLME handling for userspace SME */
270int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
271 struct net_device *dev, struct ieee80211_channel *chan,
272 enum nl80211_auth_type auth_type, const u8 *bssid,
273 const u8 *ssid, int ssid_len,
274 const u8 *ie, int ie_len)
275{
276 struct wireless_dev *wdev = dev->ieee80211_ptr;
277 struct cfg80211_auth_request req;
278 struct cfg80211_internal_bss *bss;
279 int i, err, slot = -1, nfree = 0;
280
281 memset(&req, 0, sizeof(req));
282
283 req.ie = ie;
284 req.ie_len = ie_len;
285 req.auth_type = auth_type;
286 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
287 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
288 if (!req.bss)
289 return -ENOENT;
290
291 bss = bss_from_pub(req.bss);
292
293 for (i = 0; i < MAX_AUTH_BSSES; i++) {
294 if (bss == wdev->auth_bsses[i]) {
295 err = -EALREADY;
296 goto out;
297 }
298 }
299
300 for (i = 0; i < MAX_AUTH_BSSES; i++) {
301 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
302 slot = i;
303 nfree++;
304 }
305 }
306
307 /* we need one free slot for disassoc and one for this auth */
308 if (nfree < 2) {
309 err = -ENOSPC;
310 goto out;
311 }
312
313 wdev->authtry_bsses[slot] = bss;
314 cfg80211_hold_bss(bss);
315
316 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
317 if (err) {
318 wdev->authtry_bsses[slot] = NULL;
319 cfg80211_unhold_bss(bss);
320 }
321
322 out:
323 if (err)
324 cfg80211_put_bss(req.bss);
325 return err;
326}
327
328int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
329 struct net_device *dev, struct ieee80211_channel *chan,
330 const u8 *bssid, const u8 *ssid, int ssid_len,
331 const u8 *ie, int ie_len, bool use_mfp,
332 struct cfg80211_crypto_settings *crypt)
333{
334 struct wireless_dev *wdev = dev->ieee80211_ptr;
335 struct cfg80211_assoc_request req;
336 struct cfg80211_internal_bss *bss;
337 int i, err, slot = -1;
338
339 memset(&req, 0, sizeof(req));
340
341 if (wdev->current_bss)
342 return -EALREADY;
343
344 req.ie = ie;
345 req.ie_len = ie_len;
346 memcpy(&req.crypto, crypt, sizeof(req.crypto));
347 req.use_mfp = use_mfp;
348 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
349 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
350 if (!req.bss)
351 return -ENOENT;
352
353 bss = bss_from_pub(req.bss);
354
355 for (i = 0; i < MAX_AUTH_BSSES; i++) {
356 if (bss == wdev->auth_bsses[i]) {
357 slot = i;
358 break;
359 }
360 }
361
362 if (slot < 0) {
363 err = -ENOTCONN;
364 goto out;
365 }
366
367 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
368 out:
369 /* still a reference in wdev->auth_bsses[slot] */
370 cfg80211_put_bss(req.bss);
371 return err;
372}
373
374int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
375 struct net_device *dev, const u8 *bssid,
376 const u8 *ie, int ie_len, u16 reason)
377{
378 struct wireless_dev *wdev = dev->ieee80211_ptr;
379 struct cfg80211_deauth_request req;
380 int i;
381
382 memset(&req, 0, sizeof(req));
383 req.reason_code = reason;
384 req.ie = ie;
385 req.ie_len = ie_len;
386 if (wdev->current_bss &&
387 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
388 req.bss = &wdev->current_bss->pub;
389 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
390 if (wdev->auth_bsses[i] &&
391 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
392 req.bss = &wdev->auth_bsses[i]->pub;
393 break;
394 }
395 if (wdev->authtry_bsses[i] &&
396 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
397 req.bss = &wdev->authtry_bsses[i]->pub;
398 break;
399 }
400 }
401
402 if (!req.bss)
403 return -ENOTCONN;
404
405 return rdev->ops->deauth(&rdev->wiphy, dev, &req);
406}
407
408int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
409 struct net_device *dev, const u8 *bssid,
410 const u8 *ie, int ie_len, u16 reason)
411{
412 struct wireless_dev *wdev = dev->ieee80211_ptr;
413 struct cfg80211_disassoc_request req;
414
415 memset(&req, 0, sizeof(req));
416 req.reason_code = reason;
417 req.ie = ie;
418 req.ie_len = ie_len;
419 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
420 req.bss = &wdev->current_bss->pub;
421 else
422 return -ENOTCONN;
423
424 return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
425}
426
427void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
428 struct net_device *dev)
429{
430 struct wireless_dev *wdev = dev->ieee80211_ptr;
431 struct cfg80211_deauth_request req;
432 int i;
433
434 if (!rdev->ops->deauth)
435 return;
436
437 memset(&req, 0, sizeof(req));
438 req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
439 req.ie = NULL;
440 req.ie_len = 0;
441
442 if (wdev->current_bss) {
443 req.bss = &wdev->current_bss->pub;
444 rdev->ops->deauth(&rdev->wiphy, dev, &req);
445 if (wdev->current_bss) {
446 cfg80211_unhold_bss(wdev->current_bss);
447 cfg80211_put_bss(&wdev->current_bss->pub);
448 wdev->current_bss = NULL;
449 }
450 }
451
452 for (i = 0; i < MAX_AUTH_BSSES; i++) {
453 if (wdev->auth_bsses[i]) {
454 req.bss = &wdev->auth_bsses[i]->pub;
455 rdev->ops->deauth(&rdev->wiphy, dev, &req);
456 if (wdev->auth_bsses[i]) {
457 cfg80211_unhold_bss(wdev->auth_bsses[i]);
458 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
459 wdev->auth_bsses[i] = NULL;
460 }
461 }
462 if (wdev->authtry_bsses[i]) {
463 req.bss = &wdev->authtry_bsses[i]->pub;
464 rdev->ops->deauth(&rdev->wiphy, dev, &req);
465 if (wdev->authtry_bsses[i]) {
466 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
467 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
468 wdev->authtry_bsses[i] = NULL;
469 }
470 }
471 }
472}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0008144b354b..aa2b3f35cc48 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3044,9 +3044,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3044{ 3044{
3045 struct cfg80211_registered_device *drv; 3045 struct cfg80211_registered_device *drv;
3046 struct net_device *dev; 3046 struct net_device *dev;
3047 struct cfg80211_auth_request req; 3047 struct ieee80211_channel *chan;
3048 struct wiphy *wiphy; 3048 const u8 *bssid, *ssid, *ie = NULL;
3049 int err; 3049 int err, ssid_len, ie_len = 0;
3050 enum nl80211_auth_type auth_type;
3050 3051
3051 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3052 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3052 return -EINVAL; 3053 return -EINVAL;
@@ -3057,6 +3058,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3057 if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) 3058 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
3058 return -EINVAL; 3059 return -EINVAL;
3059 3060
3061 if (!info->attrs[NL80211_ATTR_SSID])
3062 return -EINVAL;
3063
3064 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
3065 return -EINVAL;
3066
3060 rtnl_lock(); 3067 rtnl_lock();
3061 3068
3062 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 3069 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -3078,38 +3085,30 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3078 goto out; 3085 goto out;
3079 } 3086 }
3080 3087
3081 wiphy = &drv->wiphy; 3088 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3082 memset(&req, 0, sizeof(req)); 3089 chan = ieee80211_get_channel(&drv->wiphy,
3083 3090 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3084 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 3091 if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
3085 3092 err = -EINVAL;
3086 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 3093 goto out;
3087 req.chan = ieee80211_get_channel(
3088 wiphy,
3089 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3090 if (!req.chan) {
3091 err = -EINVAL;
3092 goto out;
3093 }
3094 } 3094 }
3095 3095
3096 if (info->attrs[NL80211_ATTR_SSID]) { 3096 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3097 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3097 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3098 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3099 }
3100 3098
3101 if (info->attrs[NL80211_ATTR_IE]) { 3099 if (info->attrs[NL80211_ATTR_IE]) {
3102 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3100 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3103 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3101 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3104 } 3102 }
3105 3103
3106 req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); 3104 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
3107 if (!nl80211_valid_auth_type(req.auth_type)) { 3105 if (!nl80211_valid_auth_type(auth_type)) {
3108 err = -EINVAL; 3106 err = -EINVAL;
3109 goto out; 3107 goto out;
3110 } 3108 }
3111 3109
3112 err = drv->ops->auth(&drv->wiphy, dev, &req); 3110 err = cfg80211_mlme_auth(drv, dev, chan, auth_type, bssid,
3111 ssid, ssid_len, ie, ie_len);
3113 3112
3114out: 3113out:
3115 cfg80211_put_dev(drv); 3114 cfg80211_put_dev(drv);
@@ -3183,26 +3182,29 @@ static int nl80211_crypto_settings(struct genl_info *info,
3183 3182
3184static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) 3183static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3185{ 3184{
3186 struct cfg80211_registered_device *drv; 3185 struct cfg80211_registered_device *rdev;
3187 struct net_device *dev; 3186 struct net_device *dev;
3188 struct cfg80211_assoc_request req; 3187 struct cfg80211_crypto_settings crypto;
3189 struct wiphy *wiphy; 3188 struct ieee80211_channel *chan;
3190 int err; 3189 const u8 *bssid, *ssid, *ie = NULL;
3190 int err, ssid_len, ie_len = 0;
3191 bool use_mfp = false;
3191 3192
3192 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3193 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3193 return -EINVAL; 3194 return -EINVAL;
3194 3195
3195 if (!info->attrs[NL80211_ATTR_MAC] || 3196 if (!info->attrs[NL80211_ATTR_MAC] ||
3196 !info->attrs[NL80211_ATTR_SSID]) 3197 !info->attrs[NL80211_ATTR_SSID] ||
3198 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
3197 return -EINVAL; 3199 return -EINVAL;
3198 3200
3199 rtnl_lock(); 3201 rtnl_lock();
3200 3202
3201 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 3203 err = get_drv_dev_by_info_ifindex(info->attrs, &rdev, &dev);
3202 if (err) 3204 if (err)
3203 goto unlock_rtnl; 3205 goto unlock_rtnl;
3204 3206
3205 if (!drv->ops->assoc) { 3207 if (!rdev->ops->assoc) {
3206 err = -EOPNOTSUPP; 3208 err = -EOPNOTSUPP;
3207 goto out; 3209 goto out;
3208 } 3210 }
@@ -3217,46 +3219,42 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3217 goto out; 3219 goto out;
3218 } 3220 }
3219 3221
3220 wiphy = &drv->wiphy; 3222 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3221 memset(&req, 0, sizeof(req));
3222
3223 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3224 3223
3225 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 3224 chan = ieee80211_get_channel(&rdev->wiphy,
3226 req.chan = ieee80211_get_channel( 3225 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3227 wiphy, 3226 if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
3228 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); 3227 err = -EINVAL;
3229 if (!req.chan) { 3228 goto out;
3230 err = -EINVAL;
3231 goto out;
3232 }
3233 } 3229 }
3234 3230
3235 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3231 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3236 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3232 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3237 3233
3238 if (info->attrs[NL80211_ATTR_IE]) { 3234 if (info->attrs[NL80211_ATTR_IE]) {
3239 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3235 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3240 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3236 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3241 } 3237 }
3242 3238
3243 if (info->attrs[NL80211_ATTR_USE_MFP]) { 3239 if (info->attrs[NL80211_ATTR_USE_MFP]) {
3244 enum nl80211_mfp use_mfp = 3240 enum nl80211_mfp use_mfp =
3245 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); 3241 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
3246 if (use_mfp == NL80211_MFP_REQUIRED) 3242 if (use_mfp == NL80211_MFP_REQUIRED)
3247 req.use_mfp = true; 3243 use_mfp = true;
3248 else if (use_mfp != NL80211_MFP_NO) { 3244 else if (use_mfp != NL80211_MFP_NO) {
3249 err = -EINVAL; 3245 err = -EINVAL;
3250 goto out; 3246 goto out;
3251 } 3247 }
3252 } 3248 }
3253 3249
3254 err = nl80211_crypto_settings(info, &req.crypto); 3250 err = nl80211_crypto_settings(info, &crypto);
3255 if (!err) 3251 if (!err)
3256 err = drv->ops->assoc(&drv->wiphy, dev, &req); 3252 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid,
3253 ssid_len, ie, ie_len, use_mfp,
3254 &crypto);
3257 3255
3258out: 3256out:
3259 cfg80211_put_dev(drv); 3257 cfg80211_put_dev(rdev);
3260 dev_put(dev); 3258 dev_put(dev);
3261unlock_rtnl: 3259unlock_rtnl:
3262 rtnl_unlock(); 3260 rtnl_unlock();
@@ -3267,9 +3265,9 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3267{ 3265{
3268 struct cfg80211_registered_device *drv; 3266 struct cfg80211_registered_device *drv;
3269 struct net_device *dev; 3267 struct net_device *dev;
3270 struct cfg80211_deauth_request req; 3268 const u8 *ie = NULL, *bssid;
3271 struct wiphy *wiphy; 3269 int err, ie_len = 0;
3272 int err; 3270 u16 reason_code;
3273 3271
3274 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3272 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3275 return -EINVAL; 3273 return -EINVAL;
@@ -3301,24 +3299,21 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3301 goto out; 3299 goto out;
3302 } 3300 }
3303 3301
3304 wiphy = &drv->wiphy; 3302 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3305 memset(&req, 0, sizeof(req));
3306
3307 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3308 3303
3309 req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3304 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
3310 if (req.reason_code == 0) { 3305 if (reason_code == 0) {
3311 /* Reason Code 0 is reserved */ 3306 /* Reason Code 0 is reserved */
3312 err = -EINVAL; 3307 err = -EINVAL;
3313 goto out; 3308 goto out;
3314 } 3309 }
3315 3310
3316 if (info->attrs[NL80211_ATTR_IE]) { 3311 if (info->attrs[NL80211_ATTR_IE]) {
3317 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3312 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3318 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3313 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3319 } 3314 }
3320 3315
3321 err = drv->ops->deauth(&drv->wiphy, dev, &req); 3316 err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code);
3322 3317
3323out: 3318out:
3324 cfg80211_put_dev(drv); 3319 cfg80211_put_dev(drv);
@@ -3332,9 +3327,9 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3332{ 3327{
3333 struct cfg80211_registered_device *drv; 3328 struct cfg80211_registered_device *drv;
3334 struct net_device *dev; 3329 struct net_device *dev;
3335 struct cfg80211_disassoc_request req; 3330 const u8 *ie = NULL, *bssid;
3336 struct wiphy *wiphy; 3331 int err, ie_len = 0;
3337 int err; 3332 u16 reason_code;
3338 3333
3339 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3334 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3340 return -EINVAL; 3335 return -EINVAL;
@@ -3366,24 +3361,21 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3366 goto out; 3361 goto out;
3367 } 3362 }
3368 3363
3369 wiphy = &drv->wiphy; 3364 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3370 memset(&req, 0, sizeof(req));
3371
3372 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3373 3365
3374 req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3366 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
3375 if (req.reason_code == 0) { 3367 if (reason_code == 0) {
3376 /* Reason Code 0 is reserved */ 3368 /* Reason Code 0 is reserved */
3377 err = -EINVAL; 3369 err = -EINVAL;
3378 goto out; 3370 goto out;
3379 } 3371 }
3380 3372
3381 if (info->attrs[NL80211_ATTR_IE]) { 3373 if (info->attrs[NL80211_ATTR_IE]) {
3382 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3374 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3383 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3375 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3384 } 3376 }
3385 3377
3386 err = drv->ops->disassoc(&drv->wiphy, dev, &req); 3378 err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code);
3387 3379
3388out: 3380out:
3389 cfg80211_put_dev(drv); 3381 cfg80211_put_dev(drv);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 82b33e708488..925399462a79 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -70,6 +70,8 @@ static void bss_release(struct kref *ref)
70 if (bss->ies_allocated) 70 if (bss->ies_allocated)
71 kfree(bss->pub.information_elements); 71 kfree(bss->pub.information_elements);
72 72
73 BUG_ON(atomic_read(&bss->hold));
74
73 kfree(bss); 75 kfree(bss);
74} 76}
75 77
@@ -92,8 +94,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
92 bool expired = false; 94 bool expired = false;
93 95
94 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { 96 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
95 if (bss->hold || 97 if (atomic_read(&bss->hold))
96 !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) 98 continue;
99 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
97 continue; 100 continue;
98 list_del(&bss->list); 101 list_del(&bss->list);
99 rb_erase(&bss->rbn, &dev->bss_tree); 102 rb_erase(&bss->rbn, &dev->bss_tree);
@@ -553,30 +556,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
553} 556}
554EXPORT_SYMBOL(cfg80211_unlink_bss); 557EXPORT_SYMBOL(cfg80211_unlink_bss);
555 558
556void cfg80211_hold_bss(struct cfg80211_bss *pub)
557{
558 struct cfg80211_internal_bss *bss;
559
560 if (!pub)
561 return;
562
563 bss = container_of(pub, struct cfg80211_internal_bss, pub);
564 bss->hold = true;
565}
566EXPORT_SYMBOL(cfg80211_hold_bss);
567
568void cfg80211_unhold_bss(struct cfg80211_bss *pub)
569{
570 struct cfg80211_internal_bss *bss;
571
572 if (!pub)
573 return;
574
575 bss = container_of(pub, struct cfg80211_internal_bss, pub);
576 bss->hold = false;
577}
578EXPORT_SYMBOL(cfg80211_unhold_bss);
579
580#ifdef CONFIG_WIRELESS_EXT 559#ifdef CONFIG_WIRELESS_EXT
581int cfg80211_wext_siwscan(struct net_device *dev, 560int cfg80211_wext_siwscan(struct net_device *dev,
582 struct iw_request_info *info, 561 struct iw_request_info *info,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d4e0b4065cbc..412161f7b08e 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -103,44 +103,37 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
103static int cfg80211_conn_do_work(struct wireless_dev *wdev) 103static int cfg80211_conn_do_work(struct wireless_dev *wdev)
104{ 104{
105 struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); 105 struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
106 union { 106 struct cfg80211_connect_params *params;
107 struct cfg80211_auth_request auth_req; 107 int err;
108 struct cfg80211_assoc_request assoc_req;
109 } u;
110
111 memset(&u, 0, sizeof(u));
112 108
113 if (!wdev->conn) 109 if (!wdev->conn)
114 return 0; 110 return 0;
115 111
112 params = &wdev->conn->params;
113
116 switch (wdev->conn->state) { 114 switch (wdev->conn->state) {
117 case CFG80211_CONN_SCAN_AGAIN: 115 case CFG80211_CONN_SCAN_AGAIN:
118 return cfg80211_conn_scan(wdev); 116 return cfg80211_conn_scan(wdev);
119 case CFG80211_CONN_AUTHENTICATE_NEXT: 117 case CFG80211_CONN_AUTHENTICATE_NEXT:
120 u.auth_req.chan = wdev->conn->params.channel;
121 u.auth_req.peer_addr = wdev->conn->params.bssid;
122 u.auth_req.ssid = wdev->conn->params.ssid;
123 u.auth_req.ssid_len = wdev->conn->params.ssid_len;
124 u.auth_req.auth_type = wdev->conn->params.auth_type;
125 u.auth_req.ie = NULL;
126 u.auth_req.ie_len = 0;
127 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
128 BUG_ON(!drv->ops->auth); 118 BUG_ON(!drv->ops->auth);
129 return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); 119 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
120 return cfg80211_mlme_auth(drv, wdev->netdev,
121 params->channel, params->auth_type,
122 params->bssid,
123 params->ssid, params->ssid_len,
124 NULL, 0);
130 case CFG80211_CONN_ASSOCIATE_NEXT: 125 case CFG80211_CONN_ASSOCIATE_NEXT:
131 u.assoc_req.chan = wdev->conn->params.channel;
132 u.assoc_req.peer_addr = wdev->conn->params.bssid;
133 u.assoc_req.ssid = wdev->conn->params.ssid;
134 u.assoc_req.ssid_len = wdev->conn->params.ssid_len;
135 u.assoc_req.ie = wdev->conn->params.ie;
136 u.assoc_req.ie_len = wdev->conn->params.ie_len;
137 u.assoc_req.use_mfp = false;
138 memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto,
139 sizeof(u.assoc_req.crypto));
140 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
141 BUG_ON(!drv->ops->assoc); 126 BUG_ON(!drv->ops->assoc);
142 return drv->ops->assoc(wdev->wiphy, wdev->netdev, 127 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
143 &u.assoc_req); 128 err = cfg80211_mlme_assoc(drv, wdev->netdev,
129 params->channel, params->bssid,
130 params->ssid, params->ssid_len,
131 params->ie, params->ie_len,
132 false, &params->crypto);
133 if (err)
134 cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid,
135 NULL, 0, WLAN_REASON_DEAUTH_LEAVING);
136 return err;
144 default: 137 default:
145 return 0; 138 return 0;
146 } 139 }
@@ -186,7 +179,6 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
186 wdev->conn->params.ssid_len, 179 wdev->conn->params.ssid_len,
187 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, 180 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
188 capa); 181 capa);
189
190 if (!bss) 182 if (!bss)
191 return false; 183 return false;
192 184
@@ -264,9 +256,11 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
264 } 256 }
265 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 257 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
266 schedule_work(&rdev->conn_work); 258 schedule_work(&rdev->conn_work);
267 } else if (status_code != WLAN_STATUS_SUCCESS) 259 } else if (status_code != WLAN_STATUS_SUCCESS) {
268 wdev->sme_state = CFG80211_SME_IDLE; 260 wdev->sme_state = CFG80211_SME_IDLE;
269 else if (wdev->sme_state == CFG80211_SME_CONNECTING && 261 kfree(wdev->conn);
262 wdev->conn = NULL;
263 } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
270 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { 264 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
271 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; 265 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
272 schedule_work(&rdev->conn_work); 266 schedule_work(&rdev->conn_work);
@@ -330,10 +324,13 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
330 324
331 if (wdev->current_bss) { 325 if (wdev->current_bss) {
332 cfg80211_unhold_bss(wdev->current_bss); 326 cfg80211_unhold_bss(wdev->current_bss);
333 cfg80211_put_bss(wdev->current_bss); 327 cfg80211_put_bss(&wdev->current_bss->pub);
334 wdev->current_bss = NULL; 328 wdev->current_bss = NULL;
335 } 329 }
336 330
331 if (wdev->conn)
332 wdev->conn->state = CFG80211_CONN_IDLE;
333
337 if (status == WLAN_STATUS_SUCCESS) { 334 if (status == WLAN_STATUS_SUCCESS) {
338 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, 335 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
339 wdev->ssid, wdev->ssid_len, 336 wdev->ssid, wdev->ssid_len,
@@ -343,16 +340,15 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
343 if (WARN_ON(!bss)) 340 if (WARN_ON(!bss))
344 return; 341 return;
345 342
346 cfg80211_hold_bss(bss); 343 cfg80211_hold_bss(bss_from_pub(bss));
347 wdev->current_bss = bss; 344 wdev->current_bss = bss_from_pub(bss);
348 345
349 wdev->sme_state = CFG80211_SME_CONNECTED; 346 wdev->sme_state = CFG80211_SME_CONNECTED;
350 } else { 347 } else {
351 wdev->sme_state = CFG80211_SME_IDLE; 348 wdev->sme_state = CFG80211_SME_IDLE;
349 kfree(wdev->conn);
350 wdev->conn = NULL;
352 } 351 }
353
354 if (wdev->conn)
355 wdev->conn->state = CFG80211_CONN_IDLE;
356} 352}
357 353
358void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 354void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -387,7 +383,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
387 } 383 }
388 384
389 cfg80211_unhold_bss(wdev->current_bss); 385 cfg80211_unhold_bss(wdev->current_bss);
390 cfg80211_put_bss(wdev->current_bss); 386 cfg80211_put_bss(&wdev->current_bss->pub);
391 wdev->current_bss = NULL; 387 wdev->current_bss = NULL;
392 388
393 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, 389 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
@@ -397,8 +393,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
397 if (WARN_ON(!bss)) 393 if (WARN_ON(!bss))
398 return; 394 return;
399 395
400 cfg80211_hold_bss(bss); 396 cfg80211_hold_bss(bss_from_pub(bss));
401 wdev->current_bss = bss; 397 wdev->current_bss = bss_from_pub(bss);
402 398
403 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, 399 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
404 req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); 400 req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
@@ -440,7 +436,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
440 436
441 if (wdev->current_bss) { 437 if (wdev->current_bss) {
442 cfg80211_unhold_bss(wdev->current_bss); 438 cfg80211_unhold_bss(wdev->current_bss);
443 cfg80211_put_bss(wdev->current_bss); 439 cfg80211_put_bss(&wdev->current_bss->pub);
444 } 440 }
445 441
446 wdev->current_bss = NULL; 442 wdev->current_bss = NULL;
@@ -449,6 +445,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
449 if (wdev->conn) { 445 if (wdev->conn) {
450 kfree(wdev->conn->ie); 446 kfree(wdev->conn->ie);
451 wdev->conn->ie = NULL; 447 wdev->conn->ie = NULL;
448 kfree(wdev->conn);
449 wdev->conn = NULL;
452 } 450 }
453 451
454 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, 452 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
@@ -482,12 +480,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
482 if (!rdev->ops->auth || !rdev->ops->assoc) 480 if (!rdev->ops->auth || !rdev->ops->assoc)
483 return -EOPNOTSUPP; 481 return -EOPNOTSUPP;
484 482
485 if (!wdev->conn) { 483 if (WARN_ON(wdev->conn))
486 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); 484 return -EINPROGRESS;
487 if (!wdev->conn) 485
488 return -ENOMEM; 486 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
489 } else 487 if (!wdev->conn)
490 memset(wdev->conn, 0, sizeof(*wdev->conn)); 488 return -ENOMEM;
491 489
492 /* 490 /*
493 * Copy all parameters, and treat explicitly IEs, BSSID, SSID. 491 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
@@ -502,8 +500,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
502 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, 500 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
503 GFP_KERNEL); 501 GFP_KERNEL);
504 wdev->conn->params.ie = wdev->conn->ie; 502 wdev->conn->params.ie = wdev->conn->ie;
505 if (!wdev->conn->ie) 503 if (!wdev->conn->ie) {
504 kfree(wdev->conn);
505 wdev->conn = NULL;
506 return -ENOMEM; 506 return -ENOMEM;
507 }
507 } 508 }
508 509
509 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { 510 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
@@ -543,8 +544,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
543 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; 544 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
544 } 545 }
545 } 546 }
546 if (err) 547 if (err) {
548 kfree(wdev->conn);
549 wdev->conn = NULL;
547 wdev->sme_state = CFG80211_SME_IDLE; 550 wdev->sme_state = CFG80211_SME_IDLE;
551 }
548 552
549 return err; 553 return err;
550 } else { 554 } else {
@@ -572,31 +576,27 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
572 return -EINVAL; 576 return -EINVAL;
573 577
574 if (!rdev->ops->disconnect) { 578 if (!rdev->ops->disconnect) {
575 struct cfg80211_deauth_request deauth; 579 if (!rdev->ops->deauth)
576 u8 bssid[ETH_ALEN]; 580 return -EOPNOTSUPP;
577 581
578 /* internal bug. */ 582 /* was it connected by userspace SME? */
579 if (WARN_ON(!wdev->conn)) 583 if (!wdev->conn) {
580 return -EINVAL; 584 cfg80211_mlme_down(rdev, dev);
585 return 0;
586 }
581 587
582 if (wdev->sme_state == CFG80211_SME_CONNECTING && 588 if (wdev->sme_state == CFG80211_SME_CONNECTING &&
583 (wdev->conn->state == CFG80211_CONN_SCANNING || 589 (wdev->conn->state == CFG80211_CONN_SCANNING ||
584 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { 590 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
585 wdev->sme_state = CFG80211_SME_IDLE; 591 wdev->sme_state = CFG80211_SME_IDLE;
592 kfree(wdev->conn);
593 wdev->conn = NULL;
586 return 0; 594 return 0;
587 } 595 }
588 596
589 if (!rdev->ops->deauth)
590 return -EOPNOTSUPP;
591
592 memset(&deauth, 0, sizeof(deauth));
593
594 /* wdev->conn->params.bssid must be set if > SCANNING */ 597 /* wdev->conn->params.bssid must be set if > SCANNING */
595 memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); 598 err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid,
596 deauth.peer_addr = bssid; 599 NULL, 0, reason);
597 deauth.reason_code = reason;
598
599 err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth);
600 if (err) 600 if (err)
601 return err; 601 return err;
602 } else { 602 } else {
@@ -614,3 +614,33 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
614 614
615 return 0; 615 return 0;
616} 616}
617
618void cfg80211_sme_disassoc(struct net_device *dev, int idx)
619{
620 struct wireless_dev *wdev = dev->ieee80211_ptr;
621 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
622 u8 bssid[ETH_ALEN];
623
624 if (!wdev->conn)
625 return;
626
627 if (wdev->conn->state == CFG80211_CONN_IDLE)
628 return;
629
630 /*
631 * Ok, so the association was made by this SME -- we don't
632 * want it any more so deauthenticate too.
633 */
634
635 if (!wdev->auth_bsses[idx])
636 return;
637
638 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
639 if (cfg80211_mlme_deauth(rdev, dev, bssid,
640 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
641 /* whatever -- assume gone anyway */
642 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
643 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
644 wdev->auth_bsses[idx] = NULL;
645 }
646}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 3b531d572b69..fe1987acb891 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -93,7 +93,7 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
93 return -EINVAL; 93 return -EINVAL;
94 94
95 if (wdev->current_bss) 95 if (wdev->current_bss)
96 chan = wdev->current_bss->channel; 96 chan = wdev->current_bss->pub.channel;
97 else if (wdev->wext.connect.channel) 97 else if (wdev->wext.connect.channel)
98 chan = wdev->wext.connect.channel; 98 chan = wdev->wext.connect.channel;
99 99
@@ -244,7 +244,7 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
244 ap_addr->sa_family = ARPHRD_ETHER; 244 ap_addr->sa_family = ARPHRD_ETHER;
245 245
246 if (wdev->current_bss) 246 if (wdev->current_bss)
247 memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); 247 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
248 else if (wdev->wext.connect.bssid) 248 else if (wdev->wext.connect.bssid)
249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); 249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
250 else 250 else