blob: 803fb6367419aed87f1dedff7ee90ef1961db338 [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)) {
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
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
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))) {
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 */
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
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
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 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;
1492 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1493 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1494 }
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);
1548
1549 if (!ath6kl_cfg80211_ready(ar))
1550 return -EIO;
1551
1552 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1553 __func__, chan->center_freq, chan->hw_value);
1554 ar->next_chan = chan->center_freq;
1555
1556 return 0;
1557}
1558
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001559static bool ath6kl_is_p2p_ie(const u8 *pos)
1560{
1561 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1562 pos[2] == 0x50 && pos[3] == 0x6f &&
1563 pos[4] == 0x9a && pos[5] == 0x09;
1564}
1565
1566static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1567 size_t ies_len)
1568{
1569 const u8 *pos;
1570 u8 *buf = NULL;
1571 size_t len = 0;
1572 int ret;
1573
1574 /*
1575 * Filter out P2P IE(s) since they will be included depending on
1576 * the Probe Request frame in ath6kl_send_go_probe_resp().
1577 */
1578
1579 if (ies && ies_len) {
1580 buf = kmalloc(ies_len, GFP_KERNEL);
1581 if (buf == NULL)
1582 return -ENOMEM;
1583 pos = ies;
1584 while (pos + 1 < ies + ies_len) {
1585 if (pos + 2 + pos[1] > ies + ies_len)
1586 break;
1587 if (!ath6kl_is_p2p_ie(pos)) {
1588 memcpy(buf + len, pos, 2 + pos[1]);
1589 len += 2 + pos[1];
1590 }
1591 pos += 2 + pos[1];
1592 }
1593 }
1594
1595 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1596 buf, len);
1597 kfree(buf);
1598 return ret;
1599}
1600
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001601static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1602 struct beacon_parameters *info, bool add)
1603{
1604 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301605 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001606 struct ieee80211_mgmt *mgmt;
1607 u8 *ies;
1608 int ies_len;
1609 struct wmi_connect_cmd p;
1610 int res;
1611 int i;
1612
1613 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1614
1615 if (!ath6kl_cfg80211_ready(ar))
1616 return -EIO;
1617
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301618 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001619 return -EOPNOTSUPP;
1620
1621 if (info->beacon_ies) {
1622 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1623 info->beacon_ies,
1624 info->beacon_ies_len);
1625 if (res)
1626 return res;
1627 }
1628 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001629 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1630 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001631 if (res)
1632 return res;
1633 }
1634 if (info->assocresp_ies) {
1635 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1636 info->assocresp_ies,
1637 info->assocresp_ies_len);
1638 if (res)
1639 return res;
1640 }
1641
1642 if (!add)
1643 return 0;
1644
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001645 ar->ap_mode_bkey.valid = false;
1646
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001647 /* TODO:
1648 * info->interval
1649 * info->dtim_period
1650 */
1651
1652 if (info->head == NULL)
1653 return -EINVAL;
1654 mgmt = (struct ieee80211_mgmt *) info->head;
1655 ies = mgmt->u.beacon.variable;
1656 if (ies > info->head + info->head_len)
1657 return -EINVAL;
1658 ies_len = info->head + info->head_len - ies;
1659
1660 if (info->ssid == NULL)
1661 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301662 memcpy(vif->ssid, info->ssid, info->ssid_len);
1663 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001664 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1665 return -EOPNOTSUPP; /* TODO */
1666
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301667 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001668
1669 memset(&p, 0, sizeof(p));
1670
1671 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1672 switch (info->crypto.akm_suites[i]) {
1673 case WLAN_AKM_SUITE_8021X:
1674 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1675 p.auth_mode |= WPA_AUTH;
1676 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1677 p.auth_mode |= WPA2_AUTH;
1678 break;
1679 case WLAN_AKM_SUITE_PSK:
1680 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1681 p.auth_mode |= WPA_PSK_AUTH;
1682 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1683 p.auth_mode |= WPA2_PSK_AUTH;
1684 break;
1685 }
1686 }
1687 if (p.auth_mode == 0)
1688 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301689 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001690
1691 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1692 switch (info->crypto.ciphers_pairwise[i]) {
1693 case WLAN_CIPHER_SUITE_WEP40:
1694 case WLAN_CIPHER_SUITE_WEP104:
1695 p.prwise_crypto_type |= WEP_CRYPT;
1696 break;
1697 case WLAN_CIPHER_SUITE_TKIP:
1698 p.prwise_crypto_type |= TKIP_CRYPT;
1699 break;
1700 case WLAN_CIPHER_SUITE_CCMP:
1701 p.prwise_crypto_type |= AES_CRYPT;
1702 break;
1703 }
1704 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001705 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001706 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001707 ath6kl_set_cipher(ar, 0, true);
1708 } else if (info->crypto.n_ciphers_pairwise == 1)
1709 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001710
1711 switch (info->crypto.cipher_group) {
1712 case WLAN_CIPHER_SUITE_WEP40:
1713 case WLAN_CIPHER_SUITE_WEP104:
1714 p.grp_crypto_type = WEP_CRYPT;
1715 break;
1716 case WLAN_CIPHER_SUITE_TKIP:
1717 p.grp_crypto_type = TKIP_CRYPT;
1718 break;
1719 case WLAN_CIPHER_SUITE_CCMP:
1720 p.grp_crypto_type = AES_CRYPT;
1721 break;
1722 default:
1723 p.grp_crypto_type = NONE_CRYPT;
1724 break;
1725 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001726 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001727
1728 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301729 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001730
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301731 p.ssid_len = vif->ssid_len;
1732 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1733 p.dot11_auth_mode = vif->dot11_auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001734 p.ch = cpu_to_le16(ar->next_chan);
1735
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001736 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1737 if (res < 0)
1738 return res;
1739
1740 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001741}
1742
1743static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1744 struct beacon_parameters *info)
1745{
1746 return ath6kl_ap_beacon(wiphy, dev, info, true);
1747}
1748
1749static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1750 struct beacon_parameters *info)
1751{
1752 return ath6kl_ap_beacon(wiphy, dev, info, false);
1753}
1754
1755static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1756{
1757 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301758 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001759
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301760 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001761 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301762 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001763 return -ENOTCONN;
1764
1765 ath6kl_wmi_disconnect_cmd(ar->wmi);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301766 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001767
1768 return 0;
1769}
1770
Jouni Malinen23875132011-08-30 21:57:53 +03001771static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1772 u8 *mac, struct station_parameters *params)
1773{
1774 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301775 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001776
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301777 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001778 return -EOPNOTSUPP;
1779
1780 /* Use this only for authorizing/unauthorizing a station */
1781 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1782 return -EOPNOTSUPP;
1783
1784 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1785 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1786 mac, 0);
1787 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1788 0);
1789}
1790
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001791static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1792 struct net_device *dev,
1793 struct ieee80211_channel *chan,
1794 enum nl80211_channel_type channel_type,
1795 unsigned int duration,
1796 u64 *cookie)
1797{
1798 struct ath6kl *ar = ath6kl_priv(dev);
1799
1800 /* TODO: if already pending or ongoing remain-on-channel,
1801 * return -EBUSY */
1802 *cookie = 1; /* only a single pending request is supported */
1803
1804 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1805 duration);
1806}
1807
1808static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1809 struct net_device *dev,
1810 u64 cookie)
1811{
1812 struct ath6kl *ar = ath6kl_priv(dev);
1813
1814 if (cookie != 1)
1815 return -ENOENT;
1816
1817 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1818}
1819
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001820static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1821 size_t len, unsigned int freq)
1822{
1823 const u8 *pos;
1824 u8 *p2p;
1825 int p2p_len;
1826 int ret;
1827 const struct ieee80211_mgmt *mgmt;
1828
1829 mgmt = (const struct ieee80211_mgmt *) buf;
1830
1831 /* Include P2P IE(s) from the frame generated in user space. */
1832
1833 p2p = kmalloc(len, GFP_KERNEL);
1834 if (p2p == NULL)
1835 return -ENOMEM;
1836 p2p_len = 0;
1837
1838 pos = mgmt->u.probe_resp.variable;
1839 while (pos + 1 < buf + len) {
1840 if (pos + 2 + pos[1] > buf + len)
1841 break;
1842 if (ath6kl_is_p2p_ie(pos)) {
1843 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1844 p2p_len += 2 + pos[1];
1845 }
1846 pos += 2 + pos[1];
1847 }
1848
1849 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1850 p2p, p2p_len);
1851 kfree(p2p);
1852 return ret;
1853}
1854
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001855static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1856 struct ieee80211_channel *chan, bool offchan,
1857 enum nl80211_channel_type channel_type,
1858 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001859 const u8 *buf, size_t len, bool no_cck,
1860 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001861{
1862 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301863 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001864 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001865 const struct ieee80211_mgmt *mgmt;
1866
1867 mgmt = (const struct ieee80211_mgmt *) buf;
1868 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301869 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001870 ieee80211_is_probe_resp(mgmt->frame_control)) {
1871 /*
1872 * Send Probe Response frame in AP mode using a separate WMI
1873 * command to allow the target to fill in the generic IEs.
1874 */
1875 *cookie = 0; /* TX status not supported */
1876 return ath6kl_send_go_probe_resp(ar, buf, len,
1877 chan->center_freq);
1878 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001879
1880 id = ar->send_action_id++;
1881 if (id == 0) {
1882 /*
1883 * 0 is a reserved value in the WMI command and shall not be
1884 * used for the command.
1885 */
1886 id = ar->send_action_id++;
1887 }
1888
1889 *cookie = id;
1890 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1891 buf, len);
1892}
1893
Jouni Malinenae32c302011-08-30 21:58:01 +03001894static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1895 struct net_device *dev,
1896 u16 frame_type, bool reg)
1897{
1898 struct ath6kl *ar = ath6kl_priv(dev);
1899
1900 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1901 __func__, frame_type, reg);
1902 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1903 /*
1904 * Note: This notification callback is not allowed to sleep, so
1905 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1906 * hardcode target to report Probe Request frames all the time.
1907 */
1908 ar->probe_req_report = reg;
1909 }
1910}
1911
Jouni Malinenf80574a2011-08-30 21:58:04 +03001912static const struct ieee80211_txrx_stypes
1913ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1914 [NL80211_IFTYPE_STATION] = {
1915 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1916 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1917 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1918 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1919 },
1920 [NL80211_IFTYPE_P2P_CLIENT] = {
1921 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1922 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1923 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1924 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1925 },
1926 [NL80211_IFTYPE_P2P_GO] = {
1927 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1928 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1929 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1930 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1931 },
1932};
1933
Kalle Valobdcd8172011-07-18 00:22:30 +03001934static struct cfg80211_ops ath6kl_cfg80211_ops = {
1935 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1936 .scan = ath6kl_cfg80211_scan,
1937 .connect = ath6kl_cfg80211_connect,
1938 .disconnect = ath6kl_cfg80211_disconnect,
1939 .add_key = ath6kl_cfg80211_add_key,
1940 .get_key = ath6kl_cfg80211_get_key,
1941 .del_key = ath6kl_cfg80211_del_key,
1942 .set_default_key = ath6kl_cfg80211_set_default_key,
1943 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1944 .set_tx_power = ath6kl_cfg80211_set_txpower,
1945 .get_tx_power = ath6kl_cfg80211_get_txpower,
1946 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1947 .join_ibss = ath6kl_cfg80211_join_ibss,
1948 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1949 .get_station = ath6kl_get_station,
1950 .set_pmksa = ath6kl_set_pmksa,
1951 .del_pmksa = ath6kl_del_pmksa,
1952 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001953 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001954#ifdef CONFIG_PM
1955 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001956 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001957#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001958 .set_channel = ath6kl_set_channel,
1959 .add_beacon = ath6kl_add_beacon,
1960 .set_beacon = ath6kl_set_beacon,
1961 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001962 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001963 .remain_on_channel = ath6kl_remain_on_channel,
1964 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001965 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001966 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001967};
1968
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301969struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001970{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001971 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301972 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301973 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001974
1975 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301976 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301977
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301978 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001979 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001980 return NULL;
1981 }
1982
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301983 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001984 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301985 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301986 ar->dev = dev;
1987
1988 spin_lock_init(&ar->lock);
1989 spin_lock_init(&ar->mcastpsq_lock);
1990
1991 init_waitqueue_head(&ar->event_wq);
1992 sema_init(&ar->sem, 1);
1993
1994 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1995
1996 clear_bit(WMI_ENABLED, &ar->flag);
1997 clear_bit(SKIP_SCAN, &ar->flag);
1998 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
1999
2000 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2001 ar->listen_intvl_b = 0;
2002 ar->tx_pwr = 0;
2003
2004 ar->intra_bss = 1;
2005 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2006 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2007 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2008 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2009
2010 memset((u8 *)ar->sta_list, 0,
2011 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2012
2013 /* Init the PS queues */
2014 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2015 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2016 skb_queue_head_init(&ar->sta_list[ctr].psq);
2017 }
2018
2019 skb_queue_head_init(&ar->mcastpsq);
2020
2021 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2022
2023 return ar;
2024}
2025
2026int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2027{
2028 struct wiphy *wiphy = ar->wiphy;
2029 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002030
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302031 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002032
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302033 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002034
Kalle Valobdcd8172011-07-18 00:22:30 +03002035 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302036 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002037
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302038 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302039 BIT(NL80211_IFTYPE_ADHOC) |
2040 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002041 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302042 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302043 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002044 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302045
Kalle Valobdcd8172011-07-18 00:22:30 +03002046 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302047 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2048 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2049 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2050 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2051 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002052
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302053 wiphy->cipher_suites = cipher_suites;
2054 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002055
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302056 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002057 if (ret < 0) {
2058 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302059 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002060 }
2061
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302062 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002063}
2064
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302065static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002066{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302067 vif->aggr_cntxt = aggr_init(vif->ndev);
2068 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302069 ath6kl_err("failed to initialize aggr\n");
2070 return -ENOMEM;
2071 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002072
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302073 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302074 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302075 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302076
2077 return 0;
2078}
2079
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302080void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302081{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302082 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302083
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302084 vif->aggr_cntxt = NULL;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302085
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302086 if (test_bit(NETDEV_REGISTERED, &vif->flags)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302087 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302088 clear_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302089 }
2090
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302091 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302092}
2093
2094struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
2095 enum nl80211_iftype type)
2096{
2097 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302098 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302099
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302100 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302101 if (!ndev)
2102 return NULL;
2103
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302104 vif = netdev_priv(ndev);
2105 ndev->ieee80211_ptr = &vif->wdev;
2106 vif->wdev.wiphy = ar->wiphy;
2107 vif->ar = ar;
2108 ar->vif = vif;
2109 vif->ndev = ndev;
2110 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2111 vif->wdev.netdev = ndev;
2112 vif->wdev.iftype = type;
2113 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302114 ar->net_dev = ndev;
2115
2116 init_netdev(ndev);
2117
2118 ath6kl_init_control_info(ar);
2119
2120 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302121 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302122 goto err;
2123
2124 if (register_netdev(ndev))
2125 goto err;
2126
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302127 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302128 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302129 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302130 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302131
2132 return ndev;
2133
2134err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302135 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302136
2137 return NULL;
2138}
2139
2140void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2141{
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302142 /* TODO: Findout vif */
2143 struct ath6kl_vif *vif = ar->vif;
2144
2145 if (vif->scan_req) {
2146 cfg80211_scan_done(vif->scan_req, true);
2147 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03002148 }
2149
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302150 wiphy_unregister(ar->wiphy);
2151 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002152}