blob: 4d56a3419c619d68449929cbff8678c96eb7b412 [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{
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530234 struct ath6kl_vif *vif = ar->vif;
235
Kalle Valobdcd8172011-07-18 00:22:30 +0300236 if (!test_bit(WMI_READY, &ar->flag)) {
237 ath6kl_err("wmi is not ready\n");
238 return false;
239 }
240
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530241 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300242 ath6kl_err("wlan disabled\n");
243 return false;
244 }
245
246 return true;
247}
248
Kevin Fang6981ffd2011-10-07 08:51:19 +0800249static bool ath6kl_is_wpa_ie(const u8 *pos)
250{
251 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
252 pos[2] == 0x00 && pos[3] == 0x50 &&
253 pos[4] == 0xf2 && pos[5] == 0x01;
254}
255
256static bool ath6kl_is_rsn_ie(const u8 *pos)
257{
258 return pos[0] == WLAN_EID_RSN;
259}
260
261static int ath6kl_set_assoc_req_ies(struct ath6kl *ar, const u8 *ies,
262 size_t ies_len)
263{
264 const u8 *pos;
265 u8 *buf = NULL;
266 size_t len = 0;
267 int ret;
268
269 /*
270 * Filter out RSN/WPA IE(s)
271 */
272
273 if (ies && ies_len) {
274 buf = kmalloc(ies_len, GFP_KERNEL);
275 if (buf == NULL)
276 return -ENOMEM;
277 pos = ies;
278
279 while (pos + 1 < ies + ies_len) {
280 if (pos + 2 + pos[1] > ies + ies_len)
281 break;
282 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
283 memcpy(buf + len, pos, 2 + pos[1]);
284 len += 2 + pos[1];
285 }
286 pos += 2 + pos[1];
287 }
288 }
289
290 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_REQ,
291 buf, len);
292 kfree(buf);
293 return ret;
294}
295
Kalle Valobdcd8172011-07-18 00:22:30 +0300296static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
297 struct cfg80211_connect_params *sme)
298{
299 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530300 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300301 int status;
302
303 ar->sme_state = SME_CONNECTING;
304
305 if (!ath6kl_cfg80211_ready(ar))
306 return -EIO;
307
308 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
309 ath6kl_err("destroy in progress\n");
310 return -EBUSY;
311 }
312
313 if (test_bit(SKIP_SCAN, &ar->flag) &&
314 ((sme->channel && sme->channel->center_freq == 0) ||
315 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
316 ath6kl_err("SkipScan: channel or bssid invalid\n");
317 return -EINVAL;
318 }
319
320 if (down_interruptible(&ar->sem)) {
321 ath6kl_err("busy, couldn't get access\n");
322 return -ERESTARTSYS;
323 }
324
325 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
326 ath6kl_err("busy, destroy in progress\n");
327 up(&ar->sem);
328 return -EBUSY;
329 }
330
331 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
332 /*
333 * sleep until the command queue drains
334 */
335 wait_event_interruptible_timeout(ar->event_wq,
336 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
337 WMI_TIMEOUT);
338 if (signal_pending(current)) {
339 ath6kl_err("cmd queue drain timeout\n");
340 up(&ar->sem);
341 return -EINTR;
342 }
343 }
344
Kevin Fang6981ffd2011-10-07 08:51:19 +0800345 if (sme->ie && (sme->ie_len > 0)) {
346 status = ath6kl_set_assoc_req_ies(ar, sme->ie, sme->ie_len);
347 if (status)
348 return status;
349 }
350
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530351 if (test_bit(CONNECTED, &vif->flags) &&
Kalle Valobdcd8172011-07-18 00:22:30 +0300352 ar->ssid_len == sme->ssid_len &&
353 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
354 ar->reconnect_flag = true;
355 status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
356 ar->ch_hint);
357
358 up(&ar->sem);
359 if (status) {
360 ath6kl_err("wmi_reconnect_cmd failed\n");
361 return -EIO;
362 }
363 return 0;
364 } else if (ar->ssid_len == sme->ssid_len &&
365 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
366 ath6kl_disconnect(ar);
367 }
368
369 memset(ar->ssid, 0, sizeof(ar->ssid));
370 ar->ssid_len = sme->ssid_len;
371 memcpy(ar->ssid, sme->ssid, sme->ssid_len);
372
373 if (sme->channel)
374 ar->ch_hint = sme->channel->center_freq;
375
376 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
377 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
378 memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
379
380 ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
381
382 status = ath6kl_set_auth_type(ar, sme->auth_type);
383 if (status) {
384 up(&ar->sem);
385 return status;
386 }
387
388 if (sme->crypto.n_ciphers_pairwise)
389 ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
390 else
391 ath6kl_set_cipher(ar, 0, true);
392
393 ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
394
395 if (sme->crypto.n_akm_suites)
396 ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
397
398 if ((sme->key_len) &&
399 (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
400 struct ath6kl_key *key = NULL;
401
402 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
403 sme->key_idx > WMI_MAX_KEY_INDEX) {
404 ath6kl_err("key index %d out of bounds\n",
405 sme->key_idx);
406 up(&ar->sem);
407 return -ENOENT;
408 }
409
410 key = &ar->keys[sme->key_idx];
411 key->key_len = sme->key_len;
412 memcpy(key->key, sme->key, key->key_len);
413 key->cipher = ar->prwise_crypto;
414 ar->def_txkey_index = sme->key_idx;
415
416 ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
417 ar->prwise_crypto,
418 GROUP_USAGE | TX_USAGE,
419 key->key_len,
420 NULL,
421 key->key, KEY_OP_INIT_VAL, NULL,
422 NO_SYNC_WMIFLAG);
423 }
424
425 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530426 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300427 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
428 ath6kl_err("couldn't set bss filtering\n");
429 up(&ar->sem);
430 return -EIO;
431 }
432 }
433
434 ar->nw_type = ar->next_mode;
435
436 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
437 "%s: connect called with authmode %d dot11 auth %d"
438 " PW crypto %d PW crypto len %d GRP crypto %d"
439 " GRP crypto len %d channel hint %u\n",
440 __func__,
441 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
442 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +0300443 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300444
445 ar->reconnect_flag = 0;
446 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
447 ar->dot11_auth_mode, ar->auth_mode,
448 ar->prwise_crypto,
449 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +0300450 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +0300451 ar->ssid_len, ar->ssid,
452 ar->req_bssid, ar->ch_hint,
453 ar->connect_ctrl_flags);
454
455 up(&ar->sem);
456
457 if (status == -EINVAL) {
458 memset(ar->ssid, 0, sizeof(ar->ssid));
459 ar->ssid_len = 0;
460 ath6kl_err("invalid request\n");
461 return -ENOENT;
462 } else if (status) {
463 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
464 return -EIO;
465 }
466
467 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
468 ((ar->auth_mode == WPA_PSK_AUTH)
469 || (ar->auth_mode == WPA2_PSK_AUTH))) {
470 mod_timer(&ar->disconnect_timer,
471 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
472 }
473
474 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530475 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300476
477 return 0;
478}
479
Jouni Malinen01cac472011-09-19 19:14:59 +0300480static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
481 struct ieee80211_channel *chan,
482 const u8 *beacon_ie, size_t beacon_ie_len)
483{
484 struct cfg80211_bss *bss;
485 u8 *ie;
486
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530487 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300488 ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
489 WLAN_CAPABILITY_ESS);
490 if (bss == NULL) {
491 /*
492 * Since cfg80211 may not yet know about the BSS,
493 * generate a partial entry until the first BSS info
494 * event becomes available.
495 *
496 * Prepend SSID element since it is not included in the Beacon
497 * IEs from the target.
498 */
499 ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
500 if (ie == NULL)
501 return -ENOMEM;
502 ie[0] = WLAN_EID_SSID;
503 ie[1] = ar->ssid_len;
504 memcpy(ie + 2, ar->ssid, ar->ssid_len);
505 memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530506 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300507 bssid, 0, WLAN_CAPABILITY_ESS, 100,
508 ie, 2 + ar->ssid_len + beacon_ie_len,
509 0, GFP_KERNEL);
510 if (bss)
511 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
512 "%pM prior to indicating connect/roamed "
513 "event\n", bssid);
514 kfree(ie);
515 } else
516 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
517 "entry\n");
518
519 if (bss == NULL)
520 return -ENOMEM;
521
522 cfg80211_put_bss(bss);
523
524 return 0;
525}
526
Kalle Valobdcd8172011-07-18 00:22:30 +0300527void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
528 u8 *bssid, u16 listen_intvl,
529 u16 beacon_intvl,
530 enum network_type nw_type,
531 u8 beacon_ie_len, u8 assoc_req_len,
532 u8 assoc_resp_len, u8 *assoc_info)
533{
Jouni Malinen01cac472011-09-19 19:14:59 +0300534 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530535 /* TODO: Findout vif */
536 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +0300537
538 /* capinfo + listen interval */
539 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
540
541 /* capinfo + status code + associd */
542 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
543
544 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
545 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
546 assoc_resp_ie_offset;
547
548 assoc_req_len -= assoc_req_ie_offset;
549 assoc_resp_len -= assoc_resp_ie_offset;
550
Jouni Malinen32c10872011-09-19 19:15:07 +0300551 /*
552 * Store Beacon interval here; DTIM period will be available only once
553 * a Beacon frame from the AP is seen.
554 */
555 ar->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530556 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300557
Kalle Valobdcd8172011-07-18 00:22:30 +0300558 if (nw_type & ADHOC_NETWORK) {
559 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
560 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
561 "%s: ath6k not in ibss mode\n", __func__);
562 return;
563 }
564 }
565
566 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300567 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
568 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300569 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
570 "%s: ath6k not in station mode\n", __func__);
571 return;
572 }
573 }
574
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530575 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300576
Kalle Valobdcd8172011-07-18 00:22:30 +0300577
578 if (nw_type & ADHOC_NETWORK) {
579 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
580 return;
581 }
582
Jouni Malinen01cac472011-09-19 19:14:59 +0300583 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
584 beacon_ie_len) < 0) {
585 ath6kl_err("could not add cfg80211 bss entry for "
586 "connect/roamed notification\n");
587 return;
588 }
589
Raja Mani9aa60352011-08-04 19:26:29 +0530590 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300591 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530592 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300593 cfg80211_connect_result(ar->net_dev, bssid,
594 assoc_req_ie, assoc_req_len,
595 assoc_resp_ie, assoc_resp_len,
596 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530597 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300598 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300599 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300600 assoc_req_ie, assoc_req_len,
601 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
602 }
603}
604
605static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
606 struct net_device *dev, u16 reason_code)
607{
608 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
609
610 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
611 reason_code);
612
613 if (!ath6kl_cfg80211_ready(ar))
614 return -EIO;
615
616 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
617 ath6kl_err("busy, destroy in progress\n");
618 return -EBUSY;
619 }
620
621 if (down_interruptible(&ar->sem)) {
622 ath6kl_err("busy, couldn't get access\n");
623 return -ERESTARTSYS;
624 }
625
626 ar->reconnect_flag = 0;
627 ath6kl_disconnect(ar);
628 memset(ar->ssid, 0, sizeof(ar->ssid));
629 ar->ssid_len = 0;
630
631 if (!test_bit(SKIP_SCAN, &ar->flag))
632 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
633
634 up(&ar->sem);
635
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530636 ar->sme_state = SME_DISCONNECTED;
637
Kalle Valobdcd8172011-07-18 00:22:30 +0300638 return 0;
639}
640
641void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
642 u8 *bssid, u8 assoc_resp_len,
643 u8 *assoc_info, u16 proto_reason)
644{
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530645 /* TODO: Findout vif */
646 struct ath6kl_vif *vif = ar->vif;
647
Kalle Valobdcd8172011-07-18 00:22:30 +0300648 if (ar->scan_req) {
649 cfg80211_scan_done(ar->scan_req, true);
650 ar->scan_req = NULL;
651 }
652
653 if (ar->nw_type & ADHOC_NETWORK) {
654 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
655 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
656 "%s: ath6k not in ibss mode\n", __func__);
657 return;
658 }
659 memset(bssid, 0, ETH_ALEN);
660 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
661 return;
662 }
663
664 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300665 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
666 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300667 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
668 "%s: ath6k not in station mode\n", __func__);
669 return;
670 }
671 }
672
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530673 /*
674 * Send a disconnect command to target when a disconnect event is
675 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
676 * request from host) to make the firmware stop trying to connect even
677 * after giving disconnect event. There will be one more disconnect
678 * event for this disconnect command with reason code DISCONNECT_CMD
679 * which will be notified to cfg80211.
680 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300681
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530682 if (reason != DISCONNECT_CMD) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300683 ath6kl_wmi_disconnect_cmd(ar->wmi);
684 return;
685 }
686
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530687 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300688
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530689 if (ar->sme_state == SME_CONNECTING) {
690 cfg80211_connect_result(ar->net_dev,
691 bssid, NULL, 0,
692 NULL, 0,
693 WLAN_STATUS_UNSPECIFIED_FAILURE,
694 GFP_KERNEL);
695 } else if (ar->sme_state == SME_CONNECTED) {
696 cfg80211_disconnected(ar->net_dev, reason,
697 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300698 }
699
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530700 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300701}
702
Kalle Valobdcd8172011-07-18 00:22:30 +0300703static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
704 struct cfg80211_scan_request *request)
705{
706 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530707 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300708 s8 n_channels = 0;
709 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300710 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530711 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300712
713 if (!ath6kl_cfg80211_ready(ar))
714 return -EIO;
715
716 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530717 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300718 ret = ath6kl_wmi_bssfilter_cmd(
719 ar->wmi,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530720 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300721 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
722 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300723 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300724 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300725 }
726 }
727
728 if (request->n_ssids && request->ssids[0].ssid_len) {
729 u8 i;
730
731 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
732 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
733
734 for (i = 0; i < request->n_ssids; i++)
735 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
736 SPECIFIC_SSID_FLAG,
737 request->ssids[i].ssid_len,
738 request->ssids[i].ssid);
739 }
740
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300741 if (request->ie) {
742 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
743 request->ie, request->ie_len);
744 if (ret) {
745 ath6kl_err("failed to set Probe Request appie for "
746 "scan");
747 return ret;
748 }
749 }
750
Jouni Malinen11869be2011-09-02 20:07:06 +0300751 /*
752 * Scan only the requested channels if the request specifies a set of
753 * channels. If the list is longer than the target supports, do not
754 * configure the list and instead, scan all available channels.
755 */
756 if (request->n_channels > 0 &&
757 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300758 u8 i;
759
Jouni Malinen11869be2011-09-02 20:07:06 +0300760 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300761
762 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
763 if (channels == NULL) {
764 ath6kl_warn("failed to set scan channels, "
765 "scan all channels");
766 n_channels = 0;
767 }
768
769 for (i = 0; i < n_channels; i++)
770 channels[i] = request->channels[i]->center_freq;
771 }
772
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530773 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530774 force_fg_scan = 1;
775
776 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, force_fg_scan,
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300777 false, 0, 0, n_channels, channels);
778 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300779 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300780 else
781 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300782
Edward Lu1276c9e2011-08-30 21:58:00 +0300783 kfree(channels);
784
Kalle Valobdcd8172011-07-18 00:22:30 +0300785 return ret;
786}
787
788void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
789{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300790 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300791
792 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
793
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300794 if (!ar->scan_req)
795 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300796
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300797 if ((status == -ECANCELED) || (status == -EBUSY)) {
798 cfg80211_scan_done(ar->scan_req, true);
799 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300800 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300801
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300802 cfg80211_scan_done(ar->scan_req, false);
803
804 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
805 for (i = 0; i < ar->scan_req->n_ssids; i++) {
806 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
807 DISABLE_SSID_FLAG,
808 0, NULL);
809 }
810 }
811
812out:
813 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300814}
815
816static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
817 u8 key_index, bool pairwise,
818 const u8 *mac_addr,
819 struct key_params *params)
820{
821 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530822 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300823 struct ath6kl_key *key = NULL;
824 u8 key_usage;
825 u8 key_type;
826 int status = 0;
827
828 if (!ath6kl_cfg80211_ready(ar))
829 return -EIO;
830
Jouni Malinen837cb972011-10-11 17:31:57 +0300831 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
832 if (params->key_len != WMI_KRK_LEN)
833 return -EINVAL;
834 return ath6kl_wmi_add_krk_cmd(ar->wmi, params->key);
835 }
836
Kalle Valobdcd8172011-07-18 00:22:30 +0300837 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
838 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
839 "%s: key index %d out of bounds\n", __func__,
840 key_index);
841 return -ENOENT;
842 }
843
844 key = &ar->keys[key_index];
845 memset(key, 0, sizeof(struct ath6kl_key));
846
847 if (pairwise)
848 key_usage = PAIRWISE_USAGE;
849 else
850 key_usage = GROUP_USAGE;
851
852 if (params) {
853 if (params->key_len > WLAN_MAX_KEY_LEN ||
854 params->seq_len > sizeof(key->seq))
855 return -EINVAL;
856
857 key->key_len = params->key_len;
858 memcpy(key->key, params->key, key->key_len);
859 key->seq_len = params->seq_len;
860 memcpy(key->seq, params->seq, key->seq_len);
861 key->cipher = params->cipher;
862 }
863
864 switch (key->cipher) {
865 case WLAN_CIPHER_SUITE_WEP40:
866 case WLAN_CIPHER_SUITE_WEP104:
867 key_type = WEP_CRYPT;
868 break;
869
870 case WLAN_CIPHER_SUITE_TKIP:
871 key_type = TKIP_CRYPT;
872 break;
873
874 case WLAN_CIPHER_SUITE_CCMP:
875 key_type = AES_CRYPT;
876 break;
877
878 default:
879 return -ENOTSUPP;
880 }
881
882 if (((ar->auth_mode == WPA_PSK_AUTH)
883 || (ar->auth_mode == WPA2_PSK_AUTH))
884 && (key_usage & GROUP_USAGE))
885 del_timer(&ar->disconnect_timer);
886
887 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
888 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
889 __func__, key_index, key->key_len, key_type,
890 key_usage, key->seq_len);
891
892 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300893
894 if (ar->nw_type == AP_NETWORK && !pairwise &&
895 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
896 ar->ap_mode_bkey.valid = true;
897 ar->ap_mode_bkey.key_index = key_index;
898 ar->ap_mode_bkey.key_type = key_type;
899 ar->ap_mode_bkey.key_len = key->key_len;
900 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530901 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300902 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
903 "key configuration until AP mode has been "
904 "started\n");
905 /*
906 * The key will be set in ath6kl_connect_ap_mode() once
907 * the connected event is received from the target.
908 */
909 return 0;
910 }
911 }
912
Jouni Malinen151411e2011-09-15 15:10:16 +0300913 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530914 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300915 /*
916 * Store the key locally so that it can be re-configured after
917 * the AP mode has properly started
918 * (ath6kl_install_statioc_wep_keys).
919 */
920 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
921 "until AP mode has been started\n");
922 ar->wep_key_list[key_index].key_len = key->key_len;
923 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
924 return 0;
925 }
926
Kalle Valobdcd8172011-07-18 00:22:30 +0300927 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
928 key_type, key_usage, key->key_len,
929 key->seq, key->key, KEY_OP_INIT_VAL,
930 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
931
932 if (status)
933 return -EIO;
934
935 return 0;
936}
937
938static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
939 u8 key_index, bool pairwise,
940 const u8 *mac_addr)
941{
942 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
943
944 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
945
946 if (!ath6kl_cfg80211_ready(ar))
947 return -EIO;
948
949 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
950 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
951 "%s: key index %d out of bounds\n", __func__,
952 key_index);
953 return -ENOENT;
954 }
955
956 if (!ar->keys[key_index].key_len) {
957 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
958 "%s: index %d is empty\n", __func__, key_index);
959 return 0;
960 }
961
962 ar->keys[key_index].key_len = 0;
963
964 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
965}
966
967static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
968 u8 key_index, bool pairwise,
969 const u8 *mac_addr, void *cookie,
970 void (*callback) (void *cookie,
971 struct key_params *))
972{
973 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
974 struct ath6kl_key *key = NULL;
975 struct key_params params;
976
977 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
978
979 if (!ath6kl_cfg80211_ready(ar))
980 return -EIO;
981
982 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
983 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
984 "%s: key index %d out of bounds\n", __func__,
985 key_index);
986 return -ENOENT;
987 }
988
989 key = &ar->keys[key_index];
990 memset(&params, 0, sizeof(params));
991 params.cipher = key->cipher;
992 params.key_len = key->key_len;
993 params.seq_len = key->seq_len;
994 params.seq = key->seq;
995 params.key = key->key;
996
997 callback(cookie, &params);
998
999 return key->key_len ? 0 : -ENOENT;
1000}
1001
1002static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1003 struct net_device *ndev,
1004 u8 key_index, bool unicast,
1005 bool multicast)
1006{
1007 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301008 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001009 struct ath6kl_key *key = NULL;
1010 int status = 0;
1011 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001012 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001013
1014 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1015
1016 if (!ath6kl_cfg80211_ready(ar))
1017 return -EIO;
1018
1019 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1020 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1021 "%s: key index %d out of bounds\n",
1022 __func__, key_index);
1023 return -ENOENT;
1024 }
1025
1026 if (!ar->keys[key_index].key_len) {
1027 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1028 __func__, key_index);
1029 return -EINVAL;
1030 }
1031
1032 ar->def_txkey_index = key_index;
1033 key = &ar->keys[ar->def_txkey_index];
1034 key_usage = GROUP_USAGE;
1035 if (ar->prwise_crypto == WEP_CRYPT)
1036 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001037 if (unicast)
1038 key_type = ar->prwise_crypto;
1039 if (multicast)
1040 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001041
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301042 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001043 return 0; /* Delay until AP mode has been started */
1044
Kalle Valobdcd8172011-07-18 00:22:30 +03001045 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001046 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001047 key->key_len, key->seq, key->key,
1048 KEY_OP_INIT_VAL, NULL,
1049 SYNC_BOTH_WMIFLAG);
1050 if (status)
1051 return -EIO;
1052
1053 return 0;
1054}
1055
1056void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1057 bool ismcast)
1058{
1059 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1060 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1061
1062 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1063 (ismcast ? NL80211_KEYTYPE_GROUP :
1064 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1065 GFP_KERNEL);
1066}
1067
1068static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1069{
1070 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1071 int ret;
1072
1073 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1074 changed);
1075
1076 if (!ath6kl_cfg80211_ready(ar))
1077 return -EIO;
1078
1079 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1080 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1081 if (ret != 0) {
1082 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1083 return -EIO;
1084 }
1085 }
1086
1087 return 0;
1088}
1089
1090/*
1091 * The type nl80211_tx_power_setting replaces the following
1092 * data type from 2.6.36 onwards
1093*/
1094static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1095 enum nl80211_tx_power_setting type,
1096 int dbm)
1097{
1098 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1099 u8 ath6kl_dbm;
1100
1101 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1102 type, dbm);
1103
1104 if (!ath6kl_cfg80211_ready(ar))
1105 return -EIO;
1106
1107 switch (type) {
1108 case NL80211_TX_POWER_AUTOMATIC:
1109 return 0;
1110 case NL80211_TX_POWER_LIMITED:
1111 ar->tx_pwr = ath6kl_dbm = dbm;
1112 break;
1113 default:
1114 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1115 __func__, type);
1116 return -EOPNOTSUPP;
1117 }
1118
1119 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1120
1121 return 0;
1122}
1123
1124static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1125{
1126 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301127 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001128
1129 if (!ath6kl_cfg80211_ready(ar))
1130 return -EIO;
1131
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301132 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001133 ar->tx_pwr = 0;
1134
1135 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1136 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1137 return -EIO;
1138 }
1139
1140 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1141 5 * HZ);
1142
1143 if (signal_pending(current)) {
1144 ath6kl_err("target did not respond\n");
1145 return -EINTR;
1146 }
1147 }
1148
1149 *dbm = ar->tx_pwr;
1150 return 0;
1151}
1152
1153static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1154 struct net_device *dev,
1155 bool pmgmt, int timeout)
1156{
1157 struct ath6kl *ar = ath6kl_priv(dev);
1158 struct wmi_power_mode_cmd mode;
1159
1160 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1161 __func__, pmgmt, timeout);
1162
1163 if (!ath6kl_cfg80211_ready(ar))
1164 return -EIO;
1165
1166 if (pmgmt) {
1167 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1168 mode.pwr_mode = REC_POWER;
1169 } else {
1170 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1171 mode.pwr_mode = MAX_PERF_POWER;
1172 }
1173
1174 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1175 ath6kl_err("wmi_powermode_cmd failed\n");
1176 return -EIO;
1177 }
1178
1179 return 0;
1180}
1181
1182static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1183 struct net_device *ndev,
1184 enum nl80211_iftype type, u32 *flags,
1185 struct vif_params *params)
1186{
1187 struct ath6kl *ar = ath6kl_priv(ndev);
1188 struct wireless_dev *wdev = ar->wdev;
1189
1190 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1191
1192 if (!ath6kl_cfg80211_ready(ar))
1193 return -EIO;
1194
1195 switch (type) {
1196 case NL80211_IFTYPE_STATION:
1197 ar->next_mode = INFRA_NETWORK;
1198 break;
1199 case NL80211_IFTYPE_ADHOC:
1200 ar->next_mode = ADHOC_NETWORK;
1201 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001202 case NL80211_IFTYPE_AP:
1203 ar->next_mode = AP_NETWORK;
1204 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001205 case NL80211_IFTYPE_P2P_CLIENT:
1206 ar->next_mode = INFRA_NETWORK;
1207 break;
1208 case NL80211_IFTYPE_P2P_GO:
1209 ar->next_mode = AP_NETWORK;
1210 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001211 default:
1212 ath6kl_err("invalid interface type %u\n", type);
1213 return -EOPNOTSUPP;
1214 }
1215
1216 wdev->iftype = type;
1217
1218 return 0;
1219}
1220
1221static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1222 struct net_device *dev,
1223 struct cfg80211_ibss_params *ibss_param)
1224{
1225 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301226 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001227 int status;
1228
1229 if (!ath6kl_cfg80211_ready(ar))
1230 return -EIO;
1231
1232 ar->ssid_len = ibss_param->ssid_len;
1233 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1234
1235 if (ibss_param->channel)
1236 ar->ch_hint = ibss_param->channel->center_freq;
1237
1238 if (ibss_param->channel_fixed) {
1239 /*
1240 * TODO: channel_fixed: The channel should be fixed, do not
1241 * search for IBSSs to join on other channels. Target
1242 * firmware does not support this feature, needs to be
1243 * updated.
1244 */
1245 return -EOPNOTSUPP;
1246 }
1247
1248 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1249 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1250 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1251
1252 ath6kl_set_wpa_version(ar, 0);
1253
1254 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1255 if (status)
1256 return status;
1257
1258 if (ibss_param->privacy) {
1259 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1260 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1261 } else {
1262 ath6kl_set_cipher(ar, 0, true);
1263 ath6kl_set_cipher(ar, 0, false);
1264 }
1265
1266 ar->nw_type = ar->next_mode;
1267
1268 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1269 "%s: connect called with authmode %d dot11 auth %d"
1270 " PW crypto %d PW crypto len %d GRP crypto %d"
1271 " GRP crypto len %d channel hint %u\n",
1272 __func__,
1273 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1274 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001275 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001276
1277 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1278 ar->dot11_auth_mode, ar->auth_mode,
1279 ar->prwise_crypto,
1280 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001281 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001282 ar->ssid_len, ar->ssid,
1283 ar->req_bssid, ar->ch_hint,
1284 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301285 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001286
1287 return 0;
1288}
1289
1290static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1291 struct net_device *dev)
1292{
1293 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1294
1295 if (!ath6kl_cfg80211_ready(ar))
1296 return -EIO;
1297
1298 ath6kl_disconnect(ar);
1299 memset(ar->ssid, 0, sizeof(ar->ssid));
1300 ar->ssid_len = 0;
1301
1302 return 0;
1303}
1304
1305static const u32 cipher_suites[] = {
1306 WLAN_CIPHER_SUITE_WEP40,
1307 WLAN_CIPHER_SUITE_WEP104,
1308 WLAN_CIPHER_SUITE_TKIP,
1309 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001310 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001311};
1312
1313static bool is_rate_legacy(s32 rate)
1314{
1315 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1316 6000, 9000, 12000, 18000, 24000,
1317 36000, 48000, 54000
1318 };
1319 u8 i;
1320
1321 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1322 if (rate == legacy[i])
1323 return true;
1324
1325 return false;
1326}
1327
1328static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1329{
1330 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1331 52000, 58500, 65000, 72200
1332 };
1333 u8 i;
1334
1335 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1336 if (rate == ht20[i]) {
1337 if (i == ARRAY_SIZE(ht20) - 1)
1338 /* last rate uses sgi */
1339 *sgi = true;
1340 else
1341 *sgi = false;
1342
1343 *mcs = i;
1344 return true;
1345 }
1346 }
1347 return false;
1348}
1349
1350static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1351{
1352 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1353 81000, 108000, 121500, 135000,
1354 150000
1355 };
1356 u8 i;
1357
1358 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1359 if (rate == ht40[i]) {
1360 if (i == ARRAY_SIZE(ht40) - 1)
1361 /* last rate uses sgi */
1362 *sgi = true;
1363 else
1364 *sgi = false;
1365
1366 *mcs = i;
1367 return true;
1368 }
1369 }
1370
1371 return false;
1372}
1373
1374static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1375 u8 *mac, struct station_info *sinfo)
1376{
1377 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301378 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001379 long left;
1380 bool sgi;
1381 s32 rate;
1382 int ret;
1383 u8 mcs;
1384
1385 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1386 return -ENOENT;
1387
1388 if (down_interruptible(&ar->sem))
1389 return -EBUSY;
1390
1391 set_bit(STATS_UPDATE_PEND, &ar->flag);
1392
1393 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1394
1395 if (ret != 0) {
1396 up(&ar->sem);
1397 return -EIO;
1398 }
1399
1400 left = wait_event_interruptible_timeout(ar->event_wq,
1401 !test_bit(STATS_UPDATE_PEND,
1402 &ar->flag),
1403 WMI_TIMEOUT);
1404
1405 up(&ar->sem);
1406
1407 if (left == 0)
1408 return -ETIMEDOUT;
1409 else if (left < 0)
1410 return left;
1411
1412 if (ar->target_stats.rx_byte) {
1413 sinfo->rx_bytes = ar->target_stats.rx_byte;
1414 sinfo->filled |= STATION_INFO_RX_BYTES;
1415 sinfo->rx_packets = ar->target_stats.rx_pkt;
1416 sinfo->filled |= STATION_INFO_RX_PACKETS;
1417 }
1418
1419 if (ar->target_stats.tx_byte) {
1420 sinfo->tx_bytes = ar->target_stats.tx_byte;
1421 sinfo->filled |= STATION_INFO_TX_BYTES;
1422 sinfo->tx_packets = ar->target_stats.tx_pkt;
1423 sinfo->filled |= STATION_INFO_TX_PACKETS;
1424 }
1425
1426 sinfo->signal = ar->target_stats.cs_rssi;
1427 sinfo->filled |= STATION_INFO_SIGNAL;
1428
1429 rate = ar->target_stats.tx_ucast_rate;
1430
1431 if (is_rate_legacy(rate)) {
1432 sinfo->txrate.legacy = rate / 100;
1433 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1434 if (sgi) {
1435 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1436 sinfo->txrate.mcs = mcs - 1;
1437 } else {
1438 sinfo->txrate.mcs = mcs;
1439 }
1440
1441 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1442 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1443 if (sgi) {
1444 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1445 sinfo->txrate.mcs = mcs - 1;
1446 } else {
1447 sinfo->txrate.mcs = mcs;
1448 }
1449
1450 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1451 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1452 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001453 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1454 "invalid rate from stats: %d\n", rate);
1455 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001456 return 0;
1457 }
1458
1459 sinfo->filled |= STATION_INFO_TX_BITRATE;
1460
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301461 if (test_bit(CONNECTED, &vif->flags) &&
1462 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Jouni Malinen32c10872011-09-19 19:15:07 +03001463 ar->nw_type == INFRA_NETWORK) {
1464 sinfo->filled |= STATION_INFO_BSS_PARAM;
1465 sinfo->bss_param.flags = 0;
1466 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1467 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1468 }
1469
Kalle Valobdcd8172011-07-18 00:22:30 +03001470 return 0;
1471}
1472
1473static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1474 struct cfg80211_pmksa *pmksa)
1475{
1476 struct ath6kl *ar = ath6kl_priv(netdev);
1477 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1478 pmksa->pmkid, true);
1479}
1480
1481static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1482 struct cfg80211_pmksa *pmksa)
1483{
1484 struct ath6kl *ar = ath6kl_priv(netdev);
1485 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1486 pmksa->pmkid, false);
1487}
1488
1489static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1490{
1491 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301492 struct ath6kl_vif *vif = netdev_priv(netdev);
1493
1494 if (test_bit(CONNECTED, &vif->flags))
Kalle Valobdcd8172011-07-18 00:22:30 +03001495 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1496 return 0;
1497}
1498
Kalle Valoabcb3442011-07-22 08:26:20 +03001499#ifdef CONFIG_PM
1500static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1501 struct cfg80211_wowlan *wow)
1502{
1503 struct ath6kl *ar = wiphy_priv(wiphy);
1504
1505 return ath6kl_hif_suspend(ar);
1506}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001507
1508static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1509{
1510 struct ath6kl *ar = wiphy_priv(wiphy);
1511
1512 return ath6kl_hif_resume(ar);
1513}
Kalle Valoabcb3442011-07-22 08:26:20 +03001514#endif
1515
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001516static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1517 struct ieee80211_channel *chan,
1518 enum nl80211_channel_type channel_type)
1519{
1520 struct ath6kl *ar = ath6kl_priv(dev);
1521
1522 if (!ath6kl_cfg80211_ready(ar))
1523 return -EIO;
1524
1525 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1526 __func__, chan->center_freq, chan->hw_value);
1527 ar->next_chan = chan->center_freq;
1528
1529 return 0;
1530}
1531
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001532static bool ath6kl_is_p2p_ie(const u8 *pos)
1533{
1534 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1535 pos[2] == 0x50 && pos[3] == 0x6f &&
1536 pos[4] == 0x9a && pos[5] == 0x09;
1537}
1538
1539static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1540 size_t ies_len)
1541{
1542 const u8 *pos;
1543 u8 *buf = NULL;
1544 size_t len = 0;
1545 int ret;
1546
1547 /*
1548 * Filter out P2P IE(s) since they will be included depending on
1549 * the Probe Request frame in ath6kl_send_go_probe_resp().
1550 */
1551
1552 if (ies && ies_len) {
1553 buf = kmalloc(ies_len, GFP_KERNEL);
1554 if (buf == NULL)
1555 return -ENOMEM;
1556 pos = ies;
1557 while (pos + 1 < ies + ies_len) {
1558 if (pos + 2 + pos[1] > ies + ies_len)
1559 break;
1560 if (!ath6kl_is_p2p_ie(pos)) {
1561 memcpy(buf + len, pos, 2 + pos[1]);
1562 len += 2 + pos[1];
1563 }
1564 pos += 2 + pos[1];
1565 }
1566 }
1567
1568 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1569 buf, len);
1570 kfree(buf);
1571 return ret;
1572}
1573
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001574static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1575 struct beacon_parameters *info, bool add)
1576{
1577 struct ath6kl *ar = ath6kl_priv(dev);
1578 struct ieee80211_mgmt *mgmt;
1579 u8 *ies;
1580 int ies_len;
1581 struct wmi_connect_cmd p;
1582 int res;
1583 int i;
1584
1585 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1586
1587 if (!ath6kl_cfg80211_ready(ar))
1588 return -EIO;
1589
1590 if (ar->next_mode != AP_NETWORK)
1591 return -EOPNOTSUPP;
1592
1593 if (info->beacon_ies) {
1594 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1595 info->beacon_ies,
1596 info->beacon_ies_len);
1597 if (res)
1598 return res;
1599 }
1600 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001601 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1602 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001603 if (res)
1604 return res;
1605 }
1606 if (info->assocresp_ies) {
1607 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1608 info->assocresp_ies,
1609 info->assocresp_ies_len);
1610 if (res)
1611 return res;
1612 }
1613
1614 if (!add)
1615 return 0;
1616
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001617 ar->ap_mode_bkey.valid = false;
1618
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001619 /* TODO:
1620 * info->interval
1621 * info->dtim_period
1622 */
1623
1624 if (info->head == NULL)
1625 return -EINVAL;
1626 mgmt = (struct ieee80211_mgmt *) info->head;
1627 ies = mgmt->u.beacon.variable;
1628 if (ies > info->head + info->head_len)
1629 return -EINVAL;
1630 ies_len = info->head + info->head_len - ies;
1631
1632 if (info->ssid == NULL)
1633 return -EINVAL;
1634 memcpy(ar->ssid, info->ssid, info->ssid_len);
1635 ar->ssid_len = info->ssid_len;
1636 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1637 return -EOPNOTSUPP; /* TODO */
1638
1639 ar->dot11_auth_mode = OPEN_AUTH;
1640
1641 memset(&p, 0, sizeof(p));
1642
1643 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1644 switch (info->crypto.akm_suites[i]) {
1645 case WLAN_AKM_SUITE_8021X:
1646 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1647 p.auth_mode |= WPA_AUTH;
1648 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1649 p.auth_mode |= WPA2_AUTH;
1650 break;
1651 case WLAN_AKM_SUITE_PSK:
1652 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1653 p.auth_mode |= WPA_PSK_AUTH;
1654 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1655 p.auth_mode |= WPA2_PSK_AUTH;
1656 break;
1657 }
1658 }
1659 if (p.auth_mode == 0)
1660 p.auth_mode = NONE_AUTH;
1661 ar->auth_mode = p.auth_mode;
1662
1663 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1664 switch (info->crypto.ciphers_pairwise[i]) {
1665 case WLAN_CIPHER_SUITE_WEP40:
1666 case WLAN_CIPHER_SUITE_WEP104:
1667 p.prwise_crypto_type |= WEP_CRYPT;
1668 break;
1669 case WLAN_CIPHER_SUITE_TKIP:
1670 p.prwise_crypto_type |= TKIP_CRYPT;
1671 break;
1672 case WLAN_CIPHER_SUITE_CCMP:
1673 p.prwise_crypto_type |= AES_CRYPT;
1674 break;
1675 }
1676 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001677 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001678 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001679 ath6kl_set_cipher(ar, 0, true);
1680 } else if (info->crypto.n_ciphers_pairwise == 1)
1681 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001682
1683 switch (info->crypto.cipher_group) {
1684 case WLAN_CIPHER_SUITE_WEP40:
1685 case WLAN_CIPHER_SUITE_WEP104:
1686 p.grp_crypto_type = WEP_CRYPT;
1687 break;
1688 case WLAN_CIPHER_SUITE_TKIP:
1689 p.grp_crypto_type = TKIP_CRYPT;
1690 break;
1691 case WLAN_CIPHER_SUITE_CCMP:
1692 p.grp_crypto_type = AES_CRYPT;
1693 break;
1694 default:
1695 p.grp_crypto_type = NONE_CRYPT;
1696 break;
1697 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001698 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001699
1700 p.nw_type = AP_NETWORK;
1701 ar->nw_type = ar->next_mode;
1702
1703 p.ssid_len = ar->ssid_len;
1704 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1705 p.dot11_auth_mode = ar->dot11_auth_mode;
1706 p.ch = cpu_to_le16(ar->next_chan);
1707
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001708 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1709 if (res < 0)
1710 return res;
1711
1712 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001713}
1714
1715static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1716 struct beacon_parameters *info)
1717{
1718 return ath6kl_ap_beacon(wiphy, dev, info, true);
1719}
1720
1721static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1722 struct beacon_parameters *info)
1723{
1724 return ath6kl_ap_beacon(wiphy, dev, info, false);
1725}
1726
1727static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1728{
1729 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301730 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001731
1732 if (ar->nw_type != AP_NETWORK)
1733 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301734 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001735 return -ENOTCONN;
1736
1737 ath6kl_wmi_disconnect_cmd(ar->wmi);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301738 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001739
1740 return 0;
1741}
1742
Jouni Malinen23875132011-08-30 21:57:53 +03001743static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1744 u8 *mac, struct station_parameters *params)
1745{
1746 struct ath6kl *ar = ath6kl_priv(dev);
1747
1748 if (ar->nw_type != AP_NETWORK)
1749 return -EOPNOTSUPP;
1750
1751 /* Use this only for authorizing/unauthorizing a station */
1752 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1753 return -EOPNOTSUPP;
1754
1755 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1756 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1757 mac, 0);
1758 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1759 0);
1760}
1761
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001762static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1763 struct net_device *dev,
1764 struct ieee80211_channel *chan,
1765 enum nl80211_channel_type channel_type,
1766 unsigned int duration,
1767 u64 *cookie)
1768{
1769 struct ath6kl *ar = ath6kl_priv(dev);
1770
1771 /* TODO: if already pending or ongoing remain-on-channel,
1772 * return -EBUSY */
1773 *cookie = 1; /* only a single pending request is supported */
1774
1775 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1776 duration);
1777}
1778
1779static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1780 struct net_device *dev,
1781 u64 cookie)
1782{
1783 struct ath6kl *ar = ath6kl_priv(dev);
1784
1785 if (cookie != 1)
1786 return -ENOENT;
1787
1788 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1789}
1790
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001791static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1792 size_t len, unsigned int freq)
1793{
1794 const u8 *pos;
1795 u8 *p2p;
1796 int p2p_len;
1797 int ret;
1798 const struct ieee80211_mgmt *mgmt;
1799
1800 mgmt = (const struct ieee80211_mgmt *) buf;
1801
1802 /* Include P2P IE(s) from the frame generated in user space. */
1803
1804 p2p = kmalloc(len, GFP_KERNEL);
1805 if (p2p == NULL)
1806 return -ENOMEM;
1807 p2p_len = 0;
1808
1809 pos = mgmt->u.probe_resp.variable;
1810 while (pos + 1 < buf + len) {
1811 if (pos + 2 + pos[1] > buf + len)
1812 break;
1813 if (ath6kl_is_p2p_ie(pos)) {
1814 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1815 p2p_len += 2 + pos[1];
1816 }
1817 pos += 2 + pos[1];
1818 }
1819
1820 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1821 p2p, p2p_len);
1822 kfree(p2p);
1823 return ret;
1824}
1825
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001826static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1827 struct ieee80211_channel *chan, bool offchan,
1828 enum nl80211_channel_type channel_type,
1829 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001830 const u8 *buf, size_t len, bool no_cck,
1831 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001832{
1833 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301834 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001835 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001836 const struct ieee80211_mgmt *mgmt;
1837
1838 mgmt = (const struct ieee80211_mgmt *) buf;
1839 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301840 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001841 ieee80211_is_probe_resp(mgmt->frame_control)) {
1842 /*
1843 * Send Probe Response frame in AP mode using a separate WMI
1844 * command to allow the target to fill in the generic IEs.
1845 */
1846 *cookie = 0; /* TX status not supported */
1847 return ath6kl_send_go_probe_resp(ar, buf, len,
1848 chan->center_freq);
1849 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001850
1851 id = ar->send_action_id++;
1852 if (id == 0) {
1853 /*
1854 * 0 is a reserved value in the WMI command and shall not be
1855 * used for the command.
1856 */
1857 id = ar->send_action_id++;
1858 }
1859
1860 *cookie = id;
1861 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1862 buf, len);
1863}
1864
Jouni Malinenae32c302011-08-30 21:58:01 +03001865static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1866 struct net_device *dev,
1867 u16 frame_type, bool reg)
1868{
1869 struct ath6kl *ar = ath6kl_priv(dev);
1870
1871 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1872 __func__, frame_type, reg);
1873 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1874 /*
1875 * Note: This notification callback is not allowed to sleep, so
1876 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1877 * hardcode target to report Probe Request frames all the time.
1878 */
1879 ar->probe_req_report = reg;
1880 }
1881}
1882
Jouni Malinenf80574a2011-08-30 21:58:04 +03001883static const struct ieee80211_txrx_stypes
1884ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1885 [NL80211_IFTYPE_STATION] = {
1886 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1887 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1888 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1889 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1890 },
1891 [NL80211_IFTYPE_P2P_CLIENT] = {
1892 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1893 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1894 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1895 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1896 },
1897 [NL80211_IFTYPE_P2P_GO] = {
1898 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1899 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1900 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1901 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1902 },
1903};
1904
Kalle Valobdcd8172011-07-18 00:22:30 +03001905static struct cfg80211_ops ath6kl_cfg80211_ops = {
1906 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1907 .scan = ath6kl_cfg80211_scan,
1908 .connect = ath6kl_cfg80211_connect,
1909 .disconnect = ath6kl_cfg80211_disconnect,
1910 .add_key = ath6kl_cfg80211_add_key,
1911 .get_key = ath6kl_cfg80211_get_key,
1912 .del_key = ath6kl_cfg80211_del_key,
1913 .set_default_key = ath6kl_cfg80211_set_default_key,
1914 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1915 .set_tx_power = ath6kl_cfg80211_set_txpower,
1916 .get_tx_power = ath6kl_cfg80211_get_txpower,
1917 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1918 .join_ibss = ath6kl_cfg80211_join_ibss,
1919 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1920 .get_station = ath6kl_get_station,
1921 .set_pmksa = ath6kl_set_pmksa,
1922 .del_pmksa = ath6kl_del_pmksa,
1923 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001924 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001925#ifdef CONFIG_PM
1926 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001927 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001928#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001929 .set_channel = ath6kl_set_channel,
1930 .add_beacon = ath6kl_add_beacon,
1931 .set_beacon = ath6kl_set_beacon,
1932 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001933 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001934 .remain_on_channel = ath6kl_remain_on_channel,
1935 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001936 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001937 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001938};
1939
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301940struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001941{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001942 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301943 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301944 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001945
1946 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301947 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301948
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301949 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001950 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001951 return NULL;
1952 }
1953
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301954 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001955 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301956 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301957 ar->dev = dev;
1958
1959 spin_lock_init(&ar->lock);
1960 spin_lock_init(&ar->mcastpsq_lock);
1961
1962 init_waitqueue_head(&ar->event_wq);
1963 sema_init(&ar->sem, 1);
1964
1965 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1966
1967 clear_bit(WMI_ENABLED, &ar->flag);
1968 clear_bit(SKIP_SCAN, &ar->flag);
1969 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
1970
1971 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
1972 ar->listen_intvl_b = 0;
1973 ar->tx_pwr = 0;
1974
1975 ar->intra_bss = 1;
1976 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
1977 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
1978 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
1979 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
1980
1981 memset((u8 *)ar->sta_list, 0,
1982 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
1983
1984 /* Init the PS queues */
1985 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
1986 spin_lock_init(&ar->sta_list[ctr].psq_lock);
1987 skb_queue_head_init(&ar->sta_list[ctr].psq);
1988 }
1989
1990 skb_queue_head_init(&ar->mcastpsq);
1991
1992 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
1993
1994 return ar;
1995}
1996
1997int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
1998{
1999 struct wiphy *wiphy = ar->wiphy;
2000 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002001
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302002 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002003
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302004 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002005
Kalle Valobdcd8172011-07-18 00:22:30 +03002006 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302007 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002008
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302009 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302010 BIT(NL80211_IFTYPE_ADHOC) |
2011 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002012 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302013 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302014 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002015 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302016
Kalle Valobdcd8172011-07-18 00:22:30 +03002017 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302018 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2019 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2020 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2021 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2022 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002023
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302024 wiphy->cipher_suites = cipher_suites;
2025 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002026
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302027 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002028 if (ret < 0) {
2029 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302030 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002031 }
2032
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302033 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002034}
2035
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302036static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002037{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302038 struct ath6kl *ar = vif->ar;
2039
2040 ar->aggr_cntxt = aggr_init(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302041 if (!ar->aggr_cntxt) {
2042 ath6kl_err("failed to initialize aggr\n");
2043 return -ENOMEM;
2044 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002045
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302046 setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302047 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302048
2049 return 0;
2050}
2051
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302052void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302053{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302054 struct ath6kl *ar = vif->ar;
2055
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302056 aggr_module_destroy(ar->aggr_cntxt);
2057
2058 ar->aggr_cntxt = NULL;
2059
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302060 if (test_bit(NETDEV_REGISTERED, &vif->flags)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302061 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302062 clear_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302063 }
2064
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302065 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302066}
2067
2068struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
2069 enum nl80211_iftype type)
2070{
2071 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302072 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302073
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302074 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302075 if (!ndev)
2076 return NULL;
2077
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302078 vif = netdev_priv(ndev);
2079 ndev->ieee80211_ptr = &vif->wdev;
2080 vif->wdev.wiphy = ar->wiphy;
2081 vif->ar = ar;
2082 ar->vif = vif;
2083 vif->ndev = ndev;
2084 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2085 vif->wdev.netdev = ndev;
2086 vif->wdev.iftype = type;
2087 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302088 ar->net_dev = ndev;
2089
2090 init_netdev(ndev);
2091
2092 ath6kl_init_control_info(ar);
2093
2094 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302095 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302096 goto err;
2097
2098 if (register_netdev(ndev))
2099 goto err;
2100
2101 ar->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302102 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302103 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302104 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302105
2106 return ndev;
2107
2108err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302109 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302110
2111 return NULL;
2112}
2113
2114void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2115{
Kalle Valobdcd8172011-07-18 00:22:30 +03002116 if (ar->scan_req) {
2117 cfg80211_scan_done(ar->scan_req, true);
2118 ar->scan_req = NULL;
2119 }
2120
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302121 wiphy_unregister(ar->wiphy);
2122 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002123}