blob: 06a7c4f452b7d4acced0094e485e1e5c05705c21 [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
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530314 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300315
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)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530365 vif->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
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530422 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300423 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
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530457 vif->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))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530482 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300483 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 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530569 vif->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
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530604 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300605 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530606 vif->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);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530611 } else if (vif->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
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530641 vif->reconnect_flag = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300642 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 Thiagarajan14ee6f62011-10-25 19:34:09 +0530651 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530652
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
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530663 if (vif->scan_req) {
664 cfg80211_scan_done(vif->scan_req, true);
665 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300666 }
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 Thiagarajan14ee6f62011-10-25 19:34:09 +0530704 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530705 cfg80211_connect_result(ar->net_dev,
706 bssid, NULL, 0,
707 NULL, 0,
708 WLAN_STATUS_UNSPECIFIED_FAILURE,
709 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530710 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530711 cfg80211_disconnected(ar->net_dev, reason,
712 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300713 }
714
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530715 vif->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
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530796 vif->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{
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530805 /* TODO: Findout vif */
806 struct ath6kl_vif *vif = ar->vif;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300807 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300808
809 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
810
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530811 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300812 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300813
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300814 if ((status == -ECANCELED) || (status == -EBUSY)) {
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530815 cfg80211_scan_done(vif->scan_req, true);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300816 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300817 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300818
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530819 cfg80211_scan_done(vif->scan_req, false);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300820
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530821 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
822 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300823 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
824 DISABLE_SSID_FLAG,
825 0, NULL);
826 }
827 }
828
829out:
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530830 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300831}
832
833static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
834 u8 key_index, bool pairwise,
835 const u8 *mac_addr,
836 struct key_params *params)
837{
838 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530839 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300840 struct ath6kl_key *key = NULL;
841 u8 key_usage;
842 u8 key_type;
843 int status = 0;
844
845 if (!ath6kl_cfg80211_ready(ar))
846 return -EIO;
847
Jouni Malinen837cb972011-10-11 17:31:57 +0300848 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
849 if (params->key_len != WMI_KRK_LEN)
850 return -EINVAL;
851 return ath6kl_wmi_add_krk_cmd(ar->wmi, params->key);
852 }
853
Kalle Valobdcd8172011-07-18 00:22:30 +0300854 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
855 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
856 "%s: key index %d out of bounds\n", __func__,
857 key_index);
858 return -ENOENT;
859 }
860
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530861 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300862 memset(key, 0, sizeof(struct ath6kl_key));
863
864 if (pairwise)
865 key_usage = PAIRWISE_USAGE;
866 else
867 key_usage = GROUP_USAGE;
868
869 if (params) {
870 if (params->key_len > WLAN_MAX_KEY_LEN ||
871 params->seq_len > sizeof(key->seq))
872 return -EINVAL;
873
874 key->key_len = params->key_len;
875 memcpy(key->key, params->key, key->key_len);
876 key->seq_len = params->seq_len;
877 memcpy(key->seq, params->seq, key->seq_len);
878 key->cipher = params->cipher;
879 }
880
881 switch (key->cipher) {
882 case WLAN_CIPHER_SUITE_WEP40:
883 case WLAN_CIPHER_SUITE_WEP104:
884 key_type = WEP_CRYPT;
885 break;
886
887 case WLAN_CIPHER_SUITE_TKIP:
888 key_type = TKIP_CRYPT;
889 break;
890
891 case WLAN_CIPHER_SUITE_CCMP:
892 key_type = AES_CRYPT;
893 break;
894
895 default:
896 return -ENOTSUPP;
897 }
898
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530899 if (((vif->auth_mode == WPA_PSK_AUTH)
900 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300901 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530902 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300903
904 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
905 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
906 __func__, key_index, key->key_len, key_type,
907 key_usage, key->seq_len);
908
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530909 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300910
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530911 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300912 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
913 ar->ap_mode_bkey.valid = true;
914 ar->ap_mode_bkey.key_index = key_index;
915 ar->ap_mode_bkey.key_type = key_type;
916 ar->ap_mode_bkey.key_len = key->key_len;
917 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530918 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300919 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
920 "key configuration until AP mode has been "
921 "started\n");
922 /*
923 * The key will be set in ath6kl_connect_ap_mode() once
924 * the connected event is received from the target.
925 */
926 return 0;
927 }
928 }
929
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530930 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530931 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300932 /*
933 * Store the key locally so that it can be re-configured after
934 * the AP mode has properly started
935 * (ath6kl_install_statioc_wep_keys).
936 */
937 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
938 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530939 vif->wep_key_list[key_index].key_len = key->key_len;
940 memcpy(vif->wep_key_list[key_index].key, key->key,
941 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +0300942 return 0;
943 }
944
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530945 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +0300946 key_type, key_usage, key->key_len,
947 key->seq, key->key, KEY_OP_INIT_VAL,
948 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
949
950 if (status)
951 return -EIO;
952
953 return 0;
954}
955
956static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
957 u8 key_index, bool pairwise,
958 const u8 *mac_addr)
959{
960 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530961 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300962
963 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
964
965 if (!ath6kl_cfg80211_ready(ar))
966 return -EIO;
967
968 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
969 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
970 "%s: key index %d out of bounds\n", __func__,
971 key_index);
972 return -ENOENT;
973 }
974
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530975 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300976 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
977 "%s: index %d is empty\n", __func__, key_index);
978 return 0;
979 }
980
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530981 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300982
983 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
984}
985
986static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
987 u8 key_index, bool pairwise,
988 const u8 *mac_addr, void *cookie,
989 void (*callback) (void *cookie,
990 struct key_params *))
991{
992 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530993 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300994 struct ath6kl_key *key = NULL;
995 struct key_params params;
996
997 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
998
999 if (!ath6kl_cfg80211_ready(ar))
1000 return -EIO;
1001
1002 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1003 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1004 "%s: key index %d out of bounds\n", __func__,
1005 key_index);
1006 return -ENOENT;
1007 }
1008
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301009 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001010 memset(&params, 0, sizeof(params));
1011 params.cipher = key->cipher;
1012 params.key_len = key->key_len;
1013 params.seq_len = key->seq_len;
1014 params.seq = key->seq;
1015 params.key = key->key;
1016
1017 callback(cookie, &params);
1018
1019 return key->key_len ? 0 : -ENOENT;
1020}
1021
1022static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1023 struct net_device *ndev,
1024 u8 key_index, bool unicast,
1025 bool multicast)
1026{
1027 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301028 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001029 struct ath6kl_key *key = NULL;
1030 int status = 0;
1031 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001032 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001033
1034 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1035
1036 if (!ath6kl_cfg80211_ready(ar))
1037 return -EIO;
1038
1039 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1040 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1041 "%s: key index %d out of bounds\n",
1042 __func__, key_index);
1043 return -ENOENT;
1044 }
1045
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301046 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001047 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1048 __func__, key_index);
1049 return -EINVAL;
1050 }
1051
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301052 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301053 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001054 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301055 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001056 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001057 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301058 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001059 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301060 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001061
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301062 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001063 return 0; /* Delay until AP mode has been started */
1064
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301065 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001066 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001067 key->key_len, key->seq, key->key,
1068 KEY_OP_INIT_VAL, NULL,
1069 SYNC_BOTH_WMIFLAG);
1070 if (status)
1071 return -EIO;
1072
1073 return 0;
1074}
1075
1076void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1077 bool ismcast)
1078{
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301079 /* TODO: Findout vif */
1080 struct ath6kl_vif *vif = ar->vif;
1081
Kalle Valobdcd8172011-07-18 00:22:30 +03001082 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1083 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1084
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301085 cfg80211_michael_mic_failure(ar->net_dev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001086 (ismcast ? NL80211_KEYTYPE_GROUP :
1087 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1088 GFP_KERNEL);
1089}
1090
1091static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1092{
1093 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1094 int ret;
1095
1096 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1097 changed);
1098
1099 if (!ath6kl_cfg80211_ready(ar))
1100 return -EIO;
1101
1102 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1103 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1104 if (ret != 0) {
1105 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1106 return -EIO;
1107 }
1108 }
1109
1110 return 0;
1111}
1112
1113/*
1114 * The type nl80211_tx_power_setting replaces the following
1115 * data type from 2.6.36 onwards
1116*/
1117static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1118 enum nl80211_tx_power_setting type,
1119 int dbm)
1120{
1121 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1122 u8 ath6kl_dbm;
1123
1124 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1125 type, dbm);
1126
1127 if (!ath6kl_cfg80211_ready(ar))
1128 return -EIO;
1129
1130 switch (type) {
1131 case NL80211_TX_POWER_AUTOMATIC:
1132 return 0;
1133 case NL80211_TX_POWER_LIMITED:
1134 ar->tx_pwr = ath6kl_dbm = dbm;
1135 break;
1136 default:
1137 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1138 __func__, type);
1139 return -EOPNOTSUPP;
1140 }
1141
1142 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1143
1144 return 0;
1145}
1146
1147static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1148{
1149 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301150 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001151
1152 if (!ath6kl_cfg80211_ready(ar))
1153 return -EIO;
1154
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301155 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001156 ar->tx_pwr = 0;
1157
1158 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1159 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1160 return -EIO;
1161 }
1162
1163 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1164 5 * HZ);
1165
1166 if (signal_pending(current)) {
1167 ath6kl_err("target did not respond\n");
1168 return -EINTR;
1169 }
1170 }
1171
1172 *dbm = ar->tx_pwr;
1173 return 0;
1174}
1175
1176static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1177 struct net_device *dev,
1178 bool pmgmt, int timeout)
1179{
1180 struct ath6kl *ar = ath6kl_priv(dev);
1181 struct wmi_power_mode_cmd mode;
1182
1183 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1184 __func__, pmgmt, timeout);
1185
1186 if (!ath6kl_cfg80211_ready(ar))
1187 return -EIO;
1188
1189 if (pmgmt) {
1190 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1191 mode.pwr_mode = REC_POWER;
1192 } else {
1193 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1194 mode.pwr_mode = MAX_PERF_POWER;
1195 }
1196
1197 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1198 ath6kl_err("wmi_powermode_cmd failed\n");
1199 return -EIO;
1200 }
1201
1202 return 0;
1203}
1204
1205static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1206 struct net_device *ndev,
1207 enum nl80211_iftype type, u32 *flags,
1208 struct vif_params *params)
1209{
1210 struct ath6kl *ar = ath6kl_priv(ndev);
1211 struct wireless_dev *wdev = ar->wdev;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301212 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001213
1214 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1215
1216 if (!ath6kl_cfg80211_ready(ar))
1217 return -EIO;
1218
1219 switch (type) {
1220 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301221 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001222 break;
1223 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301224 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001225 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001226 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301227 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001228 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001229 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301230 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001231 break;
1232 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301233 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001234 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001235 default:
1236 ath6kl_err("invalid interface type %u\n", type);
1237 return -EOPNOTSUPP;
1238 }
1239
1240 wdev->iftype = type;
1241
1242 return 0;
1243}
1244
1245static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1246 struct net_device *dev,
1247 struct cfg80211_ibss_params *ibss_param)
1248{
1249 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301250 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001251 int status;
1252
1253 if (!ath6kl_cfg80211_ready(ar))
1254 return -EIO;
1255
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301256 vif->ssid_len = ibss_param->ssid_len;
1257 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001258
1259 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301260 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001261
1262 if (ibss_param->channel_fixed) {
1263 /*
1264 * TODO: channel_fixed: The channel should be fixed, do not
1265 * search for IBSSs to join on other channels. Target
1266 * firmware does not support this feature, needs to be
1267 * updated.
1268 */
1269 return -EOPNOTSUPP;
1270 }
1271
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301272 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001273 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301274 memcpy(vif->req_bssid, ibss_param->bssid,
1275 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001276
1277 ath6kl_set_wpa_version(ar, 0);
1278
1279 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1280 if (status)
1281 return status;
1282
1283 if (ibss_param->privacy) {
1284 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1285 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1286 } else {
1287 ath6kl_set_cipher(ar, 0, true);
1288 ath6kl_set_cipher(ar, 0, false);
1289 }
1290
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301291 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001292
1293 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1294 "%s: connect called with authmode %d dot11 auth %d"
1295 " PW crypto %d PW crypto len %d GRP crypto %d"
1296 " GRP crypto len %d channel hint %u\n",
1297 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301298 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1299 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301300 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001301
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301302 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301303 vif->dot11_auth_mode, vif->auth_mode,
1304 vif->prwise_crypto,
1305 vif->prwise_crypto_len,
1306 vif->grp_crypto, vif->grp_crypto_len,
1307 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301308 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001309 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301310 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001311
1312 return 0;
1313}
1314
1315static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1316 struct net_device *dev)
1317{
1318 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301319 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001320
1321 if (!ath6kl_cfg80211_ready(ar))
1322 return -EIO;
1323
1324 ath6kl_disconnect(ar);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301325 memset(vif->ssid, 0, sizeof(vif->ssid));
1326 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001327
1328 return 0;
1329}
1330
1331static const u32 cipher_suites[] = {
1332 WLAN_CIPHER_SUITE_WEP40,
1333 WLAN_CIPHER_SUITE_WEP104,
1334 WLAN_CIPHER_SUITE_TKIP,
1335 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001336 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001337};
1338
1339static bool is_rate_legacy(s32 rate)
1340{
1341 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1342 6000, 9000, 12000, 18000, 24000,
1343 36000, 48000, 54000
1344 };
1345 u8 i;
1346
1347 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1348 if (rate == legacy[i])
1349 return true;
1350
1351 return false;
1352}
1353
1354static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1355{
1356 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1357 52000, 58500, 65000, 72200
1358 };
1359 u8 i;
1360
1361 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1362 if (rate == ht20[i]) {
1363 if (i == ARRAY_SIZE(ht20) - 1)
1364 /* last rate uses sgi */
1365 *sgi = true;
1366 else
1367 *sgi = false;
1368
1369 *mcs = i;
1370 return true;
1371 }
1372 }
1373 return false;
1374}
1375
1376static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1377{
1378 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1379 81000, 108000, 121500, 135000,
1380 150000
1381 };
1382 u8 i;
1383
1384 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1385 if (rate == ht40[i]) {
1386 if (i == ARRAY_SIZE(ht40) - 1)
1387 /* last rate uses sgi */
1388 *sgi = true;
1389 else
1390 *sgi = false;
1391
1392 *mcs = i;
1393 return true;
1394 }
1395 }
1396
1397 return false;
1398}
1399
1400static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1401 u8 *mac, struct station_info *sinfo)
1402{
1403 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301404 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001405 long left;
1406 bool sgi;
1407 s32 rate;
1408 int ret;
1409 u8 mcs;
1410
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301411 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001412 return -ENOENT;
1413
1414 if (down_interruptible(&ar->sem))
1415 return -EBUSY;
1416
1417 set_bit(STATS_UPDATE_PEND, &ar->flag);
1418
1419 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1420
1421 if (ret != 0) {
1422 up(&ar->sem);
1423 return -EIO;
1424 }
1425
1426 left = wait_event_interruptible_timeout(ar->event_wq,
1427 !test_bit(STATS_UPDATE_PEND,
1428 &ar->flag),
1429 WMI_TIMEOUT);
1430
1431 up(&ar->sem);
1432
1433 if (left == 0)
1434 return -ETIMEDOUT;
1435 else if (left < 0)
1436 return left;
1437
1438 if (ar->target_stats.rx_byte) {
1439 sinfo->rx_bytes = ar->target_stats.rx_byte;
1440 sinfo->filled |= STATION_INFO_RX_BYTES;
1441 sinfo->rx_packets = ar->target_stats.rx_pkt;
1442 sinfo->filled |= STATION_INFO_RX_PACKETS;
1443 }
1444
1445 if (ar->target_stats.tx_byte) {
1446 sinfo->tx_bytes = ar->target_stats.tx_byte;
1447 sinfo->filled |= STATION_INFO_TX_BYTES;
1448 sinfo->tx_packets = ar->target_stats.tx_pkt;
1449 sinfo->filled |= STATION_INFO_TX_PACKETS;
1450 }
1451
1452 sinfo->signal = ar->target_stats.cs_rssi;
1453 sinfo->filled |= STATION_INFO_SIGNAL;
1454
1455 rate = ar->target_stats.tx_ucast_rate;
1456
1457 if (is_rate_legacy(rate)) {
1458 sinfo->txrate.legacy = rate / 100;
1459 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1460 if (sgi) {
1461 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1462 sinfo->txrate.mcs = mcs - 1;
1463 } else {
1464 sinfo->txrate.mcs = mcs;
1465 }
1466
1467 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1468 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1469 if (sgi) {
1470 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1471 sinfo->txrate.mcs = mcs - 1;
1472 } else {
1473 sinfo->txrate.mcs = mcs;
1474 }
1475
1476 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1477 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1478 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001479 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1480 "invalid rate from stats: %d\n", rate);
1481 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001482 return 0;
1483 }
1484
1485 sinfo->filled |= STATION_INFO_TX_BITRATE;
1486
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301487 if (test_bit(CONNECTED, &vif->flags) &&
1488 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301489 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001490 sinfo->filled |= STATION_INFO_BSS_PARAM;
1491 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301492 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1493 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001494 }
1495
Kalle Valobdcd8172011-07-18 00:22:30 +03001496 return 0;
1497}
1498
1499static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1500 struct cfg80211_pmksa *pmksa)
1501{
1502 struct ath6kl *ar = ath6kl_priv(netdev);
1503 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1504 pmksa->pmkid, true);
1505}
1506
1507static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1508 struct cfg80211_pmksa *pmksa)
1509{
1510 struct ath6kl *ar = ath6kl_priv(netdev);
1511 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1512 pmksa->pmkid, false);
1513}
1514
1515static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1516{
1517 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301518 struct ath6kl_vif *vif = netdev_priv(netdev);
1519
1520 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301521 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->bssid,
1522 NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001523 return 0;
1524}
1525
Kalle Valoabcb3442011-07-22 08:26:20 +03001526#ifdef CONFIG_PM
1527static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1528 struct cfg80211_wowlan *wow)
1529{
1530 struct ath6kl *ar = wiphy_priv(wiphy);
1531
1532 return ath6kl_hif_suspend(ar);
1533}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001534
1535static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1536{
1537 struct ath6kl *ar = wiphy_priv(wiphy);
1538
1539 return ath6kl_hif_resume(ar);
1540}
Kalle Valoabcb3442011-07-22 08:26:20 +03001541#endif
1542
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001543static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1544 struct ieee80211_channel *chan,
1545 enum nl80211_channel_type channel_type)
1546{
1547 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301548 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001549
1550 if (!ath6kl_cfg80211_ready(ar))
1551 return -EIO;
1552
1553 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1554 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301555 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001556
1557 return 0;
1558}
1559
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001560static bool ath6kl_is_p2p_ie(const u8 *pos)
1561{
1562 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1563 pos[2] == 0x50 && pos[3] == 0x6f &&
1564 pos[4] == 0x9a && pos[5] == 0x09;
1565}
1566
1567static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1568 size_t ies_len)
1569{
1570 const u8 *pos;
1571 u8 *buf = NULL;
1572 size_t len = 0;
1573 int ret;
1574
1575 /*
1576 * Filter out P2P IE(s) since they will be included depending on
1577 * the Probe Request frame in ath6kl_send_go_probe_resp().
1578 */
1579
1580 if (ies && ies_len) {
1581 buf = kmalloc(ies_len, GFP_KERNEL);
1582 if (buf == NULL)
1583 return -ENOMEM;
1584 pos = ies;
1585 while (pos + 1 < ies + ies_len) {
1586 if (pos + 2 + pos[1] > ies + ies_len)
1587 break;
1588 if (!ath6kl_is_p2p_ie(pos)) {
1589 memcpy(buf + len, pos, 2 + pos[1]);
1590 len += 2 + pos[1];
1591 }
1592 pos += 2 + pos[1];
1593 }
1594 }
1595
1596 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1597 buf, len);
1598 kfree(buf);
1599 return ret;
1600}
1601
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001602static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1603 struct beacon_parameters *info, bool add)
1604{
1605 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301606 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001607 struct ieee80211_mgmt *mgmt;
1608 u8 *ies;
1609 int ies_len;
1610 struct wmi_connect_cmd p;
1611 int res;
1612 int i;
1613
1614 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1615
1616 if (!ath6kl_cfg80211_ready(ar))
1617 return -EIO;
1618
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301619 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001620 return -EOPNOTSUPP;
1621
1622 if (info->beacon_ies) {
1623 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1624 info->beacon_ies,
1625 info->beacon_ies_len);
1626 if (res)
1627 return res;
1628 }
1629 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001630 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1631 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001632 if (res)
1633 return res;
1634 }
1635 if (info->assocresp_ies) {
1636 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1637 info->assocresp_ies,
1638 info->assocresp_ies_len);
1639 if (res)
1640 return res;
1641 }
1642
1643 if (!add)
1644 return 0;
1645
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001646 ar->ap_mode_bkey.valid = false;
1647
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001648 /* TODO:
1649 * info->interval
1650 * info->dtim_period
1651 */
1652
1653 if (info->head == NULL)
1654 return -EINVAL;
1655 mgmt = (struct ieee80211_mgmt *) info->head;
1656 ies = mgmt->u.beacon.variable;
1657 if (ies > info->head + info->head_len)
1658 return -EINVAL;
1659 ies_len = info->head + info->head_len - ies;
1660
1661 if (info->ssid == NULL)
1662 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301663 memcpy(vif->ssid, info->ssid, info->ssid_len);
1664 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001665 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1666 return -EOPNOTSUPP; /* TODO */
1667
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301668 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001669
1670 memset(&p, 0, sizeof(p));
1671
1672 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1673 switch (info->crypto.akm_suites[i]) {
1674 case WLAN_AKM_SUITE_8021X:
1675 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1676 p.auth_mode |= WPA_AUTH;
1677 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1678 p.auth_mode |= WPA2_AUTH;
1679 break;
1680 case WLAN_AKM_SUITE_PSK:
1681 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1682 p.auth_mode |= WPA_PSK_AUTH;
1683 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1684 p.auth_mode |= WPA2_PSK_AUTH;
1685 break;
1686 }
1687 }
1688 if (p.auth_mode == 0)
1689 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301690 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001691
1692 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1693 switch (info->crypto.ciphers_pairwise[i]) {
1694 case WLAN_CIPHER_SUITE_WEP40:
1695 case WLAN_CIPHER_SUITE_WEP104:
1696 p.prwise_crypto_type |= WEP_CRYPT;
1697 break;
1698 case WLAN_CIPHER_SUITE_TKIP:
1699 p.prwise_crypto_type |= TKIP_CRYPT;
1700 break;
1701 case WLAN_CIPHER_SUITE_CCMP:
1702 p.prwise_crypto_type |= AES_CRYPT;
1703 break;
1704 }
1705 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001706 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001707 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001708 ath6kl_set_cipher(ar, 0, true);
1709 } else if (info->crypto.n_ciphers_pairwise == 1)
1710 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001711
1712 switch (info->crypto.cipher_group) {
1713 case WLAN_CIPHER_SUITE_WEP40:
1714 case WLAN_CIPHER_SUITE_WEP104:
1715 p.grp_crypto_type = WEP_CRYPT;
1716 break;
1717 case WLAN_CIPHER_SUITE_TKIP:
1718 p.grp_crypto_type = TKIP_CRYPT;
1719 break;
1720 case WLAN_CIPHER_SUITE_CCMP:
1721 p.grp_crypto_type = AES_CRYPT;
1722 break;
1723 default:
1724 p.grp_crypto_type = NONE_CRYPT;
1725 break;
1726 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001727 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001728
1729 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301730 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001731
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301732 p.ssid_len = vif->ssid_len;
1733 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1734 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301735 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001736
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001737 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1738 if (res < 0)
1739 return res;
1740
1741 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001742}
1743
1744static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1745 struct beacon_parameters *info)
1746{
1747 return ath6kl_ap_beacon(wiphy, dev, info, true);
1748}
1749
1750static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1751 struct beacon_parameters *info)
1752{
1753 return ath6kl_ap_beacon(wiphy, dev, info, false);
1754}
1755
1756static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1757{
1758 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301759 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001760
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301761 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001762 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301763 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001764 return -ENOTCONN;
1765
1766 ath6kl_wmi_disconnect_cmd(ar->wmi);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301767 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001768
1769 return 0;
1770}
1771
Jouni Malinen23875132011-08-30 21:57:53 +03001772static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1773 u8 *mac, struct station_parameters *params)
1774{
1775 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301776 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001777
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301778 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001779 return -EOPNOTSUPP;
1780
1781 /* Use this only for authorizing/unauthorizing a station */
1782 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1783 return -EOPNOTSUPP;
1784
1785 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1786 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1787 mac, 0);
1788 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1789 0);
1790}
1791
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001792static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1793 struct net_device *dev,
1794 struct ieee80211_channel *chan,
1795 enum nl80211_channel_type channel_type,
1796 unsigned int duration,
1797 u64 *cookie)
1798{
1799 struct ath6kl *ar = ath6kl_priv(dev);
1800
1801 /* TODO: if already pending or ongoing remain-on-channel,
1802 * return -EBUSY */
1803 *cookie = 1; /* only a single pending request is supported */
1804
1805 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1806 duration);
1807}
1808
1809static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1810 struct net_device *dev,
1811 u64 cookie)
1812{
1813 struct ath6kl *ar = ath6kl_priv(dev);
1814
1815 if (cookie != 1)
1816 return -ENOENT;
1817
1818 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1819}
1820
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001821static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1822 size_t len, unsigned int freq)
1823{
1824 const u8 *pos;
1825 u8 *p2p;
1826 int p2p_len;
1827 int ret;
1828 const struct ieee80211_mgmt *mgmt;
1829
1830 mgmt = (const struct ieee80211_mgmt *) buf;
1831
1832 /* Include P2P IE(s) from the frame generated in user space. */
1833
1834 p2p = kmalloc(len, GFP_KERNEL);
1835 if (p2p == NULL)
1836 return -ENOMEM;
1837 p2p_len = 0;
1838
1839 pos = mgmt->u.probe_resp.variable;
1840 while (pos + 1 < buf + len) {
1841 if (pos + 2 + pos[1] > buf + len)
1842 break;
1843 if (ath6kl_is_p2p_ie(pos)) {
1844 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1845 p2p_len += 2 + pos[1];
1846 }
1847 pos += 2 + pos[1];
1848 }
1849
1850 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1851 p2p, p2p_len);
1852 kfree(p2p);
1853 return ret;
1854}
1855
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001856static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1857 struct ieee80211_channel *chan, bool offchan,
1858 enum nl80211_channel_type channel_type,
1859 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001860 const u8 *buf, size_t len, bool no_cck,
1861 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001862{
1863 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301864 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001865 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001866 const struct ieee80211_mgmt *mgmt;
1867
1868 mgmt = (const struct ieee80211_mgmt *) buf;
1869 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301870 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001871 ieee80211_is_probe_resp(mgmt->frame_control)) {
1872 /*
1873 * Send Probe Response frame in AP mode using a separate WMI
1874 * command to allow the target to fill in the generic IEs.
1875 */
1876 *cookie = 0; /* TX status not supported */
1877 return ath6kl_send_go_probe_resp(ar, buf, len,
1878 chan->center_freq);
1879 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001880
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301881 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001882 if (id == 0) {
1883 /*
1884 * 0 is a reserved value in the WMI command and shall not be
1885 * used for the command.
1886 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301887 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001888 }
1889
1890 *cookie = id;
1891 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1892 buf, len);
1893}
1894
Jouni Malinenae32c302011-08-30 21:58:01 +03001895static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1896 struct net_device *dev,
1897 u16 frame_type, bool reg)
1898{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301899 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03001900
1901 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1902 __func__, frame_type, reg);
1903 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1904 /*
1905 * Note: This notification callback is not allowed to sleep, so
1906 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1907 * hardcode target to report Probe Request frames all the time.
1908 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301909 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03001910 }
1911}
1912
Jouni Malinenf80574a2011-08-30 21:58:04 +03001913static const struct ieee80211_txrx_stypes
1914ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1915 [NL80211_IFTYPE_STATION] = {
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_CLIENT] = {
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 [NL80211_IFTYPE_P2P_GO] = {
1928 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1929 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1930 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1931 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1932 },
1933};
1934
Kalle Valobdcd8172011-07-18 00:22:30 +03001935static struct cfg80211_ops ath6kl_cfg80211_ops = {
1936 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1937 .scan = ath6kl_cfg80211_scan,
1938 .connect = ath6kl_cfg80211_connect,
1939 .disconnect = ath6kl_cfg80211_disconnect,
1940 .add_key = ath6kl_cfg80211_add_key,
1941 .get_key = ath6kl_cfg80211_get_key,
1942 .del_key = ath6kl_cfg80211_del_key,
1943 .set_default_key = ath6kl_cfg80211_set_default_key,
1944 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1945 .set_tx_power = ath6kl_cfg80211_set_txpower,
1946 .get_tx_power = ath6kl_cfg80211_get_txpower,
1947 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1948 .join_ibss = ath6kl_cfg80211_join_ibss,
1949 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1950 .get_station = ath6kl_get_station,
1951 .set_pmksa = ath6kl_set_pmksa,
1952 .del_pmksa = ath6kl_del_pmksa,
1953 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001954 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001955#ifdef CONFIG_PM
1956 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001957 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001958#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001959 .set_channel = ath6kl_set_channel,
1960 .add_beacon = ath6kl_add_beacon,
1961 .set_beacon = ath6kl_set_beacon,
1962 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001963 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001964 .remain_on_channel = ath6kl_remain_on_channel,
1965 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001966 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001967 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001968};
1969
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301970struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001971{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001972 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301973 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301974 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001975
1976 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301977 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301978
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301979 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001980 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001981 return NULL;
1982 }
1983
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301984 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001985 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301986 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301987 ar->dev = dev;
1988
1989 spin_lock_init(&ar->lock);
1990 spin_lock_init(&ar->mcastpsq_lock);
1991
1992 init_waitqueue_head(&ar->event_wq);
1993 sema_init(&ar->sem, 1);
1994
1995 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1996
1997 clear_bit(WMI_ENABLED, &ar->flag);
1998 clear_bit(SKIP_SCAN, &ar->flag);
1999 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2000
2001 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2002 ar->listen_intvl_b = 0;
2003 ar->tx_pwr = 0;
2004
2005 ar->intra_bss = 1;
2006 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2007 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2008 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2009 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2010
2011 memset((u8 *)ar->sta_list, 0,
2012 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2013
2014 /* Init the PS queues */
2015 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2016 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2017 skb_queue_head_init(&ar->sta_list[ctr].psq);
2018 }
2019
2020 skb_queue_head_init(&ar->mcastpsq);
2021
2022 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2023
2024 return ar;
2025}
2026
2027int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2028{
2029 struct wiphy *wiphy = ar->wiphy;
2030 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002031
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302032 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002033
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302034 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002035
Kalle Valobdcd8172011-07-18 00:22:30 +03002036 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302037 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002038
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302039 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302040 BIT(NL80211_IFTYPE_ADHOC) |
2041 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002042 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302043 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302044 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002045 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302046
Kalle Valobdcd8172011-07-18 00:22:30 +03002047 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302048 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2049 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2050 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2051 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2052 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002053
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302054 wiphy->cipher_suites = cipher_suites;
2055 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002056
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302057 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002058 if (ret < 0) {
2059 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302060 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002061 }
2062
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302063 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002064}
2065
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302066static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002067{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302068 vif->aggr_cntxt = aggr_init(vif->ndev);
2069 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302070 ath6kl_err("failed to initialize aggr\n");
2071 return -ENOMEM;
2072 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002073
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302074 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302075 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302076 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302077
2078 return 0;
2079}
2080
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302081void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302082{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302083 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302084
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302085 vif->aggr_cntxt = NULL;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302086
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302087 if (test_bit(NETDEV_REGISTERED, &vif->flags)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302088 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302089 clear_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302090 }
2091
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302092 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302093}
2094
2095struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
2096 enum nl80211_iftype type)
2097{
2098 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302099 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302100
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302101 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302102 if (!ndev)
2103 return NULL;
2104
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302105 vif = netdev_priv(ndev);
2106 ndev->ieee80211_ptr = &vif->wdev;
2107 vif->wdev.wiphy = ar->wiphy;
2108 vif->ar = ar;
2109 ar->vif = vif;
2110 vif->ndev = ndev;
2111 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2112 vif->wdev.netdev = ndev;
2113 vif->wdev.iftype = type;
2114 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302115 ar->net_dev = ndev;
2116
2117 init_netdev(ndev);
2118
2119 ath6kl_init_control_info(ar);
2120
2121 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302122 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302123 goto err;
2124
2125 if (register_netdev(ndev))
2126 goto err;
2127
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302128 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302129 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302130 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302131 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302132
2133 return ndev;
2134
2135err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302136 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302137
2138 return NULL;
2139}
2140
2141void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2142{
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302143 /* TODO: Findout vif */
2144 struct ath6kl_vif *vif = ar->vif;
2145
2146 if (vif->scan_req) {
2147 cfg80211_scan_done(vif->scan_req, true);
2148 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03002149 }
2150
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302151 wiphy_unregister(ar->wiphy);
2152 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002153}