aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
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/mlme.c
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/mlme.c')
-rw-r--r--net/wireless/mlme.c357
1 files changed, 342 insertions, 15 deletions
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}