blob: b6b3112e57ef1d479eb2c2bfc56697aaa914644b [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
24
25module_param(ath6kl_p2p, uint, 0644);
26
Kalle Valobdcd8172011-07-18 00:22:30 +030027#define RATETAB_ENT(_rate, _rateid, _flags) { \
28 .bitrate = (_rate), \
29 .flags = (_flags), \
30 .hw_value = (_rateid), \
31}
32
33#define CHAN2G(_channel, _freq, _flags) { \
34 .band = IEEE80211_BAND_2GHZ, \
35 .hw_value = (_channel), \
36 .center_freq = (_freq), \
37 .flags = (_flags), \
38 .max_antenna_gain = 0, \
39 .max_power = 30, \
40}
41
42#define CHAN5G(_channel, _flags) { \
43 .band = IEEE80211_BAND_5GHZ, \
44 .hw_value = (_channel), \
45 .center_freq = 5000 + (5 * (_channel)), \
46 .flags = (_flags), \
47 .max_antenna_gain = 0, \
48 .max_power = 30, \
49}
50
51static struct ieee80211_rate ath6kl_rates[] = {
52 RATETAB_ENT(10, 0x1, 0),
53 RATETAB_ENT(20, 0x2, 0),
54 RATETAB_ENT(55, 0x4, 0),
55 RATETAB_ENT(110, 0x8, 0),
56 RATETAB_ENT(60, 0x10, 0),
57 RATETAB_ENT(90, 0x20, 0),
58 RATETAB_ENT(120, 0x40, 0),
59 RATETAB_ENT(180, 0x80, 0),
60 RATETAB_ENT(240, 0x100, 0),
61 RATETAB_ENT(360, 0x200, 0),
62 RATETAB_ENT(480, 0x400, 0),
63 RATETAB_ENT(540, 0x800, 0),
64};
65
66#define ath6kl_a_rates (ath6kl_rates + 4)
67#define ath6kl_a_rates_size 8
68#define ath6kl_g_rates (ath6kl_rates + 0)
69#define ath6kl_g_rates_size 12
70
71static struct ieee80211_channel ath6kl_2ghz_channels[] = {
72 CHAN2G(1, 2412, 0),
73 CHAN2G(2, 2417, 0),
74 CHAN2G(3, 2422, 0),
75 CHAN2G(4, 2427, 0),
76 CHAN2G(5, 2432, 0),
77 CHAN2G(6, 2437, 0),
78 CHAN2G(7, 2442, 0),
79 CHAN2G(8, 2447, 0),
80 CHAN2G(9, 2452, 0),
81 CHAN2G(10, 2457, 0),
82 CHAN2G(11, 2462, 0),
83 CHAN2G(12, 2467, 0),
84 CHAN2G(13, 2472, 0),
85 CHAN2G(14, 2484, 0),
86};
87
88static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
89 CHAN5G(34, 0), CHAN5G(36, 0),
90 CHAN5G(38, 0), CHAN5G(40, 0),
91 CHAN5G(42, 0), CHAN5G(44, 0),
92 CHAN5G(46, 0), CHAN5G(48, 0),
93 CHAN5G(52, 0), CHAN5G(56, 0),
94 CHAN5G(60, 0), CHAN5G(64, 0),
95 CHAN5G(100, 0), CHAN5G(104, 0),
96 CHAN5G(108, 0), CHAN5G(112, 0),
97 CHAN5G(116, 0), CHAN5G(120, 0),
98 CHAN5G(124, 0), CHAN5G(128, 0),
99 CHAN5G(132, 0), CHAN5G(136, 0),
100 CHAN5G(140, 0), CHAN5G(149, 0),
101 CHAN5G(153, 0), CHAN5G(157, 0),
102 CHAN5G(161, 0), CHAN5G(165, 0),
103 CHAN5G(184, 0), CHAN5G(188, 0),
104 CHAN5G(192, 0), CHAN5G(196, 0),
105 CHAN5G(200, 0), CHAN5G(204, 0),
106 CHAN5G(208, 0), CHAN5G(212, 0),
107 CHAN5G(216, 0),
108};
109
110static struct ieee80211_supported_band ath6kl_band_2ghz = {
111 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
112 .channels = ath6kl_2ghz_channels,
113 .n_bitrates = ath6kl_g_rates_size,
114 .bitrates = ath6kl_g_rates,
115};
116
117static struct ieee80211_supported_band ath6kl_band_5ghz = {
118 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
119 .channels = ath6kl_5ghz_a_channels,
120 .n_bitrates = ath6kl_a_rates_size,
121 .bitrates = ath6kl_a_rates,
122};
123
Jouni Malinen837cb972011-10-11 17:31:57 +0300124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
125
Kalle Valobdcd8172011-07-18 00:22:30 +0300126static int ath6kl_set_wpa_version(struct ath6kl *ar,
127 enum nl80211_wpa_versions wpa_version)
128{
129 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
130
131 if (!wpa_version) {
132 ar->auth_mode = NONE_AUTH;
133 } else if (wpa_version & NL80211_WPA_VERSION_2) {
134 ar->auth_mode = WPA2_AUTH;
135 } else if (wpa_version & NL80211_WPA_VERSION_1) {
136 ar->auth_mode = WPA_AUTH;
137 } else {
138 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
139 return -ENOTSUPP;
140 }
141
142 return 0;
143}
144
145static int ath6kl_set_auth_type(struct ath6kl *ar,
146 enum nl80211_auth_type auth_type)
147{
148
149 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
150
151 switch (auth_type) {
152 case NL80211_AUTHTYPE_OPEN_SYSTEM:
153 ar->dot11_auth_mode = OPEN_AUTH;
154 break;
155 case NL80211_AUTHTYPE_SHARED_KEY:
156 ar->dot11_auth_mode = SHARED_AUTH;
157 break;
158 case NL80211_AUTHTYPE_NETWORK_EAP:
159 ar->dot11_auth_mode = LEAP_AUTH;
160 break;
161
162 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530163 ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300164 break;
165
166 default:
167 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
168 return -ENOTSUPP;
169 }
170
171 return 0;
172}
173
174static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
175{
176 u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
Edward Lu38acde32011-08-30 21:58:06 +0300177 u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
178 &ar->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300179
180 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
181 __func__, cipher, ucast);
182
183 switch (cipher) {
184 case 0:
185 /* our own hack to use value 0 as no crypto used */
186 *ar_cipher = NONE_CRYPT;
187 *ar_cipher_len = 0;
188 break;
189 case WLAN_CIPHER_SUITE_WEP40:
190 *ar_cipher = WEP_CRYPT;
191 *ar_cipher_len = 5;
192 break;
193 case WLAN_CIPHER_SUITE_WEP104:
194 *ar_cipher = WEP_CRYPT;
195 *ar_cipher_len = 13;
196 break;
197 case WLAN_CIPHER_SUITE_TKIP:
198 *ar_cipher = TKIP_CRYPT;
199 *ar_cipher_len = 0;
200 break;
201 case WLAN_CIPHER_SUITE_CCMP:
202 *ar_cipher = AES_CRYPT;
203 *ar_cipher_len = 0;
204 break;
205 default:
206 ath6kl_err("cipher 0x%x not supported\n", cipher);
207 return -ENOTSUPP;
208 }
209
210 return 0;
211}
212
213static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
214{
215 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
216
217 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
218 if (ar->auth_mode == WPA_AUTH)
219 ar->auth_mode = WPA_PSK_AUTH;
220 else if (ar->auth_mode == WPA2_AUTH)
221 ar->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300222 } else if (key_mgmt == 0x00409600) {
223 if (ar->auth_mode == WPA_AUTH)
224 ar->auth_mode = WPA_AUTH_CCKM;
225 else if (ar->auth_mode == WPA2_AUTH)
226 ar->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300227 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
228 ar->auth_mode = NONE_AUTH;
229 }
230}
231
232static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
233{
234 if (!test_bit(WMI_READY, &ar->flag)) {
235 ath6kl_err("wmi is not ready\n");
236 return false;
237 }
238
Raja Mani575b5f32011-07-19 19:27:33 +0530239 if (!test_bit(WLAN_ENABLED, &ar->flag)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300240 ath6kl_err("wlan disabled\n");
241 return false;
242 }
243
244 return true;
245}
246
Kevin Fang6981ffd2011-10-07 08:51:19 +0800247static bool ath6kl_is_wpa_ie(const u8 *pos)
248{
249 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
250 pos[2] == 0x00 && pos[3] == 0x50 &&
251 pos[4] == 0xf2 && pos[5] == 0x01;
252}
253
254static bool ath6kl_is_rsn_ie(const u8 *pos)
255{
256 return pos[0] == WLAN_EID_RSN;
257}
258
259static int ath6kl_set_assoc_req_ies(struct ath6kl *ar, const u8 *ies,
260 size_t ies_len)
261{
262 const u8 *pos;
263 u8 *buf = NULL;
264 size_t len = 0;
265 int ret;
266
267 /*
268 * Filter out RSN/WPA IE(s)
269 */
270
271 if (ies && ies_len) {
272 buf = kmalloc(ies_len, GFP_KERNEL);
273 if (buf == NULL)
274 return -ENOMEM;
275 pos = ies;
276
277 while (pos + 1 < ies + ies_len) {
278 if (pos + 2 + pos[1] > ies + ies_len)
279 break;
280 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
281 memcpy(buf + len, pos, 2 + pos[1]);
282 len += 2 + pos[1];
283 }
284 pos += 2 + pos[1];
285 }
286 }
287
288 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_REQ,
289 buf, len);
290 kfree(buf);
291 return ret;
292}
293
Kalle Valobdcd8172011-07-18 00:22:30 +0300294static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
295 struct cfg80211_connect_params *sme)
296{
297 struct ath6kl *ar = ath6kl_priv(dev);
298 int status;
299
300 ar->sme_state = SME_CONNECTING;
301
302 if (!ath6kl_cfg80211_ready(ar))
303 return -EIO;
304
305 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
306 ath6kl_err("destroy in progress\n");
307 return -EBUSY;
308 }
309
310 if (test_bit(SKIP_SCAN, &ar->flag) &&
311 ((sme->channel && sme->channel->center_freq == 0) ||
312 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
313 ath6kl_err("SkipScan: channel or bssid invalid\n");
314 return -EINVAL;
315 }
316
317 if (down_interruptible(&ar->sem)) {
318 ath6kl_err("busy, couldn't get access\n");
319 return -ERESTARTSYS;
320 }
321
322 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
323 ath6kl_err("busy, destroy in progress\n");
324 up(&ar->sem);
325 return -EBUSY;
326 }
327
328 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
329 /*
330 * sleep until the command queue drains
331 */
332 wait_event_interruptible_timeout(ar->event_wq,
333 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
334 WMI_TIMEOUT);
335 if (signal_pending(current)) {
336 ath6kl_err("cmd queue drain timeout\n");
337 up(&ar->sem);
338 return -EINTR;
339 }
340 }
341
Kevin Fang6981ffd2011-10-07 08:51:19 +0800342 if (sme->ie && (sme->ie_len > 0)) {
343 status = ath6kl_set_assoc_req_ies(ar, sme->ie, sme->ie_len);
344 if (status)
345 return status;
346 }
347
Kalle Valobdcd8172011-07-18 00:22:30 +0300348 if (test_bit(CONNECTED, &ar->flag) &&
349 ar->ssid_len == sme->ssid_len &&
350 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
351 ar->reconnect_flag = true;
352 status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
353 ar->ch_hint);
354
355 up(&ar->sem);
356 if (status) {
357 ath6kl_err("wmi_reconnect_cmd failed\n");
358 return -EIO;
359 }
360 return 0;
361 } else if (ar->ssid_len == sme->ssid_len &&
362 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
363 ath6kl_disconnect(ar);
364 }
365
366 memset(ar->ssid, 0, sizeof(ar->ssid));
367 ar->ssid_len = sme->ssid_len;
368 memcpy(ar->ssid, sme->ssid, sme->ssid_len);
369
370 if (sme->channel)
371 ar->ch_hint = sme->channel->center_freq;
372
373 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
374 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
375 memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
376
377 ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
378
379 status = ath6kl_set_auth_type(ar, sme->auth_type);
380 if (status) {
381 up(&ar->sem);
382 return status;
383 }
384
385 if (sme->crypto.n_ciphers_pairwise)
386 ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
387 else
388 ath6kl_set_cipher(ar, 0, true);
389
390 ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
391
392 if (sme->crypto.n_akm_suites)
393 ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
394
395 if ((sme->key_len) &&
396 (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
397 struct ath6kl_key *key = NULL;
398
399 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
400 sme->key_idx > WMI_MAX_KEY_INDEX) {
401 ath6kl_err("key index %d out of bounds\n",
402 sme->key_idx);
403 up(&ar->sem);
404 return -ENOENT;
405 }
406
407 key = &ar->keys[sme->key_idx];
408 key->key_len = sme->key_len;
409 memcpy(key->key, sme->key, key->key_len);
410 key->cipher = ar->prwise_crypto;
411 ar->def_txkey_index = sme->key_idx;
412
413 ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
414 ar->prwise_crypto,
415 GROUP_USAGE | TX_USAGE,
416 key->key_len,
417 NULL,
418 key->key, KEY_OP_INIT_VAL, NULL,
419 NO_SYNC_WMIFLAG);
420 }
421
422 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300423 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300424 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
425 ath6kl_err("couldn't set bss filtering\n");
426 up(&ar->sem);
427 return -EIO;
428 }
429 }
430
431 ar->nw_type = ar->next_mode;
432
433 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
434 "%s: connect called with authmode %d dot11 auth %d"
435 " PW crypto %d PW crypto len %d GRP crypto %d"
436 " GRP crypto len %d channel hint %u\n",
437 __func__,
438 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
439 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +0300440 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300441
442 ar->reconnect_flag = 0;
443 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
444 ar->dot11_auth_mode, ar->auth_mode,
445 ar->prwise_crypto,
446 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +0300447 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +0300448 ar->ssid_len, ar->ssid,
449 ar->req_bssid, ar->ch_hint,
450 ar->connect_ctrl_flags);
451
452 up(&ar->sem);
453
454 if (status == -EINVAL) {
455 memset(ar->ssid, 0, sizeof(ar->ssid));
456 ar->ssid_len = 0;
457 ath6kl_err("invalid request\n");
458 return -ENOENT;
459 } else if (status) {
460 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
461 return -EIO;
462 }
463
464 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
465 ((ar->auth_mode == WPA_PSK_AUTH)
466 || (ar->auth_mode == WPA2_PSK_AUTH))) {
467 mod_timer(&ar->disconnect_timer,
468 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
469 }
470
471 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
472 set_bit(CONNECT_PEND, &ar->flag);
473
474 return 0;
475}
476
Jouni Malinen01cac472011-09-19 19:14:59 +0300477static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
478 struct ieee80211_channel *chan,
479 const u8 *beacon_ie, size_t beacon_ie_len)
480{
481 struct cfg80211_bss *bss;
482 u8 *ie;
483
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530484 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300485 ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
486 WLAN_CAPABILITY_ESS);
487 if (bss == NULL) {
488 /*
489 * Since cfg80211 may not yet know about the BSS,
490 * generate a partial entry until the first BSS info
491 * event becomes available.
492 *
493 * Prepend SSID element since it is not included in the Beacon
494 * IEs from the target.
495 */
496 ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
497 if (ie == NULL)
498 return -ENOMEM;
499 ie[0] = WLAN_EID_SSID;
500 ie[1] = ar->ssid_len;
501 memcpy(ie + 2, ar->ssid, ar->ssid_len);
502 memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530503 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300504 bssid, 0, WLAN_CAPABILITY_ESS, 100,
505 ie, 2 + ar->ssid_len + beacon_ie_len,
506 0, GFP_KERNEL);
507 if (bss)
508 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
509 "%pM prior to indicating connect/roamed "
510 "event\n", bssid);
511 kfree(ie);
512 } else
513 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
514 "entry\n");
515
516 if (bss == NULL)
517 return -ENOMEM;
518
519 cfg80211_put_bss(bss);
520
521 return 0;
522}
523
Kalle Valobdcd8172011-07-18 00:22:30 +0300524void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
525 u8 *bssid, u16 listen_intvl,
526 u16 beacon_intvl,
527 enum network_type nw_type,
528 u8 beacon_ie_len, u8 assoc_req_len,
529 u8 assoc_resp_len, u8 *assoc_info)
530{
Jouni Malinen01cac472011-09-19 19:14:59 +0300531 struct ieee80211_channel *chan;
Kalle Valobdcd8172011-07-18 00:22:30 +0300532
533 /* capinfo + listen interval */
534 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
535
536 /* capinfo + status code + associd */
537 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
538
539 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
540 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
541 assoc_resp_ie_offset;
542
543 assoc_req_len -= assoc_req_ie_offset;
544 assoc_resp_len -= assoc_resp_ie_offset;
545
Jouni Malinen32c10872011-09-19 19:15:07 +0300546 /*
547 * Store Beacon interval here; DTIM period will be available only once
548 * a Beacon frame from the AP is seen.
549 */
550 ar->assoc_bss_beacon_int = beacon_intvl;
551 clear_bit(DTIM_PERIOD_AVAIL, &ar->flag);
552
Kalle Valobdcd8172011-07-18 00:22:30 +0300553 if (nw_type & ADHOC_NETWORK) {
554 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
555 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
556 "%s: ath6k not in ibss mode\n", __func__);
557 return;
558 }
559 }
560
561 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300562 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
563 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300564 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
565 "%s: ath6k not in station mode\n", __func__);
566 return;
567 }
568 }
569
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530570 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300571
Kalle Valobdcd8172011-07-18 00:22:30 +0300572
573 if (nw_type & ADHOC_NETWORK) {
574 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
575 return;
576 }
577
Jouni Malinen01cac472011-09-19 19:14:59 +0300578 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
579 beacon_ie_len) < 0) {
580 ath6kl_err("could not add cfg80211 bss entry for "
581 "connect/roamed notification\n");
582 return;
583 }
584
Raja Mani9aa60352011-08-04 19:26:29 +0530585 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300586 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530587 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300588 cfg80211_connect_result(ar->net_dev, bssid,
589 assoc_req_ie, assoc_req_len,
590 assoc_resp_ie, assoc_resp_len,
591 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530592 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300593 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300594 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300595 assoc_req_ie, assoc_req_len,
596 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
597 }
598}
599
600static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
601 struct net_device *dev, u16 reason_code)
602{
603 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
604
605 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
606 reason_code);
607
608 if (!ath6kl_cfg80211_ready(ar))
609 return -EIO;
610
611 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
612 ath6kl_err("busy, destroy in progress\n");
613 return -EBUSY;
614 }
615
616 if (down_interruptible(&ar->sem)) {
617 ath6kl_err("busy, couldn't get access\n");
618 return -ERESTARTSYS;
619 }
620
621 ar->reconnect_flag = 0;
622 ath6kl_disconnect(ar);
623 memset(ar->ssid, 0, sizeof(ar->ssid));
624 ar->ssid_len = 0;
625
626 if (!test_bit(SKIP_SCAN, &ar->flag))
627 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
628
629 up(&ar->sem);
630
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530631 ar->sme_state = SME_DISCONNECTED;
632
Kalle Valobdcd8172011-07-18 00:22:30 +0300633 return 0;
634}
635
636void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
637 u8 *bssid, u8 assoc_resp_len,
638 u8 *assoc_info, u16 proto_reason)
639{
Kalle Valobdcd8172011-07-18 00:22:30 +0300640 if (ar->scan_req) {
641 cfg80211_scan_done(ar->scan_req, true);
642 ar->scan_req = NULL;
643 }
644
645 if (ar->nw_type & ADHOC_NETWORK) {
646 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
647 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
648 "%s: ath6k not in ibss mode\n", __func__);
649 return;
650 }
651 memset(bssid, 0, ETH_ALEN);
652 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
653 return;
654 }
655
656 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300657 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
658 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300659 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
660 "%s: ath6k not in station mode\n", __func__);
661 return;
662 }
663 }
664
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530665 /*
666 * Send a disconnect command to target when a disconnect event is
667 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
668 * request from host) to make the firmware stop trying to connect even
669 * after giving disconnect event. There will be one more disconnect
670 * event for this disconnect command with reason code DISCONNECT_CMD
671 * which will be notified to cfg80211.
672 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300673
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530674 if (reason != DISCONNECT_CMD) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300675 ath6kl_wmi_disconnect_cmd(ar->wmi);
676 return;
677 }
678
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530679 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300680
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530681 if (ar->sme_state == SME_CONNECTING) {
682 cfg80211_connect_result(ar->net_dev,
683 bssid, NULL, 0,
684 NULL, 0,
685 WLAN_STATUS_UNSPECIFIED_FAILURE,
686 GFP_KERNEL);
687 } else if (ar->sme_state == SME_CONNECTED) {
688 cfg80211_disconnected(ar->net_dev, reason,
689 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300690 }
691
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530692 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300693}
694
Kalle Valobdcd8172011-07-18 00:22:30 +0300695static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
696 struct cfg80211_scan_request *request)
697{
698 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300699 s8 n_channels = 0;
700 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300701 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530702 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300703
704 if (!ath6kl_cfg80211_ready(ar))
705 return -EIO;
706
707 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300708 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300709 ret = ath6kl_wmi_bssfilter_cmd(
710 ar->wmi,
711 (test_bit(CONNECTED, &ar->flag) ?
712 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
713 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300714 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300715 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300716 }
717 }
718
719 if (request->n_ssids && request->ssids[0].ssid_len) {
720 u8 i;
721
722 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
723 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
724
725 for (i = 0; i < request->n_ssids; i++)
726 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
727 SPECIFIC_SSID_FLAG,
728 request->ssids[i].ssid_len,
729 request->ssids[i].ssid);
730 }
731
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300732 if (request->ie) {
733 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
734 request->ie, request->ie_len);
735 if (ret) {
736 ath6kl_err("failed to set Probe Request appie for "
737 "scan");
738 return ret;
739 }
740 }
741
Jouni Malinen11869be2011-09-02 20:07:06 +0300742 /*
743 * Scan only the requested channels if the request specifies a set of
744 * channels. If the list is longer than the target supports, do not
745 * configure the list and instead, scan all available channels.
746 */
747 if (request->n_channels > 0 &&
748 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300749 u8 i;
750
Jouni Malinen11869be2011-09-02 20:07:06 +0300751 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300752
753 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
754 if (channels == NULL) {
755 ath6kl_warn("failed to set scan channels, "
756 "scan all channels");
757 n_channels = 0;
758 }
759
760 for (i = 0; i < n_channels; i++)
761 channels[i] = request->channels[i]->center_freq;
762 }
763
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530764 if (test_bit(CONNECTED, &ar->flag))
765 force_fg_scan = 1;
766
767 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, force_fg_scan,
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300768 false, 0, 0, n_channels, channels);
769 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300770 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300771 else
772 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300773
Edward Lu1276c9e2011-08-30 21:58:00 +0300774 kfree(channels);
775
Kalle Valobdcd8172011-07-18 00:22:30 +0300776 return ret;
777}
778
779void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
780{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300781 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300782
783 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
784
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300785 if (!ar->scan_req)
786 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300787
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300788 if ((status == -ECANCELED) || (status == -EBUSY)) {
789 cfg80211_scan_done(ar->scan_req, true);
790 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300791 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300792
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300793 cfg80211_scan_done(ar->scan_req, false);
794
795 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
796 for (i = 0; i < ar->scan_req->n_ssids; i++) {
797 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
798 DISABLE_SSID_FLAG,
799 0, NULL);
800 }
801 }
802
803out:
804 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300805}
806
807static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
808 u8 key_index, bool pairwise,
809 const u8 *mac_addr,
810 struct key_params *params)
811{
812 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
813 struct ath6kl_key *key = NULL;
814 u8 key_usage;
815 u8 key_type;
816 int status = 0;
817
818 if (!ath6kl_cfg80211_ready(ar))
819 return -EIO;
820
Jouni Malinen837cb972011-10-11 17:31:57 +0300821 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
822 if (params->key_len != WMI_KRK_LEN)
823 return -EINVAL;
824 return ath6kl_wmi_add_krk_cmd(ar->wmi, params->key);
825 }
826
Kalle Valobdcd8172011-07-18 00:22:30 +0300827 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
828 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
829 "%s: key index %d out of bounds\n", __func__,
830 key_index);
831 return -ENOENT;
832 }
833
834 key = &ar->keys[key_index];
835 memset(key, 0, sizeof(struct ath6kl_key));
836
837 if (pairwise)
838 key_usage = PAIRWISE_USAGE;
839 else
840 key_usage = GROUP_USAGE;
841
842 if (params) {
843 if (params->key_len > WLAN_MAX_KEY_LEN ||
844 params->seq_len > sizeof(key->seq))
845 return -EINVAL;
846
847 key->key_len = params->key_len;
848 memcpy(key->key, params->key, key->key_len);
849 key->seq_len = params->seq_len;
850 memcpy(key->seq, params->seq, key->seq_len);
851 key->cipher = params->cipher;
852 }
853
854 switch (key->cipher) {
855 case WLAN_CIPHER_SUITE_WEP40:
856 case WLAN_CIPHER_SUITE_WEP104:
857 key_type = WEP_CRYPT;
858 break;
859
860 case WLAN_CIPHER_SUITE_TKIP:
861 key_type = TKIP_CRYPT;
862 break;
863
864 case WLAN_CIPHER_SUITE_CCMP:
865 key_type = AES_CRYPT;
866 break;
867
868 default:
869 return -ENOTSUPP;
870 }
871
872 if (((ar->auth_mode == WPA_PSK_AUTH)
873 || (ar->auth_mode == WPA2_PSK_AUTH))
874 && (key_usage & GROUP_USAGE))
875 del_timer(&ar->disconnect_timer);
876
877 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
878 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
879 __func__, key_index, key->key_len, key_type,
880 key_usage, key->seq_len);
881
882 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300883
884 if (ar->nw_type == AP_NETWORK && !pairwise &&
885 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
886 ar->ap_mode_bkey.valid = true;
887 ar->ap_mode_bkey.key_index = key_index;
888 ar->ap_mode_bkey.key_type = key_type;
889 ar->ap_mode_bkey.key_len = key->key_len;
890 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
891 if (!test_bit(CONNECTED, &ar->flag)) {
892 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
893 "key configuration until AP mode has been "
894 "started\n");
895 /*
896 * The key will be set in ath6kl_connect_ap_mode() once
897 * the connected event is received from the target.
898 */
899 return 0;
900 }
901 }
902
Jouni Malinen151411e2011-09-15 15:10:16 +0300903 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
904 !test_bit(CONNECTED, &ar->flag)) {
905 /*
906 * Store the key locally so that it can be re-configured after
907 * the AP mode has properly started
908 * (ath6kl_install_statioc_wep_keys).
909 */
910 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
911 "until AP mode has been started\n");
912 ar->wep_key_list[key_index].key_len = key->key_len;
913 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
914 return 0;
915 }
916
Kalle Valobdcd8172011-07-18 00:22:30 +0300917 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
918 key_type, key_usage, key->key_len,
919 key->seq, key->key, KEY_OP_INIT_VAL,
920 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
921
922 if (status)
923 return -EIO;
924
925 return 0;
926}
927
928static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
929 u8 key_index, bool pairwise,
930 const u8 *mac_addr)
931{
932 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
933
934 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
935
936 if (!ath6kl_cfg80211_ready(ar))
937 return -EIO;
938
939 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
940 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
941 "%s: key index %d out of bounds\n", __func__,
942 key_index);
943 return -ENOENT;
944 }
945
946 if (!ar->keys[key_index].key_len) {
947 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
948 "%s: index %d is empty\n", __func__, key_index);
949 return 0;
950 }
951
952 ar->keys[key_index].key_len = 0;
953
954 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
955}
956
957static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
958 u8 key_index, bool pairwise,
959 const u8 *mac_addr, void *cookie,
960 void (*callback) (void *cookie,
961 struct key_params *))
962{
963 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
964 struct ath6kl_key *key = NULL;
965 struct key_params params;
966
967 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
968
969 if (!ath6kl_cfg80211_ready(ar))
970 return -EIO;
971
972 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
973 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
974 "%s: key index %d out of bounds\n", __func__,
975 key_index);
976 return -ENOENT;
977 }
978
979 key = &ar->keys[key_index];
980 memset(&params, 0, sizeof(params));
981 params.cipher = key->cipher;
982 params.key_len = key->key_len;
983 params.seq_len = key->seq_len;
984 params.seq = key->seq;
985 params.key = key->key;
986
987 callback(cookie, &params);
988
989 return key->key_len ? 0 : -ENOENT;
990}
991
992static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
993 struct net_device *ndev,
994 u8 key_index, bool unicast,
995 bool multicast)
996{
997 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
998 struct ath6kl_key *key = NULL;
999 int status = 0;
1000 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001001 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001002
1003 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1004
1005 if (!ath6kl_cfg80211_ready(ar))
1006 return -EIO;
1007
1008 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1009 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1010 "%s: key index %d out of bounds\n",
1011 __func__, key_index);
1012 return -ENOENT;
1013 }
1014
1015 if (!ar->keys[key_index].key_len) {
1016 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1017 __func__, key_index);
1018 return -EINVAL;
1019 }
1020
1021 ar->def_txkey_index = key_index;
1022 key = &ar->keys[ar->def_txkey_index];
1023 key_usage = GROUP_USAGE;
1024 if (ar->prwise_crypto == WEP_CRYPT)
1025 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001026 if (unicast)
1027 key_type = ar->prwise_crypto;
1028 if (multicast)
1029 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001030
Jouni Malinen151411e2011-09-15 15:10:16 +03001031 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001032 return 0; /* Delay until AP mode has been started */
1033
Kalle Valobdcd8172011-07-18 00:22:30 +03001034 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001035 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001036 key->key_len, key->seq, key->key,
1037 KEY_OP_INIT_VAL, NULL,
1038 SYNC_BOTH_WMIFLAG);
1039 if (status)
1040 return -EIO;
1041
1042 return 0;
1043}
1044
1045void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1046 bool ismcast)
1047{
1048 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1049 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1050
1051 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1052 (ismcast ? NL80211_KEYTYPE_GROUP :
1053 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1054 GFP_KERNEL);
1055}
1056
1057static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1058{
1059 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1060 int ret;
1061
1062 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1063 changed);
1064
1065 if (!ath6kl_cfg80211_ready(ar))
1066 return -EIO;
1067
1068 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1069 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1070 if (ret != 0) {
1071 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1072 return -EIO;
1073 }
1074 }
1075
1076 return 0;
1077}
1078
1079/*
1080 * The type nl80211_tx_power_setting replaces the following
1081 * data type from 2.6.36 onwards
1082*/
1083static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1084 enum nl80211_tx_power_setting type,
1085 int dbm)
1086{
1087 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1088 u8 ath6kl_dbm;
1089
1090 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1091 type, dbm);
1092
1093 if (!ath6kl_cfg80211_ready(ar))
1094 return -EIO;
1095
1096 switch (type) {
1097 case NL80211_TX_POWER_AUTOMATIC:
1098 return 0;
1099 case NL80211_TX_POWER_LIMITED:
1100 ar->tx_pwr = ath6kl_dbm = dbm;
1101 break;
1102 default:
1103 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1104 __func__, type);
1105 return -EOPNOTSUPP;
1106 }
1107
1108 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1109
1110 return 0;
1111}
1112
1113static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1114{
1115 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1116
1117 if (!ath6kl_cfg80211_ready(ar))
1118 return -EIO;
1119
1120 if (test_bit(CONNECTED, &ar->flag)) {
1121 ar->tx_pwr = 0;
1122
1123 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1124 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1125 return -EIO;
1126 }
1127
1128 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1129 5 * HZ);
1130
1131 if (signal_pending(current)) {
1132 ath6kl_err("target did not respond\n");
1133 return -EINTR;
1134 }
1135 }
1136
1137 *dbm = ar->tx_pwr;
1138 return 0;
1139}
1140
1141static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1142 struct net_device *dev,
1143 bool pmgmt, int timeout)
1144{
1145 struct ath6kl *ar = ath6kl_priv(dev);
1146 struct wmi_power_mode_cmd mode;
1147
1148 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1149 __func__, pmgmt, timeout);
1150
1151 if (!ath6kl_cfg80211_ready(ar))
1152 return -EIO;
1153
1154 if (pmgmt) {
1155 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1156 mode.pwr_mode = REC_POWER;
1157 } else {
1158 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1159 mode.pwr_mode = MAX_PERF_POWER;
1160 }
1161
1162 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1163 ath6kl_err("wmi_powermode_cmd failed\n");
1164 return -EIO;
1165 }
1166
1167 return 0;
1168}
1169
1170static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1171 struct net_device *ndev,
1172 enum nl80211_iftype type, u32 *flags,
1173 struct vif_params *params)
1174{
1175 struct ath6kl *ar = ath6kl_priv(ndev);
1176 struct wireless_dev *wdev = ar->wdev;
1177
1178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1179
1180 if (!ath6kl_cfg80211_ready(ar))
1181 return -EIO;
1182
1183 switch (type) {
1184 case NL80211_IFTYPE_STATION:
1185 ar->next_mode = INFRA_NETWORK;
1186 break;
1187 case NL80211_IFTYPE_ADHOC:
1188 ar->next_mode = ADHOC_NETWORK;
1189 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001190 case NL80211_IFTYPE_AP:
1191 ar->next_mode = AP_NETWORK;
1192 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001193 case NL80211_IFTYPE_P2P_CLIENT:
1194 ar->next_mode = INFRA_NETWORK;
1195 break;
1196 case NL80211_IFTYPE_P2P_GO:
1197 ar->next_mode = AP_NETWORK;
1198 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001199 default:
1200 ath6kl_err("invalid interface type %u\n", type);
1201 return -EOPNOTSUPP;
1202 }
1203
1204 wdev->iftype = type;
1205
1206 return 0;
1207}
1208
1209static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1210 struct net_device *dev,
1211 struct cfg80211_ibss_params *ibss_param)
1212{
1213 struct ath6kl *ar = ath6kl_priv(dev);
1214 int status;
1215
1216 if (!ath6kl_cfg80211_ready(ar))
1217 return -EIO;
1218
1219 ar->ssid_len = ibss_param->ssid_len;
1220 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1221
1222 if (ibss_param->channel)
1223 ar->ch_hint = ibss_param->channel->center_freq;
1224
1225 if (ibss_param->channel_fixed) {
1226 /*
1227 * TODO: channel_fixed: The channel should be fixed, do not
1228 * search for IBSSs to join on other channels. Target
1229 * firmware does not support this feature, needs to be
1230 * updated.
1231 */
1232 return -EOPNOTSUPP;
1233 }
1234
1235 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1236 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1237 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1238
1239 ath6kl_set_wpa_version(ar, 0);
1240
1241 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1242 if (status)
1243 return status;
1244
1245 if (ibss_param->privacy) {
1246 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1247 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1248 } else {
1249 ath6kl_set_cipher(ar, 0, true);
1250 ath6kl_set_cipher(ar, 0, false);
1251 }
1252
1253 ar->nw_type = ar->next_mode;
1254
1255 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1256 "%s: connect called with authmode %d dot11 auth %d"
1257 " PW crypto %d PW crypto len %d GRP crypto %d"
1258 " GRP crypto len %d channel hint %u\n",
1259 __func__,
1260 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1261 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001262 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001263
1264 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1265 ar->dot11_auth_mode, ar->auth_mode,
1266 ar->prwise_crypto,
1267 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001268 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001269 ar->ssid_len, ar->ssid,
1270 ar->req_bssid, ar->ch_hint,
1271 ar->connect_ctrl_flags);
1272 set_bit(CONNECT_PEND, &ar->flag);
1273
1274 return 0;
1275}
1276
1277static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1278 struct net_device *dev)
1279{
1280 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1281
1282 if (!ath6kl_cfg80211_ready(ar))
1283 return -EIO;
1284
1285 ath6kl_disconnect(ar);
1286 memset(ar->ssid, 0, sizeof(ar->ssid));
1287 ar->ssid_len = 0;
1288
1289 return 0;
1290}
1291
1292static const u32 cipher_suites[] = {
1293 WLAN_CIPHER_SUITE_WEP40,
1294 WLAN_CIPHER_SUITE_WEP104,
1295 WLAN_CIPHER_SUITE_TKIP,
1296 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001297 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001298};
1299
1300static bool is_rate_legacy(s32 rate)
1301{
1302 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1303 6000, 9000, 12000, 18000, 24000,
1304 36000, 48000, 54000
1305 };
1306 u8 i;
1307
1308 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1309 if (rate == legacy[i])
1310 return true;
1311
1312 return false;
1313}
1314
1315static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1316{
1317 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1318 52000, 58500, 65000, 72200
1319 };
1320 u8 i;
1321
1322 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1323 if (rate == ht20[i]) {
1324 if (i == ARRAY_SIZE(ht20) - 1)
1325 /* last rate uses sgi */
1326 *sgi = true;
1327 else
1328 *sgi = false;
1329
1330 *mcs = i;
1331 return true;
1332 }
1333 }
1334 return false;
1335}
1336
1337static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1338{
1339 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1340 81000, 108000, 121500, 135000,
1341 150000
1342 };
1343 u8 i;
1344
1345 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1346 if (rate == ht40[i]) {
1347 if (i == ARRAY_SIZE(ht40) - 1)
1348 /* last rate uses sgi */
1349 *sgi = true;
1350 else
1351 *sgi = false;
1352
1353 *mcs = i;
1354 return true;
1355 }
1356 }
1357
1358 return false;
1359}
1360
1361static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1362 u8 *mac, struct station_info *sinfo)
1363{
1364 struct ath6kl *ar = ath6kl_priv(dev);
1365 long left;
1366 bool sgi;
1367 s32 rate;
1368 int ret;
1369 u8 mcs;
1370
1371 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1372 return -ENOENT;
1373
1374 if (down_interruptible(&ar->sem))
1375 return -EBUSY;
1376
1377 set_bit(STATS_UPDATE_PEND, &ar->flag);
1378
1379 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1380
1381 if (ret != 0) {
1382 up(&ar->sem);
1383 return -EIO;
1384 }
1385
1386 left = wait_event_interruptible_timeout(ar->event_wq,
1387 !test_bit(STATS_UPDATE_PEND,
1388 &ar->flag),
1389 WMI_TIMEOUT);
1390
1391 up(&ar->sem);
1392
1393 if (left == 0)
1394 return -ETIMEDOUT;
1395 else if (left < 0)
1396 return left;
1397
1398 if (ar->target_stats.rx_byte) {
1399 sinfo->rx_bytes = ar->target_stats.rx_byte;
1400 sinfo->filled |= STATION_INFO_RX_BYTES;
1401 sinfo->rx_packets = ar->target_stats.rx_pkt;
1402 sinfo->filled |= STATION_INFO_RX_PACKETS;
1403 }
1404
1405 if (ar->target_stats.tx_byte) {
1406 sinfo->tx_bytes = ar->target_stats.tx_byte;
1407 sinfo->filled |= STATION_INFO_TX_BYTES;
1408 sinfo->tx_packets = ar->target_stats.tx_pkt;
1409 sinfo->filled |= STATION_INFO_TX_PACKETS;
1410 }
1411
1412 sinfo->signal = ar->target_stats.cs_rssi;
1413 sinfo->filled |= STATION_INFO_SIGNAL;
1414
1415 rate = ar->target_stats.tx_ucast_rate;
1416
1417 if (is_rate_legacy(rate)) {
1418 sinfo->txrate.legacy = rate / 100;
1419 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1420 if (sgi) {
1421 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1422 sinfo->txrate.mcs = mcs - 1;
1423 } else {
1424 sinfo->txrate.mcs = mcs;
1425 }
1426
1427 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1428 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1429 if (sgi) {
1430 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1431 sinfo->txrate.mcs = mcs - 1;
1432 } else {
1433 sinfo->txrate.mcs = mcs;
1434 }
1435
1436 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1437 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1438 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001439 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1440 "invalid rate from stats: %d\n", rate);
1441 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001442 return 0;
1443 }
1444
1445 sinfo->filled |= STATION_INFO_TX_BITRATE;
1446
Jouni Malinen32c10872011-09-19 19:15:07 +03001447 if (test_bit(CONNECTED, &ar->flag) &&
1448 test_bit(DTIM_PERIOD_AVAIL, &ar->flag) &&
1449 ar->nw_type == INFRA_NETWORK) {
1450 sinfo->filled |= STATION_INFO_BSS_PARAM;
1451 sinfo->bss_param.flags = 0;
1452 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1453 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1454 }
1455
Kalle Valobdcd8172011-07-18 00:22:30 +03001456 return 0;
1457}
1458
1459static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1460 struct cfg80211_pmksa *pmksa)
1461{
1462 struct ath6kl *ar = ath6kl_priv(netdev);
1463 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1464 pmksa->pmkid, true);
1465}
1466
1467static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1468 struct cfg80211_pmksa *pmksa)
1469{
1470 struct ath6kl *ar = ath6kl_priv(netdev);
1471 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1472 pmksa->pmkid, false);
1473}
1474
1475static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1476{
1477 struct ath6kl *ar = ath6kl_priv(netdev);
1478 if (test_bit(CONNECTED, &ar->flag))
1479 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1480 return 0;
1481}
1482
Kalle Valoabcb3442011-07-22 08:26:20 +03001483#ifdef CONFIG_PM
1484static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1485 struct cfg80211_wowlan *wow)
1486{
1487 struct ath6kl *ar = wiphy_priv(wiphy);
1488
1489 return ath6kl_hif_suspend(ar);
1490}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001491
1492static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1493{
1494 struct ath6kl *ar = wiphy_priv(wiphy);
1495
1496 return ath6kl_hif_resume(ar);
1497}
Kalle Valoabcb3442011-07-22 08:26:20 +03001498#endif
1499
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001500static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1501 struct ieee80211_channel *chan,
1502 enum nl80211_channel_type channel_type)
1503{
1504 struct ath6kl *ar = ath6kl_priv(dev);
1505
1506 if (!ath6kl_cfg80211_ready(ar))
1507 return -EIO;
1508
1509 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1510 __func__, chan->center_freq, chan->hw_value);
1511 ar->next_chan = chan->center_freq;
1512
1513 return 0;
1514}
1515
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001516static bool ath6kl_is_p2p_ie(const u8 *pos)
1517{
1518 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1519 pos[2] == 0x50 && pos[3] == 0x6f &&
1520 pos[4] == 0x9a && pos[5] == 0x09;
1521}
1522
1523static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1524 size_t ies_len)
1525{
1526 const u8 *pos;
1527 u8 *buf = NULL;
1528 size_t len = 0;
1529 int ret;
1530
1531 /*
1532 * Filter out P2P IE(s) since they will be included depending on
1533 * the Probe Request frame in ath6kl_send_go_probe_resp().
1534 */
1535
1536 if (ies && ies_len) {
1537 buf = kmalloc(ies_len, GFP_KERNEL);
1538 if (buf == NULL)
1539 return -ENOMEM;
1540 pos = ies;
1541 while (pos + 1 < ies + ies_len) {
1542 if (pos + 2 + pos[1] > ies + ies_len)
1543 break;
1544 if (!ath6kl_is_p2p_ie(pos)) {
1545 memcpy(buf + len, pos, 2 + pos[1]);
1546 len += 2 + pos[1];
1547 }
1548 pos += 2 + pos[1];
1549 }
1550 }
1551
1552 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1553 buf, len);
1554 kfree(buf);
1555 return ret;
1556}
1557
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001558static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1559 struct beacon_parameters *info, bool add)
1560{
1561 struct ath6kl *ar = ath6kl_priv(dev);
1562 struct ieee80211_mgmt *mgmt;
1563 u8 *ies;
1564 int ies_len;
1565 struct wmi_connect_cmd p;
1566 int res;
1567 int i;
1568
1569 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1570
1571 if (!ath6kl_cfg80211_ready(ar))
1572 return -EIO;
1573
1574 if (ar->next_mode != AP_NETWORK)
1575 return -EOPNOTSUPP;
1576
1577 if (info->beacon_ies) {
1578 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1579 info->beacon_ies,
1580 info->beacon_ies_len);
1581 if (res)
1582 return res;
1583 }
1584 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001585 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1586 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001587 if (res)
1588 return res;
1589 }
1590 if (info->assocresp_ies) {
1591 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1592 info->assocresp_ies,
1593 info->assocresp_ies_len);
1594 if (res)
1595 return res;
1596 }
1597
1598 if (!add)
1599 return 0;
1600
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001601 ar->ap_mode_bkey.valid = false;
1602
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001603 /* TODO:
1604 * info->interval
1605 * info->dtim_period
1606 */
1607
1608 if (info->head == NULL)
1609 return -EINVAL;
1610 mgmt = (struct ieee80211_mgmt *) info->head;
1611 ies = mgmt->u.beacon.variable;
1612 if (ies > info->head + info->head_len)
1613 return -EINVAL;
1614 ies_len = info->head + info->head_len - ies;
1615
1616 if (info->ssid == NULL)
1617 return -EINVAL;
1618 memcpy(ar->ssid, info->ssid, info->ssid_len);
1619 ar->ssid_len = info->ssid_len;
1620 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1621 return -EOPNOTSUPP; /* TODO */
1622
1623 ar->dot11_auth_mode = OPEN_AUTH;
1624
1625 memset(&p, 0, sizeof(p));
1626
1627 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1628 switch (info->crypto.akm_suites[i]) {
1629 case WLAN_AKM_SUITE_8021X:
1630 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1631 p.auth_mode |= WPA_AUTH;
1632 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1633 p.auth_mode |= WPA2_AUTH;
1634 break;
1635 case WLAN_AKM_SUITE_PSK:
1636 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1637 p.auth_mode |= WPA_PSK_AUTH;
1638 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1639 p.auth_mode |= WPA2_PSK_AUTH;
1640 break;
1641 }
1642 }
1643 if (p.auth_mode == 0)
1644 p.auth_mode = NONE_AUTH;
1645 ar->auth_mode = p.auth_mode;
1646
1647 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1648 switch (info->crypto.ciphers_pairwise[i]) {
1649 case WLAN_CIPHER_SUITE_WEP40:
1650 case WLAN_CIPHER_SUITE_WEP104:
1651 p.prwise_crypto_type |= WEP_CRYPT;
1652 break;
1653 case WLAN_CIPHER_SUITE_TKIP:
1654 p.prwise_crypto_type |= TKIP_CRYPT;
1655 break;
1656 case WLAN_CIPHER_SUITE_CCMP:
1657 p.prwise_crypto_type |= AES_CRYPT;
1658 break;
1659 }
1660 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001661 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001662 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001663 ath6kl_set_cipher(ar, 0, true);
1664 } else if (info->crypto.n_ciphers_pairwise == 1)
1665 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001666
1667 switch (info->crypto.cipher_group) {
1668 case WLAN_CIPHER_SUITE_WEP40:
1669 case WLAN_CIPHER_SUITE_WEP104:
1670 p.grp_crypto_type = WEP_CRYPT;
1671 break;
1672 case WLAN_CIPHER_SUITE_TKIP:
1673 p.grp_crypto_type = TKIP_CRYPT;
1674 break;
1675 case WLAN_CIPHER_SUITE_CCMP:
1676 p.grp_crypto_type = AES_CRYPT;
1677 break;
1678 default:
1679 p.grp_crypto_type = NONE_CRYPT;
1680 break;
1681 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001682 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001683
1684 p.nw_type = AP_NETWORK;
1685 ar->nw_type = ar->next_mode;
1686
1687 p.ssid_len = ar->ssid_len;
1688 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1689 p.dot11_auth_mode = ar->dot11_auth_mode;
1690 p.ch = cpu_to_le16(ar->next_chan);
1691
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001692 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1693 if (res < 0)
1694 return res;
1695
1696 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001697}
1698
1699static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1700 struct beacon_parameters *info)
1701{
1702 return ath6kl_ap_beacon(wiphy, dev, info, true);
1703}
1704
1705static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1706 struct beacon_parameters *info)
1707{
1708 return ath6kl_ap_beacon(wiphy, dev, info, false);
1709}
1710
1711static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1712{
1713 struct ath6kl *ar = ath6kl_priv(dev);
1714
1715 if (ar->nw_type != AP_NETWORK)
1716 return -EOPNOTSUPP;
1717 if (!test_bit(CONNECTED, &ar->flag))
1718 return -ENOTCONN;
1719
1720 ath6kl_wmi_disconnect_cmd(ar->wmi);
1721 clear_bit(CONNECTED, &ar->flag);
1722
1723 return 0;
1724}
1725
Jouni Malinen23875132011-08-30 21:57:53 +03001726static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1727 u8 *mac, struct station_parameters *params)
1728{
1729 struct ath6kl *ar = ath6kl_priv(dev);
1730
1731 if (ar->nw_type != AP_NETWORK)
1732 return -EOPNOTSUPP;
1733
1734 /* Use this only for authorizing/unauthorizing a station */
1735 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1736 return -EOPNOTSUPP;
1737
1738 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1739 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1740 mac, 0);
1741 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1742 0);
1743}
1744
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001745static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1746 struct net_device *dev,
1747 struct ieee80211_channel *chan,
1748 enum nl80211_channel_type channel_type,
1749 unsigned int duration,
1750 u64 *cookie)
1751{
1752 struct ath6kl *ar = ath6kl_priv(dev);
1753
1754 /* TODO: if already pending or ongoing remain-on-channel,
1755 * return -EBUSY */
1756 *cookie = 1; /* only a single pending request is supported */
1757
1758 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1759 duration);
1760}
1761
1762static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1763 struct net_device *dev,
1764 u64 cookie)
1765{
1766 struct ath6kl *ar = ath6kl_priv(dev);
1767
1768 if (cookie != 1)
1769 return -ENOENT;
1770
1771 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1772}
1773
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001774static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1775 size_t len, unsigned int freq)
1776{
1777 const u8 *pos;
1778 u8 *p2p;
1779 int p2p_len;
1780 int ret;
1781 const struct ieee80211_mgmt *mgmt;
1782
1783 mgmt = (const struct ieee80211_mgmt *) buf;
1784
1785 /* Include P2P IE(s) from the frame generated in user space. */
1786
1787 p2p = kmalloc(len, GFP_KERNEL);
1788 if (p2p == NULL)
1789 return -ENOMEM;
1790 p2p_len = 0;
1791
1792 pos = mgmt->u.probe_resp.variable;
1793 while (pos + 1 < buf + len) {
1794 if (pos + 2 + pos[1] > buf + len)
1795 break;
1796 if (ath6kl_is_p2p_ie(pos)) {
1797 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1798 p2p_len += 2 + pos[1];
1799 }
1800 pos += 2 + pos[1];
1801 }
1802
1803 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1804 p2p, p2p_len);
1805 kfree(p2p);
1806 return ret;
1807}
1808
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001809static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1810 struct ieee80211_channel *chan, bool offchan,
1811 enum nl80211_channel_type channel_type,
1812 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001813 const u8 *buf, size_t len, bool no_cck,
1814 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001815{
1816 struct ath6kl *ar = ath6kl_priv(dev);
1817 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001818 const struct ieee80211_mgmt *mgmt;
1819
1820 mgmt = (const struct ieee80211_mgmt *) buf;
1821 if (buf + len >= mgmt->u.probe_resp.variable &&
1822 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1823 ieee80211_is_probe_resp(mgmt->frame_control)) {
1824 /*
1825 * Send Probe Response frame in AP mode using a separate WMI
1826 * command to allow the target to fill in the generic IEs.
1827 */
1828 *cookie = 0; /* TX status not supported */
1829 return ath6kl_send_go_probe_resp(ar, buf, len,
1830 chan->center_freq);
1831 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001832
1833 id = ar->send_action_id++;
1834 if (id == 0) {
1835 /*
1836 * 0 is a reserved value in the WMI command and shall not be
1837 * used for the command.
1838 */
1839 id = ar->send_action_id++;
1840 }
1841
1842 *cookie = id;
1843 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1844 buf, len);
1845}
1846
Jouni Malinenae32c302011-08-30 21:58:01 +03001847static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1848 struct net_device *dev,
1849 u16 frame_type, bool reg)
1850{
1851 struct ath6kl *ar = ath6kl_priv(dev);
1852
1853 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1854 __func__, frame_type, reg);
1855 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1856 /*
1857 * Note: This notification callback is not allowed to sleep, so
1858 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1859 * hardcode target to report Probe Request frames all the time.
1860 */
1861 ar->probe_req_report = reg;
1862 }
1863}
1864
Jouni Malinenf80574a2011-08-30 21:58:04 +03001865static const struct ieee80211_txrx_stypes
1866ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1867 [NL80211_IFTYPE_STATION] = {
1868 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1869 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1870 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1871 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1872 },
1873 [NL80211_IFTYPE_P2P_CLIENT] = {
1874 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1875 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1876 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1877 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1878 },
1879 [NL80211_IFTYPE_P2P_GO] = {
1880 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1881 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1882 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1883 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1884 },
1885};
1886
Kalle Valobdcd8172011-07-18 00:22:30 +03001887static struct cfg80211_ops ath6kl_cfg80211_ops = {
1888 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1889 .scan = ath6kl_cfg80211_scan,
1890 .connect = ath6kl_cfg80211_connect,
1891 .disconnect = ath6kl_cfg80211_disconnect,
1892 .add_key = ath6kl_cfg80211_add_key,
1893 .get_key = ath6kl_cfg80211_get_key,
1894 .del_key = ath6kl_cfg80211_del_key,
1895 .set_default_key = ath6kl_cfg80211_set_default_key,
1896 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1897 .set_tx_power = ath6kl_cfg80211_set_txpower,
1898 .get_tx_power = ath6kl_cfg80211_get_txpower,
1899 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1900 .join_ibss = ath6kl_cfg80211_join_ibss,
1901 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1902 .get_station = ath6kl_get_station,
1903 .set_pmksa = ath6kl_set_pmksa,
1904 .del_pmksa = ath6kl_del_pmksa,
1905 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001906 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001907#ifdef CONFIG_PM
1908 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001909 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001910#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001911 .set_channel = ath6kl_set_channel,
1912 .add_beacon = ath6kl_add_beacon,
1913 .set_beacon = ath6kl_set_beacon,
1914 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001915 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001916 .remain_on_channel = ath6kl_remain_on_channel,
1917 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001918 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001919 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001920};
1921
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301922struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001923{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001924 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301925 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301926 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001927
1928 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301929 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301930
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301931 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001932 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001933 return NULL;
1934 }
1935
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301936 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001937 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301938 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301939 ar->dev = dev;
1940
1941 spin_lock_init(&ar->lock);
1942 spin_lock_init(&ar->mcastpsq_lock);
1943
1944 init_waitqueue_head(&ar->event_wq);
1945 sema_init(&ar->sem, 1);
1946
1947 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1948
1949 clear_bit(WMI_ENABLED, &ar->flag);
1950 clear_bit(SKIP_SCAN, &ar->flag);
1951 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
1952
1953 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
1954 ar->listen_intvl_b = 0;
1955 ar->tx_pwr = 0;
1956
1957 ar->intra_bss = 1;
1958 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
1959 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
1960 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
1961 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
1962
1963 memset((u8 *)ar->sta_list, 0,
1964 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
1965
1966 /* Init the PS queues */
1967 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
1968 spin_lock_init(&ar->sta_list[ctr].psq_lock);
1969 skb_queue_head_init(&ar->sta_list[ctr].psq);
1970 }
1971
1972 skb_queue_head_init(&ar->mcastpsq);
1973
1974 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
1975
1976 return ar;
1977}
1978
1979int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
1980{
1981 struct wiphy *wiphy = ar->wiphy;
1982 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001983
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301984 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03001985
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301986 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001987
Kalle Valobdcd8172011-07-18 00:22:30 +03001988 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301989 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001990
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301991 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301992 BIT(NL80211_IFTYPE_ADHOC) |
1993 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001994 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301995 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301996 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001997 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301998
Kalle Valobdcd8172011-07-18 00:22:30 +03001999 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302000 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2001 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2002 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2003 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2004 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002005
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302006 wiphy->cipher_suites = cipher_suites;
2007 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002008
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302009 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002010 if (ret < 0) {
2011 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302012 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002013 }
2014
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302015 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002016}
2017
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302018static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002019{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302020 struct ath6kl *ar = vif->ar;
2021
2022 ar->aggr_cntxt = aggr_init(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302023 if (!ar->aggr_cntxt) {
2024 ath6kl_err("failed to initialize aggr\n");
2025 return -ENOMEM;
2026 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002027
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302028 setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302029 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302030
2031 return 0;
2032}
2033
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302034void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302035{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302036 struct ath6kl *ar = vif->ar;
2037
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302038 aggr_module_destroy(ar->aggr_cntxt);
2039
2040 ar->aggr_cntxt = NULL;
2041
2042 if (test_bit(NETDEV_REGISTERED, &ar->flag)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302043 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302044 clear_bit(NETDEV_REGISTERED, &ar->flag);
2045 }
2046
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302047 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302048}
2049
2050struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
2051 enum nl80211_iftype type)
2052{
2053 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302054 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302055
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302056 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302057 if (!ndev)
2058 return NULL;
2059
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302060 vif = netdev_priv(ndev);
2061 ndev->ieee80211_ptr = &vif->wdev;
2062 vif->wdev.wiphy = ar->wiphy;
2063 vif->ar = ar;
2064 ar->vif = vif;
2065 vif->ndev = ndev;
2066 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2067 vif->wdev.netdev = ndev;
2068 vif->wdev.iftype = type;
2069 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302070 ar->net_dev = ndev;
2071
2072 init_netdev(ndev);
2073
2074 ath6kl_init_control_info(ar);
2075
2076 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302077 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302078 goto err;
2079
2080 if (register_netdev(ndev))
2081 goto err;
2082
2083 ar->sme_state = SME_DISCONNECTED;
2084 set_bit(WLAN_ENABLED, &ar->flag);
2085 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
2086 set_bit(NETDEV_REGISTERED, &ar->flag);
2087
2088 return ndev;
2089
2090err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302091 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302092
2093 return NULL;
2094}
2095
2096void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2097{
Kalle Valobdcd8172011-07-18 00:22:30 +03002098 if (ar->scan_req) {
2099 cfg80211_scan_done(ar->scan_req, true);
2100 ar->scan_req = NULL;
2101 }
2102
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302103 wiphy_unregister(ar->wiphy);
2104 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002105}