blob: 33da58c13efc3d40bd62ddb809041784486f4544 [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{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530129 /* TODO: Findout vif */
130 struct ath6kl_vif *vif = ar->vif;
131
Kalle Valobdcd8172011-07-18 00:22:30 +0300132 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
133
134 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530135 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300136 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530137 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300138 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530139 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300140 } else {
141 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
142 return -ENOTSUPP;
143 }
144
145 return 0;
146}
147
148static int ath6kl_set_auth_type(struct ath6kl *ar,
149 enum nl80211_auth_type auth_type)
150{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530151 /* TODO: Findout vif */
152 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +0300153
154 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
155
156 switch (auth_type) {
157 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530158 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300159 break;
160 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530161 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300162 break;
163 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530164 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 break;
166
167 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530168 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300169 break;
170
171 default:
172 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
173 return -ENOTSUPP;
174 }
175
176 return 0;
177}
178
179static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
180{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530181 /* TODO: Findout vif */
182 struct ath6kl_vif *vif = ar->vif;
183
184 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
185 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
186 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300187
188 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
189 __func__, cipher, ucast);
190
191 switch (cipher) {
192 case 0:
193 /* our own hack to use value 0 as no crypto used */
194 *ar_cipher = NONE_CRYPT;
195 *ar_cipher_len = 0;
196 break;
197 case WLAN_CIPHER_SUITE_WEP40:
198 *ar_cipher = WEP_CRYPT;
199 *ar_cipher_len = 5;
200 break;
201 case WLAN_CIPHER_SUITE_WEP104:
202 *ar_cipher = WEP_CRYPT;
203 *ar_cipher_len = 13;
204 break;
205 case WLAN_CIPHER_SUITE_TKIP:
206 *ar_cipher = TKIP_CRYPT;
207 *ar_cipher_len = 0;
208 break;
209 case WLAN_CIPHER_SUITE_CCMP:
210 *ar_cipher = AES_CRYPT;
211 *ar_cipher_len = 0;
212 break;
213 default:
214 ath6kl_err("cipher 0x%x not supported\n", cipher);
215 return -ENOTSUPP;
216 }
217
218 return 0;
219}
220
221static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
222{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530223 /* TODO: Findout vif */
224 struct ath6kl_vif *vif = ar->vif;
225
Kalle Valobdcd8172011-07-18 00:22:30 +0300226 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
227
228 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530229 if (vif->auth_mode == WPA_AUTH)
230 vif->auth_mode = WPA_PSK_AUTH;
231 else if (vif->auth_mode == WPA2_AUTH)
232 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300233 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530234 if (vif->auth_mode == WPA_AUTH)
235 vif->auth_mode = WPA_AUTH_CCKM;
236 else if (vif->auth_mode == WPA2_AUTH)
237 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300238 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530239 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300240 }
241}
242
243static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
244{
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530245 struct ath6kl_vif *vif = ar->vif;
246
Kalle Valobdcd8172011-07-18 00:22:30 +0300247 if (!test_bit(WMI_READY, &ar->flag)) {
248 ath6kl_err("wmi is not ready\n");
249 return false;
250 }
251
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530252 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300253 ath6kl_err("wlan disabled\n");
254 return false;
255 }
256
257 return true;
258}
259
Kevin Fang6981ffd2011-10-07 08:51:19 +0800260static bool ath6kl_is_wpa_ie(const u8 *pos)
261{
262 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
263 pos[2] == 0x00 && pos[3] == 0x50 &&
264 pos[4] == 0xf2 && pos[5] == 0x01;
265}
266
267static bool ath6kl_is_rsn_ie(const u8 *pos)
268{
269 return pos[0] == WLAN_EID_RSN;
270}
271
272static int ath6kl_set_assoc_req_ies(struct ath6kl *ar, const u8 *ies,
273 size_t ies_len)
274{
275 const u8 *pos;
276 u8 *buf = NULL;
277 size_t len = 0;
278 int ret;
279
280 /*
281 * Filter out RSN/WPA IE(s)
282 */
283
284 if (ies && ies_len) {
285 buf = kmalloc(ies_len, GFP_KERNEL);
286 if (buf == NULL)
287 return -ENOMEM;
288 pos = ies;
289
290 while (pos + 1 < ies + ies_len) {
291 if (pos + 2 + pos[1] > ies + ies_len)
292 break;
293 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
294 memcpy(buf + len, pos, 2 + pos[1]);
295 len += 2 + pos[1];
296 }
297 pos += 2 + pos[1];
298 }
299 }
300
301 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_REQ,
302 buf, len);
303 kfree(buf);
304 return ret;
305}
306
Kalle Valobdcd8172011-07-18 00:22:30 +0300307static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
308 struct cfg80211_connect_params *sme)
309{
310 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530311 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300312 int status;
313
314 ar->sme_state = SME_CONNECTING;
315
316 if (!ath6kl_cfg80211_ready(ar))
317 return -EIO;
318
319 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
320 ath6kl_err("destroy in progress\n");
321 return -EBUSY;
322 }
323
324 if (test_bit(SKIP_SCAN, &ar->flag) &&
325 ((sme->channel && sme->channel->center_freq == 0) ||
326 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
327 ath6kl_err("SkipScan: channel or bssid invalid\n");
328 return -EINVAL;
329 }
330
331 if (down_interruptible(&ar->sem)) {
332 ath6kl_err("busy, couldn't get access\n");
333 return -ERESTARTSYS;
334 }
335
336 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
337 ath6kl_err("busy, destroy in progress\n");
338 up(&ar->sem);
339 return -EBUSY;
340 }
341
342 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
343 /*
344 * sleep until the command queue drains
345 */
346 wait_event_interruptible_timeout(ar->event_wq,
347 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
348 WMI_TIMEOUT);
349 if (signal_pending(current)) {
350 ath6kl_err("cmd queue drain timeout\n");
351 up(&ar->sem);
352 return -EINTR;
353 }
354 }
355
Kevin Fang6981ffd2011-10-07 08:51:19 +0800356 if (sme->ie && (sme->ie_len > 0)) {
357 status = ath6kl_set_assoc_req_ies(ar, sme->ie, sme->ie_len);
358 if (status)
359 return status;
360 }
361
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530362 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530363 vif->ssid_len == sme->ssid_len &&
364 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300365 ar->reconnect_flag = true;
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530366 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530367 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300368
369 up(&ar->sem);
370 if (status) {
371 ath6kl_err("wmi_reconnect_cmd failed\n");
372 return -EIO;
373 }
374 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530375 } else if (vif->ssid_len == sme->ssid_len &&
376 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300377 ath6kl_disconnect(ar);
378 }
379
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530380 memset(vif->ssid, 0, sizeof(vif->ssid));
381 vif->ssid_len = sme->ssid_len;
382 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300383
384 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530385 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300386
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530387 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300388 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530389 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300390
391 ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
392
393 status = ath6kl_set_auth_type(ar, sme->auth_type);
394 if (status) {
395 up(&ar->sem);
396 return status;
397 }
398
399 if (sme->crypto.n_ciphers_pairwise)
400 ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
401 else
402 ath6kl_set_cipher(ar, 0, true);
403
404 ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
405
406 if (sme->crypto.n_akm_suites)
407 ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
408
409 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530410 (vif->auth_mode == NONE_AUTH) &&
411 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300412 struct ath6kl_key *key = NULL;
413
414 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
415 sme->key_idx > WMI_MAX_KEY_INDEX) {
416 ath6kl_err("key index %d out of bounds\n",
417 sme->key_idx);
418 up(&ar->sem);
419 return -ENOENT;
420 }
421
422 key = &ar->keys[sme->key_idx];
423 key->key_len = sme->key_len;
424 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530425 key->cipher = vif->prwise_crypto;
426 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300427
428 ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530429 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300430 GROUP_USAGE | TX_USAGE,
431 key->key_len,
432 NULL,
433 key->key, KEY_OP_INIT_VAL, NULL,
434 NO_SYNC_WMIFLAG);
435 }
436
437 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530438 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300439 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
440 ath6kl_err("couldn't set bss filtering\n");
441 up(&ar->sem);
442 return -EIO;
443 }
444 }
445
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530446 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300447
448 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
449 "%s: connect called with authmode %d dot11 auth %d"
450 " PW crypto %d PW crypto len %d GRP crypto %d"
451 " GRP crypto len %d channel hint %u\n",
452 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530453 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
454 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530455 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300456
457 ar->reconnect_flag = 0;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530458 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530459 vif->dot11_auth_mode, vif->auth_mode,
460 vif->prwise_crypto,
461 vif->prwise_crypto_len,
462 vif->grp_crypto, vif->grp_crypto_len,
463 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530464 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 ar->connect_ctrl_flags);
466
467 up(&ar->sem);
468
469 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530470 memset(vif->ssid, 0, sizeof(vif->ssid));
471 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300472 ath6kl_err("invalid request\n");
473 return -ENOENT;
474 } else if (status) {
475 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
476 return -EIO;
477 }
478
479 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530480 ((vif->auth_mode == WPA_PSK_AUTH)
481 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300482 mod_timer(&ar->disconnect_timer,
483 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
484 }
485
486 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530487 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300488
489 return 0;
490}
491
Jouni Malinen01cac472011-09-19 19:14:59 +0300492static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
493 struct ieee80211_channel *chan,
494 const u8 *beacon_ie, size_t beacon_ie_len)
495{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530496 /* TODO: Findout vif */
497 struct ath6kl_vif *vif = ar->vif;
Jouni Malinen01cac472011-09-19 19:14:59 +0300498 struct cfg80211_bss *bss;
499 u8 *ie;
500
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530501 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530502 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300503 WLAN_CAPABILITY_ESS);
504 if (bss == NULL) {
505 /*
506 * Since cfg80211 may not yet know about the BSS,
507 * generate a partial entry until the first BSS info
508 * event becomes available.
509 *
510 * Prepend SSID element since it is not included in the Beacon
511 * IEs from the target.
512 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530513 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300514 if (ie == NULL)
515 return -ENOMEM;
516 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530517 ie[1] = vif->ssid_len;
518 memcpy(ie + 2, vif->ssid, vif->ssid_len);
519 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530520 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300521 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530522 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300523 0, GFP_KERNEL);
524 if (bss)
525 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
526 "%pM prior to indicating connect/roamed "
527 "event\n", bssid);
528 kfree(ie);
529 } else
530 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
531 "entry\n");
532
533 if (bss == NULL)
534 return -ENOMEM;
535
536 cfg80211_put_bss(bss);
537
538 return 0;
539}
540
Kalle Valobdcd8172011-07-18 00:22:30 +0300541void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
542 u8 *bssid, u16 listen_intvl,
543 u16 beacon_intvl,
544 enum network_type nw_type,
545 u8 beacon_ie_len, u8 assoc_req_len,
546 u8 assoc_resp_len, u8 *assoc_info)
547{
Jouni Malinen01cac472011-09-19 19:14:59 +0300548 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530549 /* TODO: Findout vif */
550 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +0300551
552 /* capinfo + listen interval */
553 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
554
555 /* capinfo + status code + associd */
556 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
557
558 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
559 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
560 assoc_resp_ie_offset;
561
562 assoc_req_len -= assoc_req_ie_offset;
563 assoc_resp_len -= assoc_resp_ie_offset;
564
Jouni Malinen32c10872011-09-19 19:15:07 +0300565 /*
566 * Store Beacon interval here; DTIM period will be available only once
567 * a Beacon frame from the AP is seen.
568 */
569 ar->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530570 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300571
Kalle Valobdcd8172011-07-18 00:22:30 +0300572 if (nw_type & ADHOC_NETWORK) {
573 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
574 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
575 "%s: ath6k not in ibss mode\n", __func__);
576 return;
577 }
578 }
579
580 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300581 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
582 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300583 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
584 "%s: ath6k not in station mode\n", __func__);
585 return;
586 }
587 }
588
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530589 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300590
Kalle Valobdcd8172011-07-18 00:22:30 +0300591
592 if (nw_type & ADHOC_NETWORK) {
593 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
594 return;
595 }
596
Jouni Malinen01cac472011-09-19 19:14:59 +0300597 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
598 beacon_ie_len) < 0) {
599 ath6kl_err("could not add cfg80211 bss entry for "
600 "connect/roamed notification\n");
601 return;
602 }
603
Raja Mani9aa60352011-08-04 19:26:29 +0530604 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300605 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530606 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300607 cfg80211_connect_result(ar->net_dev, bssid,
608 assoc_req_ie, assoc_req_len,
609 assoc_resp_ie, assoc_resp_len,
610 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530611 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300612 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300613 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300614 assoc_req_ie, assoc_req_len,
615 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
616 }
617}
618
619static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
620 struct net_device *dev, u16 reason_code)
621{
622 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530623 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300624
625 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
626 reason_code);
627
628 if (!ath6kl_cfg80211_ready(ar))
629 return -EIO;
630
631 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
632 ath6kl_err("busy, destroy in progress\n");
633 return -EBUSY;
634 }
635
636 if (down_interruptible(&ar->sem)) {
637 ath6kl_err("busy, couldn't get access\n");
638 return -ERESTARTSYS;
639 }
640
641 ar->reconnect_flag = 0;
642 ath6kl_disconnect(ar);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530643 memset(vif->ssid, 0, sizeof(vif->ssid));
644 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300645
646 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530647 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300648
649 up(&ar->sem);
650
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530651 ar->sme_state = SME_DISCONNECTED;
652
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 return 0;
654}
655
656void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
657 u8 *bssid, u8 assoc_resp_len,
658 u8 *assoc_info, u16 proto_reason)
659{
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530660 /* TODO: Findout vif */
661 struct ath6kl_vif *vif = ar->vif;
662
Kalle Valobdcd8172011-07-18 00:22:30 +0300663 if (ar->scan_req) {
664 cfg80211_scan_done(ar->scan_req, true);
665 ar->scan_req = NULL;
666 }
667
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530668 if (vif->nw_type & ADHOC_NETWORK) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300669 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
670 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
671 "%s: ath6k not in ibss mode\n", __func__);
672 return;
673 }
674 memset(bssid, 0, ETH_ALEN);
675 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
676 return;
677 }
678
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530679 if (vif->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300680 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
681 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
683 "%s: ath6k not in station mode\n", __func__);
684 return;
685 }
686 }
687
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530688 /*
689 * Send a disconnect command to target when a disconnect event is
690 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
691 * request from host) to make the firmware stop trying to connect even
692 * after giving disconnect event. There will be one more disconnect
693 * event for this disconnect command with reason code DISCONNECT_CMD
694 * which will be notified to cfg80211.
695 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300696
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530697 if (reason != DISCONNECT_CMD) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300698 ath6kl_wmi_disconnect_cmd(ar->wmi);
699 return;
700 }
701
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530702 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300703
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530704 if (ar->sme_state == SME_CONNECTING) {
705 cfg80211_connect_result(ar->net_dev,
706 bssid, NULL, 0,
707 NULL, 0,
708 WLAN_STATUS_UNSPECIFIED_FAILURE,
709 GFP_KERNEL);
710 } else if (ar->sme_state == SME_CONNECTED) {
711 cfg80211_disconnected(ar->net_dev, reason,
712 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300713 }
714
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530715 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300716}
717
Kalle Valobdcd8172011-07-18 00:22:30 +0300718static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
719 struct cfg80211_scan_request *request)
720{
721 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530722 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300723 s8 n_channels = 0;
724 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300725 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530726 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300727
728 if (!ath6kl_cfg80211_ready(ar))
729 return -EIO;
730
731 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530732 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300733 ret = ath6kl_wmi_bssfilter_cmd(
734 ar->wmi,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530735 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300736 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
737 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300738 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300739 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300740 }
741 }
742
743 if (request->n_ssids && request->ssids[0].ssid_len) {
744 u8 i;
745
746 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
747 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
748
749 for (i = 0; i < request->n_ssids; i++)
750 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
751 SPECIFIC_SSID_FLAG,
752 request->ssids[i].ssid_len,
753 request->ssids[i].ssid);
754 }
755
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300756 if (request->ie) {
757 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
758 request->ie, request->ie_len);
759 if (ret) {
760 ath6kl_err("failed to set Probe Request appie for "
761 "scan");
762 return ret;
763 }
764 }
765
Jouni Malinen11869be2011-09-02 20:07:06 +0300766 /*
767 * Scan only the requested channels if the request specifies a set of
768 * channels. If the list is longer than the target supports, do not
769 * configure the list and instead, scan all available channels.
770 */
771 if (request->n_channels > 0 &&
772 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300773 u8 i;
774
Jouni Malinen11869be2011-09-02 20:07:06 +0300775 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300776
777 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
778 if (channels == NULL) {
779 ath6kl_warn("failed to set scan channels, "
780 "scan all channels");
781 n_channels = 0;
782 }
783
784 for (i = 0; i < n_channels; i++)
785 channels[i] = request->channels[i]->center_freq;
786 }
787
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530788 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530789 force_fg_scan = 1;
790
791 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, force_fg_scan,
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300792 false, 0, 0, n_channels, channels);
793 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300795 else
796 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300797
Edward Lu1276c9e2011-08-30 21:58:00 +0300798 kfree(channels);
799
Kalle Valobdcd8172011-07-18 00:22:30 +0300800 return ret;
801}
802
803void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
804{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300805 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300806
807 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
808
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300809 if (!ar->scan_req)
810 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300811
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300812 if ((status == -ECANCELED) || (status == -EBUSY)) {
813 cfg80211_scan_done(ar->scan_req, true);
814 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300815 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300816
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300817 cfg80211_scan_done(ar->scan_req, false);
818
819 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
820 for (i = 0; i < ar->scan_req->n_ssids; i++) {
821 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
822 DISABLE_SSID_FLAG,
823 0, NULL);
824 }
825 }
826
827out:
828 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300829}
830
831static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
832 u8 key_index, bool pairwise,
833 const u8 *mac_addr,
834 struct key_params *params)
835{
836 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530837 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300838 struct ath6kl_key *key = NULL;
839 u8 key_usage;
840 u8 key_type;
841 int status = 0;
842
843 if (!ath6kl_cfg80211_ready(ar))
844 return -EIO;
845
Jouni Malinen837cb972011-10-11 17:31:57 +0300846 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
847 if (params->key_len != WMI_KRK_LEN)
848 return -EINVAL;
849 return ath6kl_wmi_add_krk_cmd(ar->wmi, params->key);
850 }
851
Kalle Valobdcd8172011-07-18 00:22:30 +0300852 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
853 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
854 "%s: key index %d out of bounds\n", __func__,
855 key_index);
856 return -ENOENT;
857 }
858
859 key = &ar->keys[key_index];
860 memset(key, 0, sizeof(struct ath6kl_key));
861
862 if (pairwise)
863 key_usage = PAIRWISE_USAGE;
864 else
865 key_usage = GROUP_USAGE;
866
867 if (params) {
868 if (params->key_len > WLAN_MAX_KEY_LEN ||
869 params->seq_len > sizeof(key->seq))
870 return -EINVAL;
871
872 key->key_len = params->key_len;
873 memcpy(key->key, params->key, key->key_len);
874 key->seq_len = params->seq_len;
875 memcpy(key->seq, params->seq, key->seq_len);
876 key->cipher = params->cipher;
877 }
878
879 switch (key->cipher) {
880 case WLAN_CIPHER_SUITE_WEP40:
881 case WLAN_CIPHER_SUITE_WEP104:
882 key_type = WEP_CRYPT;
883 break;
884
885 case WLAN_CIPHER_SUITE_TKIP:
886 key_type = TKIP_CRYPT;
887 break;
888
889 case WLAN_CIPHER_SUITE_CCMP:
890 key_type = AES_CRYPT;
891 break;
892
893 default:
894 return -ENOTSUPP;
895 }
896
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530897 if (((vif->auth_mode == WPA_PSK_AUTH)
898 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300899 && (key_usage & GROUP_USAGE))
900 del_timer(&ar->disconnect_timer);
901
902 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
903 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
904 __func__, key_index, key->key_len, key_type,
905 key_usage, key->seq_len);
906
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530907 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300908
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530909 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300910 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
911 ar->ap_mode_bkey.valid = true;
912 ar->ap_mode_bkey.key_index = key_index;
913 ar->ap_mode_bkey.key_type = key_type;
914 ar->ap_mode_bkey.key_len = key->key_len;
915 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530916 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300917 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
918 "key configuration until AP mode has been "
919 "started\n");
920 /*
921 * The key will be set in ath6kl_connect_ap_mode() once
922 * the connected event is received from the target.
923 */
924 return 0;
925 }
926 }
927
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530928 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530929 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300930 /*
931 * Store the key locally so that it can be re-configured after
932 * the AP mode has properly started
933 * (ath6kl_install_statioc_wep_keys).
934 */
935 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
936 "until AP mode has been started\n");
937 ar->wep_key_list[key_index].key_len = key->key_len;
938 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
939 return 0;
940 }
941
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530942 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +0300943 key_type, key_usage, key->key_len,
944 key->seq, key->key, KEY_OP_INIT_VAL,
945 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
946
947 if (status)
948 return -EIO;
949
950 return 0;
951}
952
953static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
954 u8 key_index, bool pairwise,
955 const u8 *mac_addr)
956{
957 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
958
959 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
960
961 if (!ath6kl_cfg80211_ready(ar))
962 return -EIO;
963
964 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
965 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
966 "%s: key index %d out of bounds\n", __func__,
967 key_index);
968 return -ENOENT;
969 }
970
971 if (!ar->keys[key_index].key_len) {
972 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
973 "%s: index %d is empty\n", __func__, key_index);
974 return 0;
975 }
976
977 ar->keys[key_index].key_len = 0;
978
979 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
980}
981
982static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
983 u8 key_index, bool pairwise,
984 const u8 *mac_addr, void *cookie,
985 void (*callback) (void *cookie,
986 struct key_params *))
987{
988 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
989 struct ath6kl_key *key = NULL;
990 struct key_params params;
991
992 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
993
994 if (!ath6kl_cfg80211_ready(ar))
995 return -EIO;
996
997 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
998 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
999 "%s: key index %d out of bounds\n", __func__,
1000 key_index);
1001 return -ENOENT;
1002 }
1003
1004 key = &ar->keys[key_index];
1005 memset(&params, 0, sizeof(params));
1006 params.cipher = key->cipher;
1007 params.key_len = key->key_len;
1008 params.seq_len = key->seq_len;
1009 params.seq = key->seq;
1010 params.key = key->key;
1011
1012 callback(cookie, &params);
1013
1014 return key->key_len ? 0 : -ENOENT;
1015}
1016
1017static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1018 struct net_device *ndev,
1019 u8 key_index, bool unicast,
1020 bool multicast)
1021{
1022 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301023 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001024 struct ath6kl_key *key = NULL;
1025 int status = 0;
1026 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001027 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001028
1029 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1030
1031 if (!ath6kl_cfg80211_ready(ar))
1032 return -EIO;
1033
1034 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1035 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1036 "%s: key index %d out of bounds\n",
1037 __func__, key_index);
1038 return -ENOENT;
1039 }
1040
1041 if (!ar->keys[key_index].key_len) {
1042 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1043 __func__, key_index);
1044 return -EINVAL;
1045 }
1046
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301047 vif->def_txkey_index = key_index;
1048 key = &ar->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001049 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301050 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001051 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001052 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301053 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001054 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301055 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001056
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301057 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001058 return 0; /* Delay until AP mode has been started */
1059
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301060 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001061 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001062 key->key_len, key->seq, key->key,
1063 KEY_OP_INIT_VAL, NULL,
1064 SYNC_BOTH_WMIFLAG);
1065 if (status)
1066 return -EIO;
1067
1068 return 0;
1069}
1070
1071void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1072 bool ismcast)
1073{
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301074 /* TODO: Findout vif */
1075 struct ath6kl_vif *vif = ar->vif;
1076
Kalle Valobdcd8172011-07-18 00:22:30 +03001077 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1078 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1079
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301080 cfg80211_michael_mic_failure(ar->net_dev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001081 (ismcast ? NL80211_KEYTYPE_GROUP :
1082 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1083 GFP_KERNEL);
1084}
1085
1086static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1087{
1088 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1089 int ret;
1090
1091 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1092 changed);
1093
1094 if (!ath6kl_cfg80211_ready(ar))
1095 return -EIO;
1096
1097 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1098 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1099 if (ret != 0) {
1100 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1101 return -EIO;
1102 }
1103 }
1104
1105 return 0;
1106}
1107
1108/*
1109 * The type nl80211_tx_power_setting replaces the following
1110 * data type from 2.6.36 onwards
1111*/
1112static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1113 enum nl80211_tx_power_setting type,
1114 int dbm)
1115{
1116 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1117 u8 ath6kl_dbm;
1118
1119 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1120 type, dbm);
1121
1122 if (!ath6kl_cfg80211_ready(ar))
1123 return -EIO;
1124
1125 switch (type) {
1126 case NL80211_TX_POWER_AUTOMATIC:
1127 return 0;
1128 case NL80211_TX_POWER_LIMITED:
1129 ar->tx_pwr = ath6kl_dbm = dbm;
1130 break;
1131 default:
1132 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1133 __func__, type);
1134 return -EOPNOTSUPP;
1135 }
1136
1137 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1138
1139 return 0;
1140}
1141
1142static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1143{
1144 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301145 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001146
1147 if (!ath6kl_cfg80211_ready(ar))
1148 return -EIO;
1149
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301150 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001151 ar->tx_pwr = 0;
1152
1153 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1154 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1155 return -EIO;
1156 }
1157
1158 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1159 5 * HZ);
1160
1161 if (signal_pending(current)) {
1162 ath6kl_err("target did not respond\n");
1163 return -EINTR;
1164 }
1165 }
1166
1167 *dbm = ar->tx_pwr;
1168 return 0;
1169}
1170
1171static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1172 struct net_device *dev,
1173 bool pmgmt, int timeout)
1174{
1175 struct ath6kl *ar = ath6kl_priv(dev);
1176 struct wmi_power_mode_cmd mode;
1177
1178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1179 __func__, pmgmt, timeout);
1180
1181 if (!ath6kl_cfg80211_ready(ar))
1182 return -EIO;
1183
1184 if (pmgmt) {
1185 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1186 mode.pwr_mode = REC_POWER;
1187 } else {
1188 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1189 mode.pwr_mode = MAX_PERF_POWER;
1190 }
1191
1192 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1193 ath6kl_err("wmi_powermode_cmd failed\n");
1194 return -EIO;
1195 }
1196
1197 return 0;
1198}
1199
1200static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1201 struct net_device *ndev,
1202 enum nl80211_iftype type, u32 *flags,
1203 struct vif_params *params)
1204{
1205 struct ath6kl *ar = ath6kl_priv(ndev);
1206 struct wireless_dev *wdev = ar->wdev;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301207 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001208
1209 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1210
1211 if (!ath6kl_cfg80211_ready(ar))
1212 return -EIO;
1213
1214 switch (type) {
1215 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301216 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001217 break;
1218 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301219 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001220 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001221 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301222 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001223 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001224 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301225 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001226 break;
1227 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301228 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001229 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001230 default:
1231 ath6kl_err("invalid interface type %u\n", type);
1232 return -EOPNOTSUPP;
1233 }
1234
1235 wdev->iftype = type;
1236
1237 return 0;
1238}
1239
1240static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1241 struct net_device *dev,
1242 struct cfg80211_ibss_params *ibss_param)
1243{
1244 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301245 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001246 int status;
1247
1248 if (!ath6kl_cfg80211_ready(ar))
1249 return -EIO;
1250
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301251 vif->ssid_len = ibss_param->ssid_len;
1252 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001253
1254 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301255 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001256
1257 if (ibss_param->channel_fixed) {
1258 /*
1259 * TODO: channel_fixed: The channel should be fixed, do not
1260 * search for IBSSs to join on other channels. Target
1261 * firmware does not support this feature, needs to be
1262 * updated.
1263 */
1264 return -EOPNOTSUPP;
1265 }
1266
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301267 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001268 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301269 memcpy(vif->req_bssid, ibss_param->bssid,
1270 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001271
1272 ath6kl_set_wpa_version(ar, 0);
1273
1274 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1275 if (status)
1276 return status;
1277
1278 if (ibss_param->privacy) {
1279 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1280 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1281 } else {
1282 ath6kl_set_cipher(ar, 0, true);
1283 ath6kl_set_cipher(ar, 0, false);
1284 }
1285
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301286 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001287
1288 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1289 "%s: connect called with authmode %d dot11 auth %d"
1290 " PW crypto %d PW crypto len %d GRP crypto %d"
1291 " GRP crypto len %d channel hint %u\n",
1292 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301293 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1294 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301295 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001296
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301297 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301298 vif->dot11_auth_mode, vif->auth_mode,
1299 vif->prwise_crypto,
1300 vif->prwise_crypto_len,
1301 vif->grp_crypto, vif->grp_crypto_len,
1302 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301303 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001304 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301305 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001306
1307 return 0;
1308}
1309
1310static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1311 struct net_device *dev)
1312{
1313 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301314 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001315
1316 if (!ath6kl_cfg80211_ready(ar))
1317 return -EIO;
1318
1319 ath6kl_disconnect(ar);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301320 memset(vif->ssid, 0, sizeof(vif->ssid));
1321 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001322
1323 return 0;
1324}
1325
1326static const u32 cipher_suites[] = {
1327 WLAN_CIPHER_SUITE_WEP40,
1328 WLAN_CIPHER_SUITE_WEP104,
1329 WLAN_CIPHER_SUITE_TKIP,
1330 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001331 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001332};
1333
1334static bool is_rate_legacy(s32 rate)
1335{
1336 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1337 6000, 9000, 12000, 18000, 24000,
1338 36000, 48000, 54000
1339 };
1340 u8 i;
1341
1342 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1343 if (rate == legacy[i])
1344 return true;
1345
1346 return false;
1347}
1348
1349static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1350{
1351 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1352 52000, 58500, 65000, 72200
1353 };
1354 u8 i;
1355
1356 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1357 if (rate == ht20[i]) {
1358 if (i == ARRAY_SIZE(ht20) - 1)
1359 /* last rate uses sgi */
1360 *sgi = true;
1361 else
1362 *sgi = false;
1363
1364 *mcs = i;
1365 return true;
1366 }
1367 }
1368 return false;
1369}
1370
1371static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1372{
1373 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1374 81000, 108000, 121500, 135000,
1375 150000
1376 };
1377 u8 i;
1378
1379 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1380 if (rate == ht40[i]) {
1381 if (i == ARRAY_SIZE(ht40) - 1)
1382 /* last rate uses sgi */
1383 *sgi = true;
1384 else
1385 *sgi = false;
1386
1387 *mcs = i;
1388 return true;
1389 }
1390 }
1391
1392 return false;
1393}
1394
1395static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1396 u8 *mac, struct station_info *sinfo)
1397{
1398 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301399 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001400 long left;
1401 bool sgi;
1402 s32 rate;
1403 int ret;
1404 u8 mcs;
1405
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301406 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001407 return -ENOENT;
1408
1409 if (down_interruptible(&ar->sem))
1410 return -EBUSY;
1411
1412 set_bit(STATS_UPDATE_PEND, &ar->flag);
1413
1414 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1415
1416 if (ret != 0) {
1417 up(&ar->sem);
1418 return -EIO;
1419 }
1420
1421 left = wait_event_interruptible_timeout(ar->event_wq,
1422 !test_bit(STATS_UPDATE_PEND,
1423 &ar->flag),
1424 WMI_TIMEOUT);
1425
1426 up(&ar->sem);
1427
1428 if (left == 0)
1429 return -ETIMEDOUT;
1430 else if (left < 0)
1431 return left;
1432
1433 if (ar->target_stats.rx_byte) {
1434 sinfo->rx_bytes = ar->target_stats.rx_byte;
1435 sinfo->filled |= STATION_INFO_RX_BYTES;
1436 sinfo->rx_packets = ar->target_stats.rx_pkt;
1437 sinfo->filled |= STATION_INFO_RX_PACKETS;
1438 }
1439
1440 if (ar->target_stats.tx_byte) {
1441 sinfo->tx_bytes = ar->target_stats.tx_byte;
1442 sinfo->filled |= STATION_INFO_TX_BYTES;
1443 sinfo->tx_packets = ar->target_stats.tx_pkt;
1444 sinfo->filled |= STATION_INFO_TX_PACKETS;
1445 }
1446
1447 sinfo->signal = ar->target_stats.cs_rssi;
1448 sinfo->filled |= STATION_INFO_SIGNAL;
1449
1450 rate = ar->target_stats.tx_ucast_rate;
1451
1452 if (is_rate_legacy(rate)) {
1453 sinfo->txrate.legacy = rate / 100;
1454 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1455 if (sgi) {
1456 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1457 sinfo->txrate.mcs = mcs - 1;
1458 } else {
1459 sinfo->txrate.mcs = mcs;
1460 }
1461
1462 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1463 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1464 if (sgi) {
1465 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1466 sinfo->txrate.mcs = mcs - 1;
1467 } else {
1468 sinfo->txrate.mcs = mcs;
1469 }
1470
1471 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1472 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1473 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001474 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1475 "invalid rate from stats: %d\n", rate);
1476 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001477 return 0;
1478 }
1479
1480 sinfo->filled |= STATION_INFO_TX_BITRATE;
1481
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301482 if (test_bit(CONNECTED, &vif->flags) &&
1483 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301484 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001485 sinfo->filled |= STATION_INFO_BSS_PARAM;
1486 sinfo->bss_param.flags = 0;
1487 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1488 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1489 }
1490
Kalle Valobdcd8172011-07-18 00:22:30 +03001491 return 0;
1492}
1493
1494static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1495 struct cfg80211_pmksa *pmksa)
1496{
1497 struct ath6kl *ar = ath6kl_priv(netdev);
1498 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1499 pmksa->pmkid, true);
1500}
1501
1502static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1503 struct cfg80211_pmksa *pmksa)
1504{
1505 struct ath6kl *ar = ath6kl_priv(netdev);
1506 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1507 pmksa->pmkid, false);
1508}
1509
1510static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1511{
1512 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301513 struct ath6kl_vif *vif = netdev_priv(netdev);
1514
1515 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301516 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->bssid,
1517 NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518 return 0;
1519}
1520
Kalle Valoabcb3442011-07-22 08:26:20 +03001521#ifdef CONFIG_PM
1522static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1523 struct cfg80211_wowlan *wow)
1524{
1525 struct ath6kl *ar = wiphy_priv(wiphy);
1526
1527 return ath6kl_hif_suspend(ar);
1528}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001529
1530static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1531{
1532 struct ath6kl *ar = wiphy_priv(wiphy);
1533
1534 return ath6kl_hif_resume(ar);
1535}
Kalle Valoabcb3442011-07-22 08:26:20 +03001536#endif
1537
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001538static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1539 struct ieee80211_channel *chan,
1540 enum nl80211_channel_type channel_type)
1541{
1542 struct ath6kl *ar = ath6kl_priv(dev);
1543
1544 if (!ath6kl_cfg80211_ready(ar))
1545 return -EIO;
1546
1547 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1548 __func__, chan->center_freq, chan->hw_value);
1549 ar->next_chan = chan->center_freq;
1550
1551 return 0;
1552}
1553
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001554static bool ath6kl_is_p2p_ie(const u8 *pos)
1555{
1556 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1557 pos[2] == 0x50 && pos[3] == 0x6f &&
1558 pos[4] == 0x9a && pos[5] == 0x09;
1559}
1560
1561static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1562 size_t ies_len)
1563{
1564 const u8 *pos;
1565 u8 *buf = NULL;
1566 size_t len = 0;
1567 int ret;
1568
1569 /*
1570 * Filter out P2P IE(s) since they will be included depending on
1571 * the Probe Request frame in ath6kl_send_go_probe_resp().
1572 */
1573
1574 if (ies && ies_len) {
1575 buf = kmalloc(ies_len, GFP_KERNEL);
1576 if (buf == NULL)
1577 return -ENOMEM;
1578 pos = ies;
1579 while (pos + 1 < ies + ies_len) {
1580 if (pos + 2 + pos[1] > ies + ies_len)
1581 break;
1582 if (!ath6kl_is_p2p_ie(pos)) {
1583 memcpy(buf + len, pos, 2 + pos[1]);
1584 len += 2 + pos[1];
1585 }
1586 pos += 2 + pos[1];
1587 }
1588 }
1589
1590 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1591 buf, len);
1592 kfree(buf);
1593 return ret;
1594}
1595
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001596static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1597 struct beacon_parameters *info, bool add)
1598{
1599 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301600 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001601 struct ieee80211_mgmt *mgmt;
1602 u8 *ies;
1603 int ies_len;
1604 struct wmi_connect_cmd p;
1605 int res;
1606 int i;
1607
1608 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1609
1610 if (!ath6kl_cfg80211_ready(ar))
1611 return -EIO;
1612
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301613 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001614 return -EOPNOTSUPP;
1615
1616 if (info->beacon_ies) {
1617 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1618 info->beacon_ies,
1619 info->beacon_ies_len);
1620 if (res)
1621 return res;
1622 }
1623 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001624 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1625 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001626 if (res)
1627 return res;
1628 }
1629 if (info->assocresp_ies) {
1630 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1631 info->assocresp_ies,
1632 info->assocresp_ies_len);
1633 if (res)
1634 return res;
1635 }
1636
1637 if (!add)
1638 return 0;
1639
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001640 ar->ap_mode_bkey.valid = false;
1641
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001642 /* TODO:
1643 * info->interval
1644 * info->dtim_period
1645 */
1646
1647 if (info->head == NULL)
1648 return -EINVAL;
1649 mgmt = (struct ieee80211_mgmt *) info->head;
1650 ies = mgmt->u.beacon.variable;
1651 if (ies > info->head + info->head_len)
1652 return -EINVAL;
1653 ies_len = info->head + info->head_len - ies;
1654
1655 if (info->ssid == NULL)
1656 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301657 memcpy(vif->ssid, info->ssid, info->ssid_len);
1658 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001659 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1660 return -EOPNOTSUPP; /* TODO */
1661
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301662 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001663
1664 memset(&p, 0, sizeof(p));
1665
1666 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1667 switch (info->crypto.akm_suites[i]) {
1668 case WLAN_AKM_SUITE_8021X:
1669 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1670 p.auth_mode |= WPA_AUTH;
1671 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1672 p.auth_mode |= WPA2_AUTH;
1673 break;
1674 case WLAN_AKM_SUITE_PSK:
1675 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1676 p.auth_mode |= WPA_PSK_AUTH;
1677 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1678 p.auth_mode |= WPA2_PSK_AUTH;
1679 break;
1680 }
1681 }
1682 if (p.auth_mode == 0)
1683 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301684 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001685
1686 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1687 switch (info->crypto.ciphers_pairwise[i]) {
1688 case WLAN_CIPHER_SUITE_WEP40:
1689 case WLAN_CIPHER_SUITE_WEP104:
1690 p.prwise_crypto_type |= WEP_CRYPT;
1691 break;
1692 case WLAN_CIPHER_SUITE_TKIP:
1693 p.prwise_crypto_type |= TKIP_CRYPT;
1694 break;
1695 case WLAN_CIPHER_SUITE_CCMP:
1696 p.prwise_crypto_type |= AES_CRYPT;
1697 break;
1698 }
1699 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001700 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001701 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001702 ath6kl_set_cipher(ar, 0, true);
1703 } else if (info->crypto.n_ciphers_pairwise == 1)
1704 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001705
1706 switch (info->crypto.cipher_group) {
1707 case WLAN_CIPHER_SUITE_WEP40:
1708 case WLAN_CIPHER_SUITE_WEP104:
1709 p.grp_crypto_type = WEP_CRYPT;
1710 break;
1711 case WLAN_CIPHER_SUITE_TKIP:
1712 p.grp_crypto_type = TKIP_CRYPT;
1713 break;
1714 case WLAN_CIPHER_SUITE_CCMP:
1715 p.grp_crypto_type = AES_CRYPT;
1716 break;
1717 default:
1718 p.grp_crypto_type = NONE_CRYPT;
1719 break;
1720 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001721 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001722
1723 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301724 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001725
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301726 p.ssid_len = vif->ssid_len;
1727 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1728 p.dot11_auth_mode = vif->dot11_auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001729 p.ch = cpu_to_le16(ar->next_chan);
1730
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001731 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1732 if (res < 0)
1733 return res;
1734
1735 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001736}
1737
1738static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1739 struct beacon_parameters *info)
1740{
1741 return ath6kl_ap_beacon(wiphy, dev, info, true);
1742}
1743
1744static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1745 struct beacon_parameters *info)
1746{
1747 return ath6kl_ap_beacon(wiphy, dev, info, false);
1748}
1749
1750static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1751{
1752 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301753 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001754
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301755 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001756 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301757 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001758 return -ENOTCONN;
1759
1760 ath6kl_wmi_disconnect_cmd(ar->wmi);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301761 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001762
1763 return 0;
1764}
1765
Jouni Malinen23875132011-08-30 21:57:53 +03001766static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1767 u8 *mac, struct station_parameters *params)
1768{
1769 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301770 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001771
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301772 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001773 return -EOPNOTSUPP;
1774
1775 /* Use this only for authorizing/unauthorizing a station */
1776 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1777 return -EOPNOTSUPP;
1778
1779 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1780 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1781 mac, 0);
1782 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1783 0);
1784}
1785
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001786static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1787 struct net_device *dev,
1788 struct ieee80211_channel *chan,
1789 enum nl80211_channel_type channel_type,
1790 unsigned int duration,
1791 u64 *cookie)
1792{
1793 struct ath6kl *ar = ath6kl_priv(dev);
1794
1795 /* TODO: if already pending or ongoing remain-on-channel,
1796 * return -EBUSY */
1797 *cookie = 1; /* only a single pending request is supported */
1798
1799 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1800 duration);
1801}
1802
1803static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1804 struct net_device *dev,
1805 u64 cookie)
1806{
1807 struct ath6kl *ar = ath6kl_priv(dev);
1808
1809 if (cookie != 1)
1810 return -ENOENT;
1811
1812 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1813}
1814
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001815static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1816 size_t len, unsigned int freq)
1817{
1818 const u8 *pos;
1819 u8 *p2p;
1820 int p2p_len;
1821 int ret;
1822 const struct ieee80211_mgmt *mgmt;
1823
1824 mgmt = (const struct ieee80211_mgmt *) buf;
1825
1826 /* Include P2P IE(s) from the frame generated in user space. */
1827
1828 p2p = kmalloc(len, GFP_KERNEL);
1829 if (p2p == NULL)
1830 return -ENOMEM;
1831 p2p_len = 0;
1832
1833 pos = mgmt->u.probe_resp.variable;
1834 while (pos + 1 < buf + len) {
1835 if (pos + 2 + pos[1] > buf + len)
1836 break;
1837 if (ath6kl_is_p2p_ie(pos)) {
1838 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1839 p2p_len += 2 + pos[1];
1840 }
1841 pos += 2 + pos[1];
1842 }
1843
1844 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1845 p2p, p2p_len);
1846 kfree(p2p);
1847 return ret;
1848}
1849
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001850static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1851 struct ieee80211_channel *chan, bool offchan,
1852 enum nl80211_channel_type channel_type,
1853 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001854 const u8 *buf, size_t len, bool no_cck,
1855 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001856{
1857 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301858 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001859 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001860 const struct ieee80211_mgmt *mgmt;
1861
1862 mgmt = (const struct ieee80211_mgmt *) buf;
1863 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301864 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001865 ieee80211_is_probe_resp(mgmt->frame_control)) {
1866 /*
1867 * Send Probe Response frame in AP mode using a separate WMI
1868 * command to allow the target to fill in the generic IEs.
1869 */
1870 *cookie = 0; /* TX status not supported */
1871 return ath6kl_send_go_probe_resp(ar, buf, len,
1872 chan->center_freq);
1873 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001874
1875 id = ar->send_action_id++;
1876 if (id == 0) {
1877 /*
1878 * 0 is a reserved value in the WMI command and shall not be
1879 * used for the command.
1880 */
1881 id = ar->send_action_id++;
1882 }
1883
1884 *cookie = id;
1885 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1886 buf, len);
1887}
1888
Jouni Malinenae32c302011-08-30 21:58:01 +03001889static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1890 struct net_device *dev,
1891 u16 frame_type, bool reg)
1892{
1893 struct ath6kl *ar = ath6kl_priv(dev);
1894
1895 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1896 __func__, frame_type, reg);
1897 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1898 /*
1899 * Note: This notification callback is not allowed to sleep, so
1900 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1901 * hardcode target to report Probe Request frames all the time.
1902 */
1903 ar->probe_req_report = reg;
1904 }
1905}
1906
Jouni Malinenf80574a2011-08-30 21:58:04 +03001907static const struct ieee80211_txrx_stypes
1908ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1909 [NL80211_IFTYPE_STATION] = {
1910 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1911 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1912 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1913 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1914 },
1915 [NL80211_IFTYPE_P2P_CLIENT] = {
1916 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1917 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1918 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1919 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1920 },
1921 [NL80211_IFTYPE_P2P_GO] = {
1922 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1923 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1924 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1925 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1926 },
1927};
1928
Kalle Valobdcd8172011-07-18 00:22:30 +03001929static struct cfg80211_ops ath6kl_cfg80211_ops = {
1930 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1931 .scan = ath6kl_cfg80211_scan,
1932 .connect = ath6kl_cfg80211_connect,
1933 .disconnect = ath6kl_cfg80211_disconnect,
1934 .add_key = ath6kl_cfg80211_add_key,
1935 .get_key = ath6kl_cfg80211_get_key,
1936 .del_key = ath6kl_cfg80211_del_key,
1937 .set_default_key = ath6kl_cfg80211_set_default_key,
1938 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1939 .set_tx_power = ath6kl_cfg80211_set_txpower,
1940 .get_tx_power = ath6kl_cfg80211_get_txpower,
1941 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1942 .join_ibss = ath6kl_cfg80211_join_ibss,
1943 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1944 .get_station = ath6kl_get_station,
1945 .set_pmksa = ath6kl_set_pmksa,
1946 .del_pmksa = ath6kl_del_pmksa,
1947 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001948 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001949#ifdef CONFIG_PM
1950 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001951 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001952#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001953 .set_channel = ath6kl_set_channel,
1954 .add_beacon = ath6kl_add_beacon,
1955 .set_beacon = ath6kl_set_beacon,
1956 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001957 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001958 .remain_on_channel = ath6kl_remain_on_channel,
1959 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001960 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001961 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001962};
1963
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301964struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001965{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001966 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301967 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301968 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001969
1970 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301971 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301972
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301973 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001974 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001975 return NULL;
1976 }
1977
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301978 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001979 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301980 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301981 ar->dev = dev;
1982
1983 spin_lock_init(&ar->lock);
1984 spin_lock_init(&ar->mcastpsq_lock);
1985
1986 init_waitqueue_head(&ar->event_wq);
1987 sema_init(&ar->sem, 1);
1988
1989 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1990
1991 clear_bit(WMI_ENABLED, &ar->flag);
1992 clear_bit(SKIP_SCAN, &ar->flag);
1993 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
1994
1995 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
1996 ar->listen_intvl_b = 0;
1997 ar->tx_pwr = 0;
1998
1999 ar->intra_bss = 1;
2000 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2001 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2002 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2003 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2004
2005 memset((u8 *)ar->sta_list, 0,
2006 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2007
2008 /* Init the PS queues */
2009 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2010 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2011 skb_queue_head_init(&ar->sta_list[ctr].psq);
2012 }
2013
2014 skb_queue_head_init(&ar->mcastpsq);
2015
2016 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2017
2018 return ar;
2019}
2020
2021int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2022{
2023 struct wiphy *wiphy = ar->wiphy;
2024 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002025
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302026 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002027
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302028 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002029
Kalle Valobdcd8172011-07-18 00:22:30 +03002030 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302031 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002032
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302033 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302034 BIT(NL80211_IFTYPE_ADHOC) |
2035 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002036 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302037 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302038 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002039 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302040
Kalle Valobdcd8172011-07-18 00:22:30 +03002041 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302042 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2043 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2044 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2045 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2046 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002047
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302048 wiphy->cipher_suites = cipher_suites;
2049 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002050
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302051 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002052 if (ret < 0) {
2053 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302054 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002055 }
2056
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302057 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002058}
2059
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302060static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002061{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302062 struct ath6kl *ar = vif->ar;
2063
2064 ar->aggr_cntxt = aggr_init(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302065 if (!ar->aggr_cntxt) {
2066 ath6kl_err("failed to initialize aggr\n");
2067 return -ENOMEM;
2068 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002069
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302070 setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302071 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302072
2073 return 0;
2074}
2075
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302076void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302077{
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302078 struct ath6kl *ar = vif->ar;
2079
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302080 aggr_module_destroy(ar->aggr_cntxt);
2081
2082 ar->aggr_cntxt = NULL;
2083
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302084 if (test_bit(NETDEV_REGISTERED, &vif->flags)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302085 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302086 clear_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302087 }
2088
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302089 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302090}
2091
2092struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
2093 enum nl80211_iftype type)
2094{
2095 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302096 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302097
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302098 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302099 if (!ndev)
2100 return NULL;
2101
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302102 vif = netdev_priv(ndev);
2103 ndev->ieee80211_ptr = &vif->wdev;
2104 vif->wdev.wiphy = ar->wiphy;
2105 vif->ar = ar;
2106 ar->vif = vif;
2107 vif->ndev = ndev;
2108 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2109 vif->wdev.netdev = ndev;
2110 vif->wdev.iftype = type;
2111 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302112 ar->net_dev = ndev;
2113
2114 init_netdev(ndev);
2115
2116 ath6kl_init_control_info(ar);
2117
2118 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302119 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302120 goto err;
2121
2122 if (register_netdev(ndev))
2123 goto err;
2124
2125 ar->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302126 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302127 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302128 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302129
2130 return ndev;
2131
2132err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302133 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302134
2135 return NULL;
2136}
2137
2138void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2139{
Kalle Valobdcd8172011-07-18 00:22:30 +03002140 if (ar->scan_req) {
2141 cfg80211_scan_done(ar->scan_req, true);
2142 ar->scan_req = NULL;
2143 }
2144
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302145 wiphy_unregister(ar->wiphy);
2146 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002147}