]> Pileus Git - ~andy/linux/blob - net/wireless/mlme.c
cfg80211: mlme API must be able to sleep
[~andy/linux] / net / wireless / mlme.c
1 /*
2  * cfg80211 MLME SAP interface
3  *
4  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5  */
6
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/netdevice.h>
10 #include <linux/nl80211.h>
11 #include <net/cfg80211.h>
12 #include "core.h"
13 #include "nl80211.h"
14
15 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
16 {
17         struct wireless_dev *wdev = dev->ieee80211_ptr;
18         struct wiphy *wiphy = wdev->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         might_sleep();
27
28         for (i = 0; i < MAX_AUTH_BSSES; i++) {
29                 if (wdev->authtry_bsses[i] &&
30                     memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
31                                                         ETH_ALEN) == 0) {
32                         if (status == WLAN_STATUS_SUCCESS) {
33                                 wdev->auth_bsses[i] = wdev->authtry_bsses[i];
34                         } else {
35                                 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
36                                 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
37                         }
38                         wdev->authtry_bsses[i] = NULL;
39                         done = true;
40                         break;
41                 }
42         }
43
44         WARN_ON(!done);
45
46         nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
47         cfg80211_sme_rx_auth(dev, buf, len);
48 }
49 EXPORT_SYMBOL(cfg80211_send_rx_auth);
50
51 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
52 {
53         u16 status_code;
54         struct wireless_dev *wdev = dev->ieee80211_ptr;
55         struct wiphy *wiphy = wdev->wiphy;
56         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
57         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
58         u8 *ie = mgmt->u.assoc_resp.variable;
59         int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
60         bool done;
61
62         might_sleep();
63
64         status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
65
66         nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
67
68         cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
69                                 status_code, GFP_KERNEL);
70
71         if (status_code == WLAN_STATUS_SUCCESS) {
72                 for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
73                         if (wdev->auth_bsses[i] == wdev->current_bss) {
74                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
75                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
76                                 wdev->auth_bsses[i] = NULL;
77                                 done = true;
78                                 break;
79                         }
80                 }
81
82                 WARN_ON(!done);
83         }
84 }
85 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
86
87 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
88 {
89         struct wireless_dev *wdev = dev->ieee80211_ptr;
90         struct wiphy *wiphy = wdev->wiphy;
91         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
92         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
93         const u8 *bssid = mgmt->bssid;
94         int i;
95         bool done = false;
96
97         might_sleep();
98
99         nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
100
101         if (wdev->current_bss &&
102             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
103                 done = true;
104                 cfg80211_unhold_bss(wdev->current_bss);
105                 cfg80211_put_bss(&wdev->current_bss->pub);
106                 wdev->current_bss = NULL;
107         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
108                 if (wdev->auth_bsses[i] &&
109                     memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
110                         cfg80211_unhold_bss(wdev->auth_bsses[i]);
111                         cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
112                         wdev->auth_bsses[i] = NULL;
113                         done = true;
114                         break;
115                 }
116                 if (wdev->authtry_bsses[i] &&
117                     memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
118                         cfg80211_unhold_bss(wdev->authtry_bsses[i]);
119                         cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
120                         wdev->authtry_bsses[i] = NULL;
121                         done = true;
122                         break;
123                 }
124         }
125 /*
126  * mac80211 currently triggers this warning,
127  * so disable for now (it's harmless, just
128  * means that we got a spurious event)
129
130         WARN_ON(!done);
131
132  */
133
134         if (wdev->sme_state == CFG80211_SME_CONNECTED) {
135                 u16 reason_code;
136                 bool from_ap;
137
138                 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
139
140                 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
141                 __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0,
142                                         reason_code, from_ap);
143         } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
144                 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
145                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
146                                         GFP_KERNEL);
147         }
148 }
149 EXPORT_SYMBOL(cfg80211_send_deauth);
150
151 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
152 {
153         struct wireless_dev *wdev = dev->ieee80211_ptr;
154         struct wiphy *wiphy = wdev->wiphy;
155         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
156         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
157         const u8 *bssid = mgmt->bssid;
158         int i;
159         u16 reason_code;
160         bool from_ap;
161         bool done = false;
162
163         might_sleep();
164
165         nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
166
167         if (!wdev->sme_state == CFG80211_SME_CONNECTED)
168                 return;
169
170         if (wdev->current_bss &&
171             memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
172                 for (i = 0; i < MAX_AUTH_BSSES; i++) {
173                         if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
174                                 continue;
175                         wdev->auth_bsses[i] = wdev->current_bss;
176                         wdev->current_bss = NULL;
177                         done = true;
178                         cfg80211_sme_disassoc(dev, i);
179                         break;
180                 }
181                 WARN_ON(!done);
182         } else
183                 WARN_ON(1);
184
185
186         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
187
188         from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
189         __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0,
190                                 reason_code, from_ap);
191 }
192 EXPORT_SYMBOL(cfg80211_send_disassoc);
193
194 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
195 {
196         struct wireless_dev *wdev = dev->ieee80211_ptr;
197         struct wiphy *wiphy = wdev->wiphy;
198         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
199         int i;
200         bool done = false;
201
202         might_sleep();
203
204         nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
205         if (wdev->sme_state == CFG80211_SME_CONNECTING)
206                 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
207                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
208                                         GFP_KERNEL);
209
210         for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
211                 if (wdev->authtry_bsses[i] &&
212                     memcmp(wdev->authtry_bsses[i]->pub.bssid,
213                            addr, ETH_ALEN) == 0) {
214                         cfg80211_unhold_bss(wdev->authtry_bsses[i]);
215                         cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
216                         wdev->authtry_bsses[i] = NULL;
217                         done = true;
218                         break;
219                 }
220         }
221
222         WARN_ON(!done);
223 }
224 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
225
226 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
227 {
228         struct wireless_dev *wdev = dev->ieee80211_ptr;
229         struct wiphy *wiphy = wdev->wiphy;
230         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
231         int i;
232         bool done = false;
233
234         might_sleep();
235
236         nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
237         if (wdev->sme_state == CFG80211_SME_CONNECTING)
238                 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
239                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
240                                         GFP_KERNEL);
241
242         for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
243                 if (wdev->auth_bsses[i] &&
244                     memcmp(wdev->auth_bsses[i]->pub.bssid,
245                            addr, ETH_ALEN) == 0) {
246                         cfg80211_unhold_bss(wdev->auth_bsses[i]);
247                         cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
248                         wdev->auth_bsses[i] = NULL;
249                         done = true;
250                         break;
251                 }
252         }
253
254         WARN_ON(!done);
255 }
256 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
257
258 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
259                                   enum nl80211_key_type key_type, int key_id,
260                                   const u8 *tsc, gfp_t gfp)
261 {
262         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
263         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
264 #ifdef CONFIG_WIRELESS_EXT
265         union iwreq_data wrqu;
266         char *buf = kmalloc(128, gfp);
267
268         if (buf) {
269                 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
270                         "keyid=%d %scast addr=%pM)", key_id,
271                         key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
272                         addr);
273                 memset(&wrqu, 0, sizeof(wrqu));
274                 wrqu.data.length = strlen(buf);
275                 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
276                 kfree(buf);
277         }
278 #endif
279
280         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
281 }
282 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
283
284 /* some MLME handling for userspace SME */
285 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
286                        struct net_device *dev, struct ieee80211_channel *chan,
287                        enum nl80211_auth_type auth_type, const u8 *bssid,
288                        const u8 *ssid, int ssid_len,
289                        const u8 *ie, int ie_len)
290 {
291         struct wireless_dev *wdev = dev->ieee80211_ptr;
292         struct cfg80211_auth_request req;
293         struct cfg80211_internal_bss *bss;
294         int i, err, slot = -1, nfree = 0;
295
296         if (wdev->current_bss &&
297             memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
298                 return -EALREADY;
299
300         for (i = 0; i < MAX_AUTH_BSSES; i++) {
301                 if (wdev->authtry_bsses[i] &&
302                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
303                                                 ETH_ALEN) == 0)
304                         return -EALREADY;
305                 if (wdev->auth_bsses[i] &&
306                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
307                                                 ETH_ALEN) == 0)
308                         return -EALREADY;
309         }
310
311         memset(&req, 0, sizeof(req));
312
313         req.ie = ie;
314         req.ie_len = ie_len;
315         req.auth_type = auth_type;
316         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
317                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
318         if (!req.bss)
319                 return -ENOENT;
320
321         bss = bss_from_pub(req.bss);
322
323         for (i = 0; i < MAX_AUTH_BSSES; i++) {
324                 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
325                         slot = i;
326                         nfree++;
327                 }
328         }
329
330         /* we need one free slot for disassoc and one for this auth */
331         if (nfree < 2) {
332                 err = -ENOSPC;
333                 goto out;
334         }
335
336         wdev->authtry_bsses[slot] = bss;
337         cfg80211_hold_bss(bss);
338
339         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
340         if (err) {
341                 wdev->authtry_bsses[slot] = NULL;
342                 cfg80211_unhold_bss(bss);
343         }
344
345  out:
346         if (err)
347                 cfg80211_put_bss(req.bss);
348         return err;
349 }
350
351 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
352                         struct net_device *dev, struct ieee80211_channel *chan,
353                         const u8 *bssid, const u8 *prev_bssid,
354                         const u8 *ssid, int ssid_len,
355                         const u8 *ie, int ie_len, bool use_mfp,
356                         struct cfg80211_crypto_settings *crypt)
357 {
358         struct wireless_dev *wdev = dev->ieee80211_ptr;
359         struct cfg80211_assoc_request req;
360         struct cfg80211_internal_bss *bss;
361         int i, err, slot = -1;
362
363         memset(&req, 0, sizeof(req));
364
365         if (wdev->current_bss)
366                 return -EALREADY;
367
368         req.ie = ie;
369         req.ie_len = ie_len;
370         memcpy(&req.crypto, crypt, sizeof(req.crypto));
371         req.use_mfp = use_mfp;
372         req.prev_bssid = prev_bssid;
373         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
374                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
375         if (!req.bss)
376                 return -ENOENT;
377
378         bss = bss_from_pub(req.bss);
379
380         for (i = 0; i < MAX_AUTH_BSSES; i++) {
381                 if (bss == wdev->auth_bsses[i]) {
382                         slot = i;
383                         break;
384                 }
385         }
386
387         if (slot < 0) {
388                 err = -ENOTCONN;
389                 goto out;
390         }
391
392         err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
393  out:
394         /* still a reference in wdev->auth_bsses[slot] */
395         cfg80211_put_bss(req.bss);
396         return err;
397 }
398
399 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
400                          struct net_device *dev, const u8 *bssid,
401                          const u8 *ie, int ie_len, u16 reason)
402 {
403         struct wireless_dev *wdev = dev->ieee80211_ptr;
404         struct cfg80211_deauth_request req;
405         int i;
406
407         memset(&req, 0, sizeof(req));
408         req.reason_code = reason;
409         req.ie = ie;
410         req.ie_len = ie_len;
411         if (wdev->current_bss &&
412             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
413                 req.bss = &wdev->current_bss->pub;
414         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
415                 if (wdev->auth_bsses[i] &&
416                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
417                         req.bss = &wdev->auth_bsses[i]->pub;
418                         break;
419                 }
420                 if (wdev->authtry_bsses[i] &&
421                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
422                         req.bss = &wdev->authtry_bsses[i]->pub;
423                         break;
424                 }
425         }
426
427         if (!req.bss)
428                 return -ENOTCONN;
429
430         return rdev->ops->deauth(&rdev->wiphy, dev, &req);
431 }
432
433 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
434                            struct net_device *dev, const u8 *bssid,
435                            const u8 *ie, int ie_len, u16 reason)
436 {
437         struct wireless_dev *wdev = dev->ieee80211_ptr;
438         struct cfg80211_disassoc_request req;
439
440         memset(&req, 0, sizeof(req));
441         req.reason_code = reason;
442         req.ie = ie;
443         req.ie_len = ie_len;
444         if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
445                 req.bss = &wdev->current_bss->pub;
446         else
447                 return -ENOTCONN;
448
449         return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
450 }
451
452 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
453                         struct net_device *dev)
454 {
455         struct wireless_dev *wdev = dev->ieee80211_ptr;
456         struct cfg80211_deauth_request req;
457         int i;
458
459         if (!rdev->ops->deauth)
460                 return;
461
462         memset(&req, 0, sizeof(req));
463         req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
464         req.ie = NULL;
465         req.ie_len = 0;
466
467         if (wdev->current_bss) {
468                 req.bss = &wdev->current_bss->pub;
469                 rdev->ops->deauth(&rdev->wiphy, dev, &req);
470                 if (wdev->current_bss) {
471                         cfg80211_unhold_bss(wdev->current_bss);
472                         cfg80211_put_bss(&wdev->current_bss->pub);
473                         wdev->current_bss = NULL;
474                 }
475         }
476
477         for (i = 0; i < MAX_AUTH_BSSES; i++) {
478                 if (wdev->auth_bsses[i]) {
479                         req.bss = &wdev->auth_bsses[i]->pub;
480                         rdev->ops->deauth(&rdev->wiphy, dev, &req);
481                         if (wdev->auth_bsses[i]) {
482                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
483                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
484                                 wdev->auth_bsses[i] = NULL;
485                         }
486                 }
487                 if (wdev->authtry_bsses[i]) {
488                         req.bss = &wdev->authtry_bsses[i]->pub;
489                         rdev->ops->deauth(&rdev->wiphy, dev, &req);
490                         if (wdev->authtry_bsses[i]) {
491                                 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
492                                 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
493                                 wdev->authtry_bsses[i] = NULL;
494                         }
495                 }
496         }
497 }