020f33b38467ac8ee570a61bd76b634c3fda17f9
[safe/jmp/linux-2.6] / 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, gfp_t gfp)
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         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);
43
44         nl80211_send_rx_auth(rdev, dev, buf, len, gfp);
45         cfg80211_sme_rx_auth(dev, buf, len);
46 }
47 EXPORT_SYMBOL(cfg80211_send_rx_auth);
48
49 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
50 {
51         u16 status_code;
52         struct wireless_dev *wdev = dev->ieee80211_ptr;
53         struct wiphy *wiphy = wdev->wiphy;
54         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
55         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
56         u8 *ie = mgmt->u.assoc_resp.variable;
57         int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
58         bool done;
59
60         status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
61
62         nl80211_send_rx_assoc(rdev, dev, buf, len, gfp);
63
64         cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
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         }
80 }
81 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
82
83 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
84 {
85         struct wireless_dev *wdev = dev->ieee80211_ptr;
86         struct wiphy *wiphy = wdev->wiphy;
87         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
88         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
89         const u8 *bssid = mgmt->bssid;
90         int i;
91         bool done = false;
92
93         nl80211_send_deauth(rdev, dev, buf, len, gfp);
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
128         if (wdev->sme_state == CFG80211_SME_CONNECTED) {
129                 u16 reason_code;
130                 bool from_ap;
131
132                 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
133
134                 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
135                 __cfg80211_disconnected(dev, gfp, NULL, 0,
136                                         reason_code, from_ap);
137         } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
138                 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
139                                         WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
140         }
141 }
142 EXPORT_SYMBOL(cfg80211_send_deauth);
143
144 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
145 {
146         struct wireless_dev *wdev = dev->ieee80211_ptr;
147         struct wiphy *wiphy = wdev->wiphy;
148         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
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;
155
156         nl80211_send_disassoc(rdev, dev, buf, len, gfp);
157
158         if (!wdev->sme_state == CFG80211_SME_CONNECTED)
159                 return;
160
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);
175
176
177         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
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);
182 }
183 EXPORT_SYMBOL(cfg80211_send_disassoc);
184
185 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
186 {
187         struct wireless_dev *wdev = dev->ieee80211_ptr;
188         struct wiphy *wiphy = wdev->wiphy;
189         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
190         int i;
191         bool done = false;
192
193         nl80211_send_auth_timeout(rdev, dev, addr, gfp);
194         if (wdev->sme_state == CFG80211_SME_CONNECTING)
195                 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
196                                         WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
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);
211 }
212 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
213
214 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
215 {
216         struct wireless_dev *wdev = dev->ieee80211_ptr;
217         struct wiphy *wiphy = wdev->wiphy;
218         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
219         int i;
220         bool done = false;
221
222         nl80211_send_assoc_timeout(rdev, dev, addr, gfp);
223         if (wdev->sme_state == CFG80211_SME_CONNECTING)
224                 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
225                                         WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
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);
240 }
241 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
242
243 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
244                                   enum nl80211_key_type key_type, int key_id,
245                                   const u8 *tsc, gfp_t gfp)
246 {
247         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
248         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
249 #ifdef CONFIG_WIRELESS_EXT
250         union iwreq_data wrqu;
251         char *buf = kmalloc(128, gfp);
252
253         if (buf) {
254                 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
255                         "keyid=%d %scast addr=%pM)", key_id,
256                         key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
257                         addr);
258                 memset(&wrqu, 0, sizeof(wrqu));
259                 wrqu.data.length = strlen(buf);
260                 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
261                 kfree(buf);
262         }
263 #endif
264
265         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
266 }
267 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
268
269 /* some MLME handling for userspace SME */
270 int 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         if (wdev->current_bss &&
282             memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
283                 return -EALREADY;
284
285         for (i = 0; i < MAX_AUTH_BSSES; i++) {
286                 if (wdev->authtry_bsses[i] &&
287                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
288                                                 ETH_ALEN) == 0)
289                         return -EALREADY;
290                 if (wdev->auth_bsses[i] &&
291                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
292                                                 ETH_ALEN) == 0)
293                         return -EALREADY;
294         }
295
296         memset(&req, 0, sizeof(req));
297
298         req.ie = ie;
299         req.ie_len = ie_len;
300         req.auth_type = auth_type;
301         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
302                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
303         if (!req.bss)
304                 return -ENOENT;
305
306         bss = bss_from_pub(req.bss);
307
308         for (i = 0; i < MAX_AUTH_BSSES; i++) {
309                 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
310                         slot = i;
311                         nfree++;
312                 }
313         }
314
315         /* we need one free slot for disassoc and one for this auth */
316         if (nfree < 2) {
317                 err = -ENOSPC;
318                 goto out;
319         }
320
321         wdev->authtry_bsses[slot] = bss;
322         cfg80211_hold_bss(bss);
323
324         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
325         if (err) {
326                 wdev->authtry_bsses[slot] = NULL;
327                 cfg80211_unhold_bss(bss);
328         }
329
330  out:
331         if (err)
332                 cfg80211_put_bss(req.bss);
333         return err;
334 }
335
336 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
337                         struct net_device *dev, struct ieee80211_channel *chan,
338                         const u8 *bssid, const u8 *ssid, int ssid_len,
339                         const u8 *ie, int ie_len, bool use_mfp,
340                         struct cfg80211_crypto_settings *crypt)
341 {
342         struct wireless_dev *wdev = dev->ieee80211_ptr;
343         struct cfg80211_assoc_request req;
344         struct cfg80211_internal_bss *bss;
345         int i, err, slot = -1;
346
347         memset(&req, 0, sizeof(req));
348
349         if (wdev->current_bss)
350                 return -EALREADY;
351
352         req.ie = ie;
353         req.ie_len = ie_len;
354         memcpy(&req.crypto, crypt, sizeof(req.crypto));
355         req.use_mfp = use_mfp;
356         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
357                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
358         if (!req.bss)
359                 return -ENOENT;
360
361         bss = bss_from_pub(req.bss);
362
363         for (i = 0; i < MAX_AUTH_BSSES; i++) {
364                 if (bss == wdev->auth_bsses[i]) {
365                         slot = i;
366                         break;
367                 }
368         }
369
370         if (slot < 0) {
371                 err = -ENOTCONN;
372                 goto out;
373         }
374
375         err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
376  out:
377         /* still a reference in wdev->auth_bsses[slot] */
378         cfg80211_put_bss(req.bss);
379         return err;
380 }
381
382 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
383                          struct net_device *dev, const u8 *bssid,
384                          const u8 *ie, int ie_len, u16 reason)
385 {
386         struct wireless_dev *wdev = dev->ieee80211_ptr;
387         struct cfg80211_deauth_request req;
388         int i;
389
390         memset(&req, 0, sizeof(req));
391         req.reason_code = reason;
392         req.ie = ie;
393         req.ie_len = ie_len;
394         if (wdev->current_bss &&
395             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
396                 req.bss = &wdev->current_bss->pub;
397         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
398                 if (wdev->auth_bsses[i] &&
399                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
400                         req.bss = &wdev->auth_bsses[i]->pub;
401                         break;
402                 }
403                 if (wdev->authtry_bsses[i] &&
404                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
405                         req.bss = &wdev->authtry_bsses[i]->pub;
406                         break;
407                 }
408         }
409
410         if (!req.bss)
411                 return -ENOTCONN;
412
413         return rdev->ops->deauth(&rdev->wiphy, dev, &req);
414 }
415
416 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
417                            struct net_device *dev, const u8 *bssid,
418                            const u8 *ie, int ie_len, u16 reason)
419 {
420         struct wireless_dev *wdev = dev->ieee80211_ptr;
421         struct cfg80211_disassoc_request req;
422
423         memset(&req, 0, sizeof(req));
424         req.reason_code = reason;
425         req.ie = ie;
426         req.ie_len = ie_len;
427         if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
428                 req.bss = &wdev->current_bss->pub;
429         else
430                 return -ENOTCONN;
431
432         return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
433 }
434
435 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
436                         struct net_device *dev)
437 {
438         struct wireless_dev *wdev = dev->ieee80211_ptr;
439         struct cfg80211_deauth_request req;
440         int i;
441
442         if (!rdev->ops->deauth)
443                 return;
444
445         memset(&req, 0, sizeof(req));
446         req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
447         req.ie = NULL;
448         req.ie_len = 0;
449
450         if (wdev->current_bss) {
451                 req.bss = &wdev->current_bss->pub;
452                 rdev->ops->deauth(&rdev->wiphy, dev, &req);
453                 if (wdev->current_bss) {
454                         cfg80211_unhold_bss(wdev->current_bss);
455                         cfg80211_put_bss(&wdev->current_bss->pub);
456                         wdev->current_bss = NULL;
457                 }
458         }
459
460         for (i = 0; i < MAX_AUTH_BSSES; i++) {
461                 if (wdev->auth_bsses[i]) {
462                         req.bss = &wdev->auth_bsses[i]->pub;
463                         rdev->ops->deauth(&rdev->wiphy, dev, &req);
464                         if (wdev->auth_bsses[i]) {
465                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
466                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
467                                 wdev->auth_bsses[i] = NULL;
468                         }
469                 }
470                 if (wdev->authtry_bsses[i]) {
471                         req.bss = &wdev->authtry_bsses[i]->pub;
472                         rdev->ops->deauth(&rdev->wiphy, dev, &req);
473                         if (wdev->authtry_bsses[i]) {
474                                 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
475                                 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
476                                 wdev->authtry_bsses[i] = NULL;
477                         }
478                 }
479         }
480 }