blob: 0bdd837d6121b3b1b500c15fb440ac36c94bc95f [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
124static int ath6kl_set_wpa_version(struct ath6kl *ar,
125 enum nl80211_wpa_versions wpa_version)
126{
127 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
128
129 if (!wpa_version) {
130 ar->auth_mode = NONE_AUTH;
131 } else if (wpa_version & NL80211_WPA_VERSION_2) {
132 ar->auth_mode = WPA2_AUTH;
133 } else if (wpa_version & NL80211_WPA_VERSION_1) {
134 ar->auth_mode = WPA_AUTH;
135 } else {
136 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
137 return -ENOTSUPP;
138 }
139
140 return 0;
141}
142
143static int ath6kl_set_auth_type(struct ath6kl *ar,
144 enum nl80211_auth_type auth_type)
145{
146
147 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
148
149 switch (auth_type) {
150 case NL80211_AUTHTYPE_OPEN_SYSTEM:
151 ar->dot11_auth_mode = OPEN_AUTH;
152 break;
153 case NL80211_AUTHTYPE_SHARED_KEY:
154 ar->dot11_auth_mode = SHARED_AUTH;
155 break;
156 case NL80211_AUTHTYPE_NETWORK_EAP:
157 ar->dot11_auth_mode = LEAP_AUTH;
158 break;
159
160 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530161 ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300162 break;
163
164 default:
165 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
166 return -ENOTSUPP;
167 }
168
169 return 0;
170}
171
172static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
173{
174 u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
Edward Lu38acde32011-08-30 21:58:06 +0300175 u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
176 &ar->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300177
178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
179 __func__, cipher, ucast);
180
181 switch (cipher) {
182 case 0:
183 /* our own hack to use value 0 as no crypto used */
184 *ar_cipher = NONE_CRYPT;
185 *ar_cipher_len = 0;
186 break;
187 case WLAN_CIPHER_SUITE_WEP40:
188 *ar_cipher = WEP_CRYPT;
189 *ar_cipher_len = 5;
190 break;
191 case WLAN_CIPHER_SUITE_WEP104:
192 *ar_cipher = WEP_CRYPT;
193 *ar_cipher_len = 13;
194 break;
195 case WLAN_CIPHER_SUITE_TKIP:
196 *ar_cipher = TKIP_CRYPT;
197 *ar_cipher_len = 0;
198 break;
199 case WLAN_CIPHER_SUITE_CCMP:
200 *ar_cipher = AES_CRYPT;
201 *ar_cipher_len = 0;
202 break;
203 default:
204 ath6kl_err("cipher 0x%x not supported\n", cipher);
205 return -ENOTSUPP;
206 }
207
208 return 0;
209}
210
211static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
212{
213 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
214
215 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
216 if (ar->auth_mode == WPA_AUTH)
217 ar->auth_mode = WPA_PSK_AUTH;
218 else if (ar->auth_mode == WPA2_AUTH)
219 ar->auth_mode = WPA2_PSK_AUTH;
220 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
221 ar->auth_mode = NONE_AUTH;
222 }
223}
224
225static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
226{
227 if (!test_bit(WMI_READY, &ar->flag)) {
228 ath6kl_err("wmi is not ready\n");
229 return false;
230 }
231
Raja Mani575b5f32011-07-19 19:27:33 +0530232 if (!test_bit(WLAN_ENABLED, &ar->flag)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300233 ath6kl_err("wlan disabled\n");
234 return false;
235 }
236
237 return true;
238}
239
240static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
241 struct cfg80211_connect_params *sme)
242{
243 struct ath6kl *ar = ath6kl_priv(dev);
244 int status;
245
246 ar->sme_state = SME_CONNECTING;
247
248 if (!ath6kl_cfg80211_ready(ar))
249 return -EIO;
250
251 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
252 ath6kl_err("destroy in progress\n");
253 return -EBUSY;
254 }
255
256 if (test_bit(SKIP_SCAN, &ar->flag) &&
257 ((sme->channel && sme->channel->center_freq == 0) ||
258 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
259 ath6kl_err("SkipScan: channel or bssid invalid\n");
260 return -EINVAL;
261 }
262
263 if (down_interruptible(&ar->sem)) {
264 ath6kl_err("busy, couldn't get access\n");
265 return -ERESTARTSYS;
266 }
267
268 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
269 ath6kl_err("busy, destroy in progress\n");
270 up(&ar->sem);
271 return -EBUSY;
272 }
273
274 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
275 /*
276 * sleep until the command queue drains
277 */
278 wait_event_interruptible_timeout(ar->event_wq,
279 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
280 WMI_TIMEOUT);
281 if (signal_pending(current)) {
282 ath6kl_err("cmd queue drain timeout\n");
283 up(&ar->sem);
284 return -EINTR;
285 }
286 }
287
288 if (test_bit(CONNECTED, &ar->flag) &&
289 ar->ssid_len == sme->ssid_len &&
290 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
291 ar->reconnect_flag = true;
292 status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
293 ar->ch_hint);
294
295 up(&ar->sem);
296 if (status) {
297 ath6kl_err("wmi_reconnect_cmd failed\n");
298 return -EIO;
299 }
300 return 0;
301 } else if (ar->ssid_len == sme->ssid_len &&
302 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
303 ath6kl_disconnect(ar);
304 }
305
306 memset(ar->ssid, 0, sizeof(ar->ssid));
307 ar->ssid_len = sme->ssid_len;
308 memcpy(ar->ssid, sme->ssid, sme->ssid_len);
309
310 if (sme->channel)
311 ar->ch_hint = sme->channel->center_freq;
312
313 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
314 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
315 memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
316
317 ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
318
319 status = ath6kl_set_auth_type(ar, sme->auth_type);
320 if (status) {
321 up(&ar->sem);
322 return status;
323 }
324
325 if (sme->crypto.n_ciphers_pairwise)
326 ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
327 else
328 ath6kl_set_cipher(ar, 0, true);
329
330 ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
331
332 if (sme->crypto.n_akm_suites)
333 ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
334
335 if ((sme->key_len) &&
336 (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
337 struct ath6kl_key *key = NULL;
338
339 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
340 sme->key_idx > WMI_MAX_KEY_INDEX) {
341 ath6kl_err("key index %d out of bounds\n",
342 sme->key_idx);
343 up(&ar->sem);
344 return -ENOENT;
345 }
346
347 key = &ar->keys[sme->key_idx];
348 key->key_len = sme->key_len;
349 memcpy(key->key, sme->key, key->key_len);
350 key->cipher = ar->prwise_crypto;
351 ar->def_txkey_index = sme->key_idx;
352
353 ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
354 ar->prwise_crypto,
355 GROUP_USAGE | TX_USAGE,
356 key->key_len,
357 NULL,
358 key->key, KEY_OP_INIT_VAL, NULL,
359 NO_SYNC_WMIFLAG);
360 }
361
362 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300363 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300364 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
365 ath6kl_err("couldn't set bss filtering\n");
366 up(&ar->sem);
367 return -EIO;
368 }
369 }
370
371 ar->nw_type = ar->next_mode;
372
373 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
374 "%s: connect called with authmode %d dot11 auth %d"
375 " PW crypto %d PW crypto len %d GRP crypto %d"
376 " GRP crypto len %d channel hint %u\n",
377 __func__,
378 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
379 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +0300380 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300381
382 ar->reconnect_flag = 0;
383 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
384 ar->dot11_auth_mode, ar->auth_mode,
385 ar->prwise_crypto,
386 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +0300387 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +0300388 ar->ssid_len, ar->ssid,
389 ar->req_bssid, ar->ch_hint,
390 ar->connect_ctrl_flags);
391
392 up(&ar->sem);
393
394 if (status == -EINVAL) {
395 memset(ar->ssid, 0, sizeof(ar->ssid));
396 ar->ssid_len = 0;
397 ath6kl_err("invalid request\n");
398 return -ENOENT;
399 } else if (status) {
400 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
401 return -EIO;
402 }
403
404 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
405 ((ar->auth_mode == WPA_PSK_AUTH)
406 || (ar->auth_mode == WPA2_PSK_AUTH))) {
407 mod_timer(&ar->disconnect_timer,
408 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
409 }
410
411 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
412 set_bit(CONNECT_PEND, &ar->flag);
413
414 return 0;
415}
416
Jouni Malinen01cac472011-09-19 19:14:59 +0300417static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
418 struct ieee80211_channel *chan,
419 const u8 *beacon_ie, size_t beacon_ie_len)
420{
421 struct cfg80211_bss *bss;
422 u8 *ie;
423
424 bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid,
425 ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
426 WLAN_CAPABILITY_ESS);
427 if (bss == NULL) {
428 /*
429 * Since cfg80211 may not yet know about the BSS,
430 * generate a partial entry until the first BSS info
431 * event becomes available.
432 *
433 * Prepend SSID element since it is not included in the Beacon
434 * IEs from the target.
435 */
436 ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
437 if (ie == NULL)
438 return -ENOMEM;
439 ie[0] = WLAN_EID_SSID;
440 ie[1] = ar->ssid_len;
441 memcpy(ie + 2, ar->ssid, ar->ssid_len);
442 memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
443 bss = cfg80211_inform_bss(ar->wdev->wiphy, chan,
444 bssid, 0, WLAN_CAPABILITY_ESS, 100,
445 ie, 2 + ar->ssid_len + beacon_ie_len,
446 0, GFP_KERNEL);
447 if (bss)
448 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
449 "%pM prior to indicating connect/roamed "
450 "event\n", bssid);
451 kfree(ie);
452 } else
453 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
454 "entry\n");
455
456 if (bss == NULL)
457 return -ENOMEM;
458
459 cfg80211_put_bss(bss);
460
461 return 0;
462}
463
Kalle Valobdcd8172011-07-18 00:22:30 +0300464void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
465 u8 *bssid, u16 listen_intvl,
466 u16 beacon_intvl,
467 enum network_type nw_type,
468 u8 beacon_ie_len, u8 assoc_req_len,
469 u8 assoc_resp_len, u8 *assoc_info)
470{
Jouni Malinen01cac472011-09-19 19:14:59 +0300471 struct ieee80211_channel *chan;
Kalle Valobdcd8172011-07-18 00:22:30 +0300472
473 /* capinfo + listen interval */
474 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
475
476 /* capinfo + status code + associd */
477 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
478
479 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
480 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
481 assoc_resp_ie_offset;
482
483 assoc_req_len -= assoc_req_ie_offset;
484 assoc_resp_len -= assoc_resp_ie_offset;
485
Kalle Valobdcd8172011-07-18 00:22:30 +0300486 if (nw_type & ADHOC_NETWORK) {
487 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
488 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
489 "%s: ath6k not in ibss mode\n", __func__);
490 return;
491 }
492 }
493
494 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300495 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
496 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300497 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
498 "%s: ath6k not in station mode\n", __func__);
499 return;
500 }
501 }
502
Jouni Malinen01cac472011-09-19 19:14:59 +0300503 chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300504
Kalle Valobdcd8172011-07-18 00:22:30 +0300505
506 if (nw_type & ADHOC_NETWORK) {
507 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
508 return;
509 }
510
Jouni Malinen01cac472011-09-19 19:14:59 +0300511 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
512 beacon_ie_len) < 0) {
513 ath6kl_err("could not add cfg80211 bss entry for "
514 "connect/roamed notification\n");
515 return;
516 }
517
Raja Mani9aa60352011-08-04 19:26:29 +0530518 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300519 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530520 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300521 cfg80211_connect_result(ar->net_dev, bssid,
522 assoc_req_ie, assoc_req_len,
523 assoc_resp_ie, assoc_resp_len,
524 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530525 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300526 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300527 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300528 assoc_req_ie, assoc_req_len,
529 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
530 }
531}
532
533static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
534 struct net_device *dev, u16 reason_code)
535{
536 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
537
538 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
539 reason_code);
540
541 if (!ath6kl_cfg80211_ready(ar))
542 return -EIO;
543
544 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
545 ath6kl_err("busy, destroy in progress\n");
546 return -EBUSY;
547 }
548
549 if (down_interruptible(&ar->sem)) {
550 ath6kl_err("busy, couldn't get access\n");
551 return -ERESTARTSYS;
552 }
553
554 ar->reconnect_flag = 0;
555 ath6kl_disconnect(ar);
556 memset(ar->ssid, 0, sizeof(ar->ssid));
557 ar->ssid_len = 0;
558
559 if (!test_bit(SKIP_SCAN, &ar->flag))
560 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
561
562 up(&ar->sem);
563
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530564 ar->sme_state = SME_DISCONNECTED;
565
Kalle Valobdcd8172011-07-18 00:22:30 +0300566 return 0;
567}
568
569void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
570 u8 *bssid, u8 assoc_resp_len,
571 u8 *assoc_info, u16 proto_reason)
572{
Kalle Valobdcd8172011-07-18 00:22:30 +0300573 if (ar->scan_req) {
574 cfg80211_scan_done(ar->scan_req, true);
575 ar->scan_req = NULL;
576 }
577
578 if (ar->nw_type & ADHOC_NETWORK) {
579 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
580 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
581 "%s: ath6k not in ibss mode\n", __func__);
582 return;
583 }
584 memset(bssid, 0, ETH_ALEN);
585 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
586 return;
587 }
588
589 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300590 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
591 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300592 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
593 "%s: ath6k not in station mode\n", __func__);
594 return;
595 }
596 }
597
598 if (!test_bit(CONNECT_PEND, &ar->flag)) {
599 if (reason != DISCONNECT_CMD)
600 ath6kl_wmi_disconnect_cmd(ar->wmi);
601
602 return;
603 }
604
605 if (reason == NO_NETWORK_AVAIL) {
606 /* connect cmd failed */
607 ath6kl_wmi_disconnect_cmd(ar->wmi);
608 return;
609 }
610
611 if (reason != DISCONNECT_CMD)
612 return;
613
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530614 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300615
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530616 if (ar->sme_state == SME_CONNECTING) {
617 cfg80211_connect_result(ar->net_dev,
618 bssid, NULL, 0,
619 NULL, 0,
620 WLAN_STATUS_UNSPECIFIED_FAILURE,
621 GFP_KERNEL);
622 } else if (ar->sme_state == SME_CONNECTED) {
623 cfg80211_disconnected(ar->net_dev, reason,
624 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300625 }
626
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530627 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300628}
629
Kalle Valobdcd8172011-07-18 00:22:30 +0300630static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
631 struct cfg80211_scan_request *request)
632{
633 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300634 s8 n_channels = 0;
635 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300636 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300637
638 if (!ath6kl_cfg80211_ready(ar))
639 return -EIO;
640
641 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300642 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300643 ret = ath6kl_wmi_bssfilter_cmd(
644 ar->wmi,
645 (test_bit(CONNECTED, &ar->flag) ?
646 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
647 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300648 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300649 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300650 }
651 }
652
653 if (request->n_ssids && request->ssids[0].ssid_len) {
654 u8 i;
655
656 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
657 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
658
659 for (i = 0; i < request->n_ssids; i++)
660 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
661 SPECIFIC_SSID_FLAG,
662 request->ssids[i].ssid_len,
663 request->ssids[i].ssid);
664 }
665
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300666 if (request->ie) {
667 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
668 request->ie, request->ie_len);
669 if (ret) {
670 ath6kl_err("failed to set Probe Request appie for "
671 "scan");
672 return ret;
673 }
674 }
675
Jouni Malinen11869be2011-09-02 20:07:06 +0300676 /*
677 * Scan only the requested channels if the request specifies a set of
678 * channels. If the list is longer than the target supports, do not
679 * configure the list and instead, scan all available channels.
680 */
681 if (request->n_channels > 0 &&
682 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300683 u8 i;
684
Jouni Malinen11869be2011-09-02 20:07:06 +0300685 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300686
687 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
688 if (channels == NULL) {
689 ath6kl_warn("failed to set scan channels, "
690 "scan all channels");
691 n_channels = 0;
692 }
693
694 for (i = 0; i < n_channels; i++)
695 channels[i] = request->channels[i]->center_freq;
696 }
697
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300698 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
699 false, 0, 0, n_channels, channels);
700 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300701 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300702 else
703 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300704
Edward Lu1276c9e2011-08-30 21:58:00 +0300705 kfree(channels);
706
Kalle Valobdcd8172011-07-18 00:22:30 +0300707 return ret;
708}
709
710void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
711{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300712 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300713
714 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
715
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300716 if (!ar->scan_req)
717 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300718
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300719 if ((status == -ECANCELED) || (status == -EBUSY)) {
720 cfg80211_scan_done(ar->scan_req, true);
721 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300722 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300723
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300724 cfg80211_scan_done(ar->scan_req, false);
725
726 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
727 for (i = 0; i < ar->scan_req->n_ssids; i++) {
728 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
729 DISABLE_SSID_FLAG,
730 0, NULL);
731 }
732 }
733
734out:
735 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300736}
737
738static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
739 u8 key_index, bool pairwise,
740 const u8 *mac_addr,
741 struct key_params *params)
742{
743 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
744 struct ath6kl_key *key = NULL;
745 u8 key_usage;
746 u8 key_type;
747 int status = 0;
748
749 if (!ath6kl_cfg80211_ready(ar))
750 return -EIO;
751
752 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
753 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
754 "%s: key index %d out of bounds\n", __func__,
755 key_index);
756 return -ENOENT;
757 }
758
759 key = &ar->keys[key_index];
760 memset(key, 0, sizeof(struct ath6kl_key));
761
762 if (pairwise)
763 key_usage = PAIRWISE_USAGE;
764 else
765 key_usage = GROUP_USAGE;
766
767 if (params) {
768 if (params->key_len > WLAN_MAX_KEY_LEN ||
769 params->seq_len > sizeof(key->seq))
770 return -EINVAL;
771
772 key->key_len = params->key_len;
773 memcpy(key->key, params->key, key->key_len);
774 key->seq_len = params->seq_len;
775 memcpy(key->seq, params->seq, key->seq_len);
776 key->cipher = params->cipher;
777 }
778
779 switch (key->cipher) {
780 case WLAN_CIPHER_SUITE_WEP40:
781 case WLAN_CIPHER_SUITE_WEP104:
782 key_type = WEP_CRYPT;
783 break;
784
785 case WLAN_CIPHER_SUITE_TKIP:
786 key_type = TKIP_CRYPT;
787 break;
788
789 case WLAN_CIPHER_SUITE_CCMP:
790 key_type = AES_CRYPT;
791 break;
792
793 default:
794 return -ENOTSUPP;
795 }
796
797 if (((ar->auth_mode == WPA_PSK_AUTH)
798 || (ar->auth_mode == WPA2_PSK_AUTH))
799 && (key_usage & GROUP_USAGE))
800 del_timer(&ar->disconnect_timer);
801
802 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
803 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
804 __func__, key_index, key->key_len, key_type,
805 key_usage, key->seq_len);
806
807 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300808
809 if (ar->nw_type == AP_NETWORK && !pairwise &&
810 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
811 ar->ap_mode_bkey.valid = true;
812 ar->ap_mode_bkey.key_index = key_index;
813 ar->ap_mode_bkey.key_type = key_type;
814 ar->ap_mode_bkey.key_len = key->key_len;
815 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
816 if (!test_bit(CONNECTED, &ar->flag)) {
817 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
818 "key configuration until AP mode has been "
819 "started\n");
820 /*
821 * The key will be set in ath6kl_connect_ap_mode() once
822 * the connected event is received from the target.
823 */
824 return 0;
825 }
826 }
827
Jouni Malinen151411e2011-09-15 15:10:16 +0300828 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
829 !test_bit(CONNECTED, &ar->flag)) {
830 /*
831 * Store the key locally so that it can be re-configured after
832 * the AP mode has properly started
833 * (ath6kl_install_statioc_wep_keys).
834 */
835 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
836 "until AP mode has been started\n");
837 ar->wep_key_list[key_index].key_len = key->key_len;
838 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
839 return 0;
840 }
841
Kalle Valobdcd8172011-07-18 00:22:30 +0300842 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
843 key_type, key_usage, key->key_len,
844 key->seq, key->key, KEY_OP_INIT_VAL,
845 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
846
847 if (status)
848 return -EIO;
849
850 return 0;
851}
852
853static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
854 u8 key_index, bool pairwise,
855 const u8 *mac_addr)
856{
857 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
858
859 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
860
861 if (!ath6kl_cfg80211_ready(ar))
862 return -EIO;
863
864 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
865 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
866 "%s: key index %d out of bounds\n", __func__,
867 key_index);
868 return -ENOENT;
869 }
870
871 if (!ar->keys[key_index].key_len) {
872 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
873 "%s: index %d is empty\n", __func__, key_index);
874 return 0;
875 }
876
877 ar->keys[key_index].key_len = 0;
878
879 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
880}
881
882static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
883 u8 key_index, bool pairwise,
884 const u8 *mac_addr, void *cookie,
885 void (*callback) (void *cookie,
886 struct key_params *))
887{
888 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
889 struct ath6kl_key *key = NULL;
890 struct key_params params;
891
892 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
893
894 if (!ath6kl_cfg80211_ready(ar))
895 return -EIO;
896
897 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
898 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
899 "%s: key index %d out of bounds\n", __func__,
900 key_index);
901 return -ENOENT;
902 }
903
904 key = &ar->keys[key_index];
905 memset(&params, 0, sizeof(params));
906 params.cipher = key->cipher;
907 params.key_len = key->key_len;
908 params.seq_len = key->seq_len;
909 params.seq = key->seq;
910 params.key = key->key;
911
912 callback(cookie, &params);
913
914 return key->key_len ? 0 : -ENOENT;
915}
916
917static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
918 struct net_device *ndev,
919 u8 key_index, bool unicast,
920 bool multicast)
921{
922 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
923 struct ath6kl_key *key = NULL;
924 int status = 0;
925 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300926 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300927
928 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
929
930 if (!ath6kl_cfg80211_ready(ar))
931 return -EIO;
932
933 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
934 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
935 "%s: key index %d out of bounds\n",
936 __func__, key_index);
937 return -ENOENT;
938 }
939
940 if (!ar->keys[key_index].key_len) {
941 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
942 __func__, key_index);
943 return -EINVAL;
944 }
945
946 ar->def_txkey_index = key_index;
947 key = &ar->keys[ar->def_txkey_index];
948 key_usage = GROUP_USAGE;
949 if (ar->prwise_crypto == WEP_CRYPT)
950 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +0300951 if (unicast)
952 key_type = ar->prwise_crypto;
953 if (multicast)
954 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +0300955
Jouni Malinen151411e2011-09-15 15:10:16 +0300956 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300957 return 0; /* Delay until AP mode has been started */
958
Kalle Valobdcd8172011-07-18 00:22:30 +0300959 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +0300960 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +0300961 key->key_len, key->seq, key->key,
962 KEY_OP_INIT_VAL, NULL,
963 SYNC_BOTH_WMIFLAG);
964 if (status)
965 return -EIO;
966
967 return 0;
968}
969
970void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
971 bool ismcast)
972{
973 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
974 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
975
976 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
977 (ismcast ? NL80211_KEYTYPE_GROUP :
978 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
979 GFP_KERNEL);
980}
981
982static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
983{
984 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
985 int ret;
986
987 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
988 changed);
989
990 if (!ath6kl_cfg80211_ready(ar))
991 return -EIO;
992
993 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
994 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
995 if (ret != 0) {
996 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
997 return -EIO;
998 }
999 }
1000
1001 return 0;
1002}
1003
1004/*
1005 * The type nl80211_tx_power_setting replaces the following
1006 * data type from 2.6.36 onwards
1007*/
1008static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1009 enum nl80211_tx_power_setting type,
1010 int dbm)
1011{
1012 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1013 u8 ath6kl_dbm;
1014
1015 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1016 type, dbm);
1017
1018 if (!ath6kl_cfg80211_ready(ar))
1019 return -EIO;
1020
1021 switch (type) {
1022 case NL80211_TX_POWER_AUTOMATIC:
1023 return 0;
1024 case NL80211_TX_POWER_LIMITED:
1025 ar->tx_pwr = ath6kl_dbm = dbm;
1026 break;
1027 default:
1028 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1029 __func__, type);
1030 return -EOPNOTSUPP;
1031 }
1032
1033 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1034
1035 return 0;
1036}
1037
1038static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1039{
1040 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1041
1042 if (!ath6kl_cfg80211_ready(ar))
1043 return -EIO;
1044
1045 if (test_bit(CONNECTED, &ar->flag)) {
1046 ar->tx_pwr = 0;
1047
1048 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1049 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1050 return -EIO;
1051 }
1052
1053 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1054 5 * HZ);
1055
1056 if (signal_pending(current)) {
1057 ath6kl_err("target did not respond\n");
1058 return -EINTR;
1059 }
1060 }
1061
1062 *dbm = ar->tx_pwr;
1063 return 0;
1064}
1065
1066static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1067 struct net_device *dev,
1068 bool pmgmt, int timeout)
1069{
1070 struct ath6kl *ar = ath6kl_priv(dev);
1071 struct wmi_power_mode_cmd mode;
1072
1073 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1074 __func__, pmgmt, timeout);
1075
1076 if (!ath6kl_cfg80211_ready(ar))
1077 return -EIO;
1078
1079 if (pmgmt) {
1080 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1081 mode.pwr_mode = REC_POWER;
1082 } else {
1083 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1084 mode.pwr_mode = MAX_PERF_POWER;
1085 }
1086
1087 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1088 ath6kl_err("wmi_powermode_cmd failed\n");
1089 return -EIO;
1090 }
1091
1092 return 0;
1093}
1094
1095static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1096 struct net_device *ndev,
1097 enum nl80211_iftype type, u32 *flags,
1098 struct vif_params *params)
1099{
1100 struct ath6kl *ar = ath6kl_priv(ndev);
1101 struct wireless_dev *wdev = ar->wdev;
1102
1103 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1104
1105 if (!ath6kl_cfg80211_ready(ar))
1106 return -EIO;
1107
1108 switch (type) {
1109 case NL80211_IFTYPE_STATION:
1110 ar->next_mode = INFRA_NETWORK;
1111 break;
1112 case NL80211_IFTYPE_ADHOC:
1113 ar->next_mode = ADHOC_NETWORK;
1114 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001115 case NL80211_IFTYPE_AP:
1116 ar->next_mode = AP_NETWORK;
1117 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001118 case NL80211_IFTYPE_P2P_CLIENT:
1119 ar->next_mode = INFRA_NETWORK;
1120 break;
1121 case NL80211_IFTYPE_P2P_GO:
1122 ar->next_mode = AP_NETWORK;
1123 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001124 default:
1125 ath6kl_err("invalid interface type %u\n", type);
1126 return -EOPNOTSUPP;
1127 }
1128
1129 wdev->iftype = type;
1130
1131 return 0;
1132}
1133
1134static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1135 struct net_device *dev,
1136 struct cfg80211_ibss_params *ibss_param)
1137{
1138 struct ath6kl *ar = ath6kl_priv(dev);
1139 int status;
1140
1141 if (!ath6kl_cfg80211_ready(ar))
1142 return -EIO;
1143
1144 ar->ssid_len = ibss_param->ssid_len;
1145 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1146
1147 if (ibss_param->channel)
1148 ar->ch_hint = ibss_param->channel->center_freq;
1149
1150 if (ibss_param->channel_fixed) {
1151 /*
1152 * TODO: channel_fixed: The channel should be fixed, do not
1153 * search for IBSSs to join on other channels. Target
1154 * firmware does not support this feature, needs to be
1155 * updated.
1156 */
1157 return -EOPNOTSUPP;
1158 }
1159
1160 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1161 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1162 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1163
1164 ath6kl_set_wpa_version(ar, 0);
1165
1166 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1167 if (status)
1168 return status;
1169
1170 if (ibss_param->privacy) {
1171 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1172 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1173 } else {
1174 ath6kl_set_cipher(ar, 0, true);
1175 ath6kl_set_cipher(ar, 0, false);
1176 }
1177
1178 ar->nw_type = ar->next_mode;
1179
1180 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1181 "%s: connect called with authmode %d dot11 auth %d"
1182 " PW crypto %d PW crypto len %d GRP crypto %d"
1183 " GRP crypto len %d channel hint %u\n",
1184 __func__,
1185 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1186 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001187 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001188
1189 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1190 ar->dot11_auth_mode, ar->auth_mode,
1191 ar->prwise_crypto,
1192 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001193 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001194 ar->ssid_len, ar->ssid,
1195 ar->req_bssid, ar->ch_hint,
1196 ar->connect_ctrl_flags);
1197 set_bit(CONNECT_PEND, &ar->flag);
1198
1199 return 0;
1200}
1201
1202static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1203 struct net_device *dev)
1204{
1205 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1206
1207 if (!ath6kl_cfg80211_ready(ar))
1208 return -EIO;
1209
1210 ath6kl_disconnect(ar);
1211 memset(ar->ssid, 0, sizeof(ar->ssid));
1212 ar->ssid_len = 0;
1213
1214 return 0;
1215}
1216
1217static const u32 cipher_suites[] = {
1218 WLAN_CIPHER_SUITE_WEP40,
1219 WLAN_CIPHER_SUITE_WEP104,
1220 WLAN_CIPHER_SUITE_TKIP,
1221 WLAN_CIPHER_SUITE_CCMP,
1222};
1223
1224static bool is_rate_legacy(s32 rate)
1225{
1226 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1227 6000, 9000, 12000, 18000, 24000,
1228 36000, 48000, 54000
1229 };
1230 u8 i;
1231
1232 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1233 if (rate == legacy[i])
1234 return true;
1235
1236 return false;
1237}
1238
1239static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1240{
1241 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1242 52000, 58500, 65000, 72200
1243 };
1244 u8 i;
1245
1246 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1247 if (rate == ht20[i]) {
1248 if (i == ARRAY_SIZE(ht20) - 1)
1249 /* last rate uses sgi */
1250 *sgi = true;
1251 else
1252 *sgi = false;
1253
1254 *mcs = i;
1255 return true;
1256 }
1257 }
1258 return false;
1259}
1260
1261static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1262{
1263 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1264 81000, 108000, 121500, 135000,
1265 150000
1266 };
1267 u8 i;
1268
1269 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1270 if (rate == ht40[i]) {
1271 if (i == ARRAY_SIZE(ht40) - 1)
1272 /* last rate uses sgi */
1273 *sgi = true;
1274 else
1275 *sgi = false;
1276
1277 *mcs = i;
1278 return true;
1279 }
1280 }
1281
1282 return false;
1283}
1284
1285static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1286 u8 *mac, struct station_info *sinfo)
1287{
1288 struct ath6kl *ar = ath6kl_priv(dev);
1289 long left;
1290 bool sgi;
1291 s32 rate;
1292 int ret;
1293 u8 mcs;
1294
1295 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1296 return -ENOENT;
1297
1298 if (down_interruptible(&ar->sem))
1299 return -EBUSY;
1300
1301 set_bit(STATS_UPDATE_PEND, &ar->flag);
1302
1303 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1304
1305 if (ret != 0) {
1306 up(&ar->sem);
1307 return -EIO;
1308 }
1309
1310 left = wait_event_interruptible_timeout(ar->event_wq,
1311 !test_bit(STATS_UPDATE_PEND,
1312 &ar->flag),
1313 WMI_TIMEOUT);
1314
1315 up(&ar->sem);
1316
1317 if (left == 0)
1318 return -ETIMEDOUT;
1319 else if (left < 0)
1320 return left;
1321
1322 if (ar->target_stats.rx_byte) {
1323 sinfo->rx_bytes = ar->target_stats.rx_byte;
1324 sinfo->filled |= STATION_INFO_RX_BYTES;
1325 sinfo->rx_packets = ar->target_stats.rx_pkt;
1326 sinfo->filled |= STATION_INFO_RX_PACKETS;
1327 }
1328
1329 if (ar->target_stats.tx_byte) {
1330 sinfo->tx_bytes = ar->target_stats.tx_byte;
1331 sinfo->filled |= STATION_INFO_TX_BYTES;
1332 sinfo->tx_packets = ar->target_stats.tx_pkt;
1333 sinfo->filled |= STATION_INFO_TX_PACKETS;
1334 }
1335
1336 sinfo->signal = ar->target_stats.cs_rssi;
1337 sinfo->filled |= STATION_INFO_SIGNAL;
1338
1339 rate = ar->target_stats.tx_ucast_rate;
1340
1341 if (is_rate_legacy(rate)) {
1342 sinfo->txrate.legacy = rate / 100;
1343 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1344 if (sgi) {
1345 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1346 sinfo->txrate.mcs = mcs - 1;
1347 } else {
1348 sinfo->txrate.mcs = mcs;
1349 }
1350
1351 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1352 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1353 if (sgi) {
1354 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1355 sinfo->txrate.mcs = mcs - 1;
1356 } else {
1357 sinfo->txrate.mcs = mcs;
1358 }
1359
1360 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1361 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1362 } else {
1363 ath6kl_warn("invalid rate: %d\n", rate);
1364 return 0;
1365 }
1366
1367 sinfo->filled |= STATION_INFO_TX_BITRATE;
1368
1369 return 0;
1370}
1371
1372static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1373 struct cfg80211_pmksa *pmksa)
1374{
1375 struct ath6kl *ar = ath6kl_priv(netdev);
1376 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1377 pmksa->pmkid, true);
1378}
1379
1380static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1381 struct cfg80211_pmksa *pmksa)
1382{
1383 struct ath6kl *ar = ath6kl_priv(netdev);
1384 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1385 pmksa->pmkid, false);
1386}
1387
1388static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1389{
1390 struct ath6kl *ar = ath6kl_priv(netdev);
1391 if (test_bit(CONNECTED, &ar->flag))
1392 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1393 return 0;
1394}
1395
Kalle Valoabcb3442011-07-22 08:26:20 +03001396#ifdef CONFIG_PM
1397static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1398 struct cfg80211_wowlan *wow)
1399{
1400 struct ath6kl *ar = wiphy_priv(wiphy);
1401
1402 return ath6kl_hif_suspend(ar);
1403}
1404#endif
1405
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001406static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1407 struct ieee80211_channel *chan,
1408 enum nl80211_channel_type channel_type)
1409{
1410 struct ath6kl *ar = ath6kl_priv(dev);
1411
1412 if (!ath6kl_cfg80211_ready(ar))
1413 return -EIO;
1414
1415 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1416 __func__, chan->center_freq, chan->hw_value);
1417 ar->next_chan = chan->center_freq;
1418
1419 return 0;
1420}
1421
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001422static bool ath6kl_is_p2p_ie(const u8 *pos)
1423{
1424 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1425 pos[2] == 0x50 && pos[3] == 0x6f &&
1426 pos[4] == 0x9a && pos[5] == 0x09;
1427}
1428
1429static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1430 size_t ies_len)
1431{
1432 const u8 *pos;
1433 u8 *buf = NULL;
1434 size_t len = 0;
1435 int ret;
1436
1437 /*
1438 * Filter out P2P IE(s) since they will be included depending on
1439 * the Probe Request frame in ath6kl_send_go_probe_resp().
1440 */
1441
1442 if (ies && ies_len) {
1443 buf = kmalloc(ies_len, GFP_KERNEL);
1444 if (buf == NULL)
1445 return -ENOMEM;
1446 pos = ies;
1447 while (pos + 1 < ies + ies_len) {
1448 if (pos + 2 + pos[1] > ies + ies_len)
1449 break;
1450 if (!ath6kl_is_p2p_ie(pos)) {
1451 memcpy(buf + len, pos, 2 + pos[1]);
1452 len += 2 + pos[1];
1453 }
1454 pos += 2 + pos[1];
1455 }
1456 }
1457
1458 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1459 buf, len);
1460 kfree(buf);
1461 return ret;
1462}
1463
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001464static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1465 struct beacon_parameters *info, bool add)
1466{
1467 struct ath6kl *ar = ath6kl_priv(dev);
1468 struct ieee80211_mgmt *mgmt;
1469 u8 *ies;
1470 int ies_len;
1471 struct wmi_connect_cmd p;
1472 int res;
1473 int i;
1474
1475 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1476
1477 if (!ath6kl_cfg80211_ready(ar))
1478 return -EIO;
1479
1480 if (ar->next_mode != AP_NETWORK)
1481 return -EOPNOTSUPP;
1482
1483 if (info->beacon_ies) {
1484 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1485 info->beacon_ies,
1486 info->beacon_ies_len);
1487 if (res)
1488 return res;
1489 }
1490 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001491 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1492 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001493 if (res)
1494 return res;
1495 }
1496 if (info->assocresp_ies) {
1497 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1498 info->assocresp_ies,
1499 info->assocresp_ies_len);
1500 if (res)
1501 return res;
1502 }
1503
1504 if (!add)
1505 return 0;
1506
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001507 ar->ap_mode_bkey.valid = false;
1508
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001509 /* TODO:
1510 * info->interval
1511 * info->dtim_period
1512 */
1513
1514 if (info->head == NULL)
1515 return -EINVAL;
1516 mgmt = (struct ieee80211_mgmt *) info->head;
1517 ies = mgmt->u.beacon.variable;
1518 if (ies > info->head + info->head_len)
1519 return -EINVAL;
1520 ies_len = info->head + info->head_len - ies;
1521
1522 if (info->ssid == NULL)
1523 return -EINVAL;
1524 memcpy(ar->ssid, info->ssid, info->ssid_len);
1525 ar->ssid_len = info->ssid_len;
1526 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1527 return -EOPNOTSUPP; /* TODO */
1528
1529 ar->dot11_auth_mode = OPEN_AUTH;
1530
1531 memset(&p, 0, sizeof(p));
1532
1533 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1534 switch (info->crypto.akm_suites[i]) {
1535 case WLAN_AKM_SUITE_8021X:
1536 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1537 p.auth_mode |= WPA_AUTH;
1538 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1539 p.auth_mode |= WPA2_AUTH;
1540 break;
1541 case WLAN_AKM_SUITE_PSK:
1542 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1543 p.auth_mode |= WPA_PSK_AUTH;
1544 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1545 p.auth_mode |= WPA2_PSK_AUTH;
1546 break;
1547 }
1548 }
1549 if (p.auth_mode == 0)
1550 p.auth_mode = NONE_AUTH;
1551 ar->auth_mode = p.auth_mode;
1552
1553 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1554 switch (info->crypto.ciphers_pairwise[i]) {
1555 case WLAN_CIPHER_SUITE_WEP40:
1556 case WLAN_CIPHER_SUITE_WEP104:
1557 p.prwise_crypto_type |= WEP_CRYPT;
1558 break;
1559 case WLAN_CIPHER_SUITE_TKIP:
1560 p.prwise_crypto_type |= TKIP_CRYPT;
1561 break;
1562 case WLAN_CIPHER_SUITE_CCMP:
1563 p.prwise_crypto_type |= AES_CRYPT;
1564 break;
1565 }
1566 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001567 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001568 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001569 ath6kl_set_cipher(ar, 0, true);
1570 } else if (info->crypto.n_ciphers_pairwise == 1)
1571 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001572
1573 switch (info->crypto.cipher_group) {
1574 case WLAN_CIPHER_SUITE_WEP40:
1575 case WLAN_CIPHER_SUITE_WEP104:
1576 p.grp_crypto_type = WEP_CRYPT;
1577 break;
1578 case WLAN_CIPHER_SUITE_TKIP:
1579 p.grp_crypto_type = TKIP_CRYPT;
1580 break;
1581 case WLAN_CIPHER_SUITE_CCMP:
1582 p.grp_crypto_type = AES_CRYPT;
1583 break;
1584 default:
1585 p.grp_crypto_type = NONE_CRYPT;
1586 break;
1587 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001588 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001589
1590 p.nw_type = AP_NETWORK;
1591 ar->nw_type = ar->next_mode;
1592
1593 p.ssid_len = ar->ssid_len;
1594 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1595 p.dot11_auth_mode = ar->dot11_auth_mode;
1596 p.ch = cpu_to_le16(ar->next_chan);
1597
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001598 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1599 if (res < 0)
1600 return res;
1601
1602 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001603}
1604
1605static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1606 struct beacon_parameters *info)
1607{
1608 return ath6kl_ap_beacon(wiphy, dev, info, true);
1609}
1610
1611static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1612 struct beacon_parameters *info)
1613{
1614 return ath6kl_ap_beacon(wiphy, dev, info, false);
1615}
1616
1617static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1618{
1619 struct ath6kl *ar = ath6kl_priv(dev);
1620
1621 if (ar->nw_type != AP_NETWORK)
1622 return -EOPNOTSUPP;
1623 if (!test_bit(CONNECTED, &ar->flag))
1624 return -ENOTCONN;
1625
1626 ath6kl_wmi_disconnect_cmd(ar->wmi);
1627 clear_bit(CONNECTED, &ar->flag);
1628
1629 return 0;
1630}
1631
Jouni Malinen23875132011-08-30 21:57:53 +03001632static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1633 u8 *mac, struct station_parameters *params)
1634{
1635 struct ath6kl *ar = ath6kl_priv(dev);
1636
1637 if (ar->nw_type != AP_NETWORK)
1638 return -EOPNOTSUPP;
1639
1640 /* Use this only for authorizing/unauthorizing a station */
1641 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1642 return -EOPNOTSUPP;
1643
1644 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1645 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1646 mac, 0);
1647 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1648 0);
1649}
1650
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001651static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1652 struct net_device *dev,
1653 struct ieee80211_channel *chan,
1654 enum nl80211_channel_type channel_type,
1655 unsigned int duration,
1656 u64 *cookie)
1657{
1658 struct ath6kl *ar = ath6kl_priv(dev);
1659
1660 /* TODO: if already pending or ongoing remain-on-channel,
1661 * return -EBUSY */
1662 *cookie = 1; /* only a single pending request is supported */
1663
1664 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1665 duration);
1666}
1667
1668static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1669 struct net_device *dev,
1670 u64 cookie)
1671{
1672 struct ath6kl *ar = ath6kl_priv(dev);
1673
1674 if (cookie != 1)
1675 return -ENOENT;
1676
1677 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1678}
1679
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001680static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1681 size_t len, unsigned int freq)
1682{
1683 const u8 *pos;
1684 u8 *p2p;
1685 int p2p_len;
1686 int ret;
1687 const struct ieee80211_mgmt *mgmt;
1688
1689 mgmt = (const struct ieee80211_mgmt *) buf;
1690
1691 /* Include P2P IE(s) from the frame generated in user space. */
1692
1693 p2p = kmalloc(len, GFP_KERNEL);
1694 if (p2p == NULL)
1695 return -ENOMEM;
1696 p2p_len = 0;
1697
1698 pos = mgmt->u.probe_resp.variable;
1699 while (pos + 1 < buf + len) {
1700 if (pos + 2 + pos[1] > buf + len)
1701 break;
1702 if (ath6kl_is_p2p_ie(pos)) {
1703 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1704 p2p_len += 2 + pos[1];
1705 }
1706 pos += 2 + pos[1];
1707 }
1708
1709 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1710 p2p, p2p_len);
1711 kfree(p2p);
1712 return ret;
1713}
1714
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001715static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1716 struct ieee80211_channel *chan, bool offchan,
1717 enum nl80211_channel_type channel_type,
1718 bool channel_type_valid, unsigned int wait,
1719 const u8 *buf, size_t len, u64 *cookie)
1720{
1721 struct ath6kl *ar = ath6kl_priv(dev);
1722 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001723 const struct ieee80211_mgmt *mgmt;
1724
1725 mgmt = (const struct ieee80211_mgmt *) buf;
1726 if (buf + len >= mgmt->u.probe_resp.variable &&
1727 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1728 ieee80211_is_probe_resp(mgmt->frame_control)) {
1729 /*
1730 * Send Probe Response frame in AP mode using a separate WMI
1731 * command to allow the target to fill in the generic IEs.
1732 */
1733 *cookie = 0; /* TX status not supported */
1734 return ath6kl_send_go_probe_resp(ar, buf, len,
1735 chan->center_freq);
1736 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001737
1738 id = ar->send_action_id++;
1739 if (id == 0) {
1740 /*
1741 * 0 is a reserved value in the WMI command and shall not be
1742 * used for the command.
1743 */
1744 id = ar->send_action_id++;
1745 }
1746
1747 *cookie = id;
1748 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1749 buf, len);
1750}
1751
Jouni Malinenae32c302011-08-30 21:58:01 +03001752static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1753 struct net_device *dev,
1754 u16 frame_type, bool reg)
1755{
1756 struct ath6kl *ar = ath6kl_priv(dev);
1757
1758 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1759 __func__, frame_type, reg);
1760 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1761 /*
1762 * Note: This notification callback is not allowed to sleep, so
1763 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1764 * hardcode target to report Probe Request frames all the time.
1765 */
1766 ar->probe_req_report = reg;
1767 }
1768}
1769
Jouni Malinenf80574a2011-08-30 21:58:04 +03001770static const struct ieee80211_txrx_stypes
1771ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1772 [NL80211_IFTYPE_STATION] = {
1773 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1774 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1775 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1776 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1777 },
1778 [NL80211_IFTYPE_P2P_CLIENT] = {
1779 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1780 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1781 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1782 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1783 },
1784 [NL80211_IFTYPE_P2P_GO] = {
1785 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1786 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1787 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1788 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1789 },
1790};
1791
Kalle Valobdcd8172011-07-18 00:22:30 +03001792static struct cfg80211_ops ath6kl_cfg80211_ops = {
1793 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1794 .scan = ath6kl_cfg80211_scan,
1795 .connect = ath6kl_cfg80211_connect,
1796 .disconnect = ath6kl_cfg80211_disconnect,
1797 .add_key = ath6kl_cfg80211_add_key,
1798 .get_key = ath6kl_cfg80211_get_key,
1799 .del_key = ath6kl_cfg80211_del_key,
1800 .set_default_key = ath6kl_cfg80211_set_default_key,
1801 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1802 .set_tx_power = ath6kl_cfg80211_set_txpower,
1803 .get_tx_power = ath6kl_cfg80211_get_txpower,
1804 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1805 .join_ibss = ath6kl_cfg80211_join_ibss,
1806 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1807 .get_station = ath6kl_get_station,
1808 .set_pmksa = ath6kl_set_pmksa,
1809 .del_pmksa = ath6kl_del_pmksa,
1810 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001811 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001812#ifdef CONFIG_PM
1813 .suspend = ar6k_cfg80211_suspend,
1814#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001815 .set_channel = ath6kl_set_channel,
1816 .add_beacon = ath6kl_add_beacon,
1817 .set_beacon = ath6kl_set_beacon,
1818 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001819 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001820 .remain_on_channel = ath6kl_remain_on_channel,
1821 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001822 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001823 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001824};
1825
1826struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1827{
1828 int ret = 0;
1829 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001830 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001831
1832 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1833 if (!wdev) {
1834 ath6kl_err("couldn't allocate wireless device\n");
1835 return NULL;
1836 }
1837
1838 /* create a new wiphy for use with cfg80211 */
1839 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1840 if (!wdev->wiphy) {
1841 ath6kl_err("couldn't allocate wiphy device\n");
1842 kfree(wdev);
1843 return NULL;
1844 }
1845
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001846 ar = wiphy_priv(wdev->wiphy);
1847 ar->p2p = !!ath6kl_p2p;
1848
Jouni Malinenf80574a2011-08-30 21:58:04 +03001849 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1850
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001851 wdev->wiphy->max_remain_on_channel_duration = 5000;
1852
Kalle Valobdcd8172011-07-18 00:22:30 +03001853 /* set device pointer for wiphy */
1854 set_wiphy_dev(wdev->wiphy, dev);
1855
1856 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001857 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001858 if (ar->p2p) {
1859 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1860 BIT(NL80211_IFTYPE_P2P_CLIENT);
1861 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001862 /* max num of ssids that can be probed during scanning */
1863 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001864 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001865 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1866 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1867 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1868
1869 wdev->wiphy->cipher_suites = cipher_suites;
1870 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1871
1872 ret = wiphy_register(wdev->wiphy);
1873 if (ret < 0) {
1874 ath6kl_err("couldn't register wiphy device\n");
1875 wiphy_free(wdev->wiphy);
1876 kfree(wdev);
1877 return NULL;
1878 }
1879
1880 return wdev;
1881}
1882
1883void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1884{
1885 struct wireless_dev *wdev = ar->wdev;
1886
1887 if (ar->scan_req) {
1888 cfg80211_scan_done(ar->scan_req, true);
1889 ar->scan_req = NULL;
1890 }
1891
1892 if (!wdev)
1893 return;
1894
1895 wiphy_unregister(wdev->wiphy);
1896 wiphy_free(wdev->wiphy);
1897 kfree(wdev);
1898}