blob: c84f53d6523b275006a36562c4972b2f360520a1 [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
Jouni Malinen32c10872011-09-19 19:15:07 +0300486 /*
487 * Store Beacon interval here; DTIM period will be available only once
488 * a Beacon frame from the AP is seen.
489 */
490 ar->assoc_bss_beacon_int = beacon_intvl;
491 clear_bit(DTIM_PERIOD_AVAIL, &ar->flag);
492
Kalle Valobdcd8172011-07-18 00:22:30 +0300493 if (nw_type & ADHOC_NETWORK) {
494 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
495 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
496 "%s: ath6k not in ibss mode\n", __func__);
497 return;
498 }
499 }
500
501 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300502 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
503 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300504 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
505 "%s: ath6k not in station mode\n", __func__);
506 return;
507 }
508 }
509
Jouni Malinen01cac472011-09-19 19:14:59 +0300510 chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300511
Kalle Valobdcd8172011-07-18 00:22:30 +0300512
513 if (nw_type & ADHOC_NETWORK) {
514 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
515 return;
516 }
517
Jouni Malinen01cac472011-09-19 19:14:59 +0300518 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
519 beacon_ie_len) < 0) {
520 ath6kl_err("could not add cfg80211 bss entry for "
521 "connect/roamed notification\n");
522 return;
523 }
524
Raja Mani9aa60352011-08-04 19:26:29 +0530525 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300526 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530527 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300528 cfg80211_connect_result(ar->net_dev, bssid,
529 assoc_req_ie, assoc_req_len,
530 assoc_resp_ie, assoc_resp_len,
531 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530532 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300533 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300534 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300535 assoc_req_ie, assoc_req_len,
536 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
537 }
538}
539
540static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
541 struct net_device *dev, u16 reason_code)
542{
543 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
544
545 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
546 reason_code);
547
548 if (!ath6kl_cfg80211_ready(ar))
549 return -EIO;
550
551 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
552 ath6kl_err("busy, destroy in progress\n");
553 return -EBUSY;
554 }
555
556 if (down_interruptible(&ar->sem)) {
557 ath6kl_err("busy, couldn't get access\n");
558 return -ERESTARTSYS;
559 }
560
561 ar->reconnect_flag = 0;
562 ath6kl_disconnect(ar);
563 memset(ar->ssid, 0, sizeof(ar->ssid));
564 ar->ssid_len = 0;
565
566 if (!test_bit(SKIP_SCAN, &ar->flag))
567 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
568
569 up(&ar->sem);
570
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530571 ar->sme_state = SME_DISCONNECTED;
572
Kalle Valobdcd8172011-07-18 00:22:30 +0300573 return 0;
574}
575
576void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
577 u8 *bssid, u8 assoc_resp_len,
578 u8 *assoc_info, u16 proto_reason)
579{
Kalle Valobdcd8172011-07-18 00:22:30 +0300580 if (ar->scan_req) {
581 cfg80211_scan_done(ar->scan_req, true);
582 ar->scan_req = NULL;
583 }
584
585 if (ar->nw_type & ADHOC_NETWORK) {
586 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
587 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
588 "%s: ath6k not in ibss mode\n", __func__);
589 return;
590 }
591 memset(bssid, 0, ETH_ALEN);
592 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
593 return;
594 }
595
596 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300597 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
598 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300599 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
600 "%s: ath6k not in station mode\n", __func__);
601 return;
602 }
603 }
604
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530605 /*
606 * Send a disconnect command to target when a disconnect event is
607 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
608 * request from host) to make the firmware stop trying to connect even
609 * after giving disconnect event. There will be one more disconnect
610 * event for this disconnect command with reason code DISCONNECT_CMD
611 * which will be notified to cfg80211.
612 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300613
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530614 if (reason != DISCONNECT_CMD) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300615 ath6kl_wmi_disconnect_cmd(ar->wmi);
616 return;
617 }
618
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530619 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300620
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530621 if (ar->sme_state == SME_CONNECTING) {
622 cfg80211_connect_result(ar->net_dev,
623 bssid, NULL, 0,
624 NULL, 0,
625 WLAN_STATUS_UNSPECIFIED_FAILURE,
626 GFP_KERNEL);
627 } else if (ar->sme_state == SME_CONNECTED) {
628 cfg80211_disconnected(ar->net_dev, reason,
629 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300630 }
631
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530632 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300633}
634
Kalle Valobdcd8172011-07-18 00:22:30 +0300635static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
636 struct cfg80211_scan_request *request)
637{
638 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300639 s8 n_channels = 0;
640 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300641 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300642
643 if (!ath6kl_cfg80211_ready(ar))
644 return -EIO;
645
646 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300647 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300648 ret = ath6kl_wmi_bssfilter_cmd(
649 ar->wmi,
650 (test_bit(CONNECTED, &ar->flag) ?
651 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
652 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300654 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300655 }
656 }
657
658 if (request->n_ssids && request->ssids[0].ssid_len) {
659 u8 i;
660
661 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
662 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
663
664 for (i = 0; i < request->n_ssids; i++)
665 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
666 SPECIFIC_SSID_FLAG,
667 request->ssids[i].ssid_len,
668 request->ssids[i].ssid);
669 }
670
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300671 if (request->ie) {
672 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
673 request->ie, request->ie_len);
674 if (ret) {
675 ath6kl_err("failed to set Probe Request appie for "
676 "scan");
677 return ret;
678 }
679 }
680
Jouni Malinen11869be2011-09-02 20:07:06 +0300681 /*
682 * Scan only the requested channels if the request specifies a set of
683 * channels. If the list is longer than the target supports, do not
684 * configure the list and instead, scan all available channels.
685 */
686 if (request->n_channels > 0 &&
687 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300688 u8 i;
689
Jouni Malinen11869be2011-09-02 20:07:06 +0300690 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300691
692 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
693 if (channels == NULL) {
694 ath6kl_warn("failed to set scan channels, "
695 "scan all channels");
696 n_channels = 0;
697 }
698
699 for (i = 0; i < n_channels; i++)
700 channels[i] = request->channels[i]->center_freq;
701 }
702
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300703 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
704 false, 0, 0, n_channels, channels);
705 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300706 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300707 else
708 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300709
Edward Lu1276c9e2011-08-30 21:58:00 +0300710 kfree(channels);
711
Kalle Valobdcd8172011-07-18 00:22:30 +0300712 return ret;
713}
714
715void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
716{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300717 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300718
719 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
720
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300721 if (!ar->scan_req)
722 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300723
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300724 if ((status == -ECANCELED) || (status == -EBUSY)) {
725 cfg80211_scan_done(ar->scan_req, true);
726 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300728
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300729 cfg80211_scan_done(ar->scan_req, false);
730
731 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
732 for (i = 0; i < ar->scan_req->n_ssids; i++) {
733 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
734 DISABLE_SSID_FLAG,
735 0, NULL);
736 }
737 }
738
739out:
740 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300741}
742
743static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
744 u8 key_index, bool pairwise,
745 const u8 *mac_addr,
746 struct key_params *params)
747{
748 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
749 struct ath6kl_key *key = NULL;
750 u8 key_usage;
751 u8 key_type;
752 int status = 0;
753
754 if (!ath6kl_cfg80211_ready(ar))
755 return -EIO;
756
757 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
758 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
759 "%s: key index %d out of bounds\n", __func__,
760 key_index);
761 return -ENOENT;
762 }
763
764 key = &ar->keys[key_index];
765 memset(key, 0, sizeof(struct ath6kl_key));
766
767 if (pairwise)
768 key_usage = PAIRWISE_USAGE;
769 else
770 key_usage = GROUP_USAGE;
771
772 if (params) {
773 if (params->key_len > WLAN_MAX_KEY_LEN ||
774 params->seq_len > sizeof(key->seq))
775 return -EINVAL;
776
777 key->key_len = params->key_len;
778 memcpy(key->key, params->key, key->key_len);
779 key->seq_len = params->seq_len;
780 memcpy(key->seq, params->seq, key->seq_len);
781 key->cipher = params->cipher;
782 }
783
784 switch (key->cipher) {
785 case WLAN_CIPHER_SUITE_WEP40:
786 case WLAN_CIPHER_SUITE_WEP104:
787 key_type = WEP_CRYPT;
788 break;
789
790 case WLAN_CIPHER_SUITE_TKIP:
791 key_type = TKIP_CRYPT;
792 break;
793
794 case WLAN_CIPHER_SUITE_CCMP:
795 key_type = AES_CRYPT;
796 break;
797
798 default:
799 return -ENOTSUPP;
800 }
801
802 if (((ar->auth_mode == WPA_PSK_AUTH)
803 || (ar->auth_mode == WPA2_PSK_AUTH))
804 && (key_usage & GROUP_USAGE))
805 del_timer(&ar->disconnect_timer);
806
807 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
808 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
809 __func__, key_index, key->key_len, key_type,
810 key_usage, key->seq_len);
811
812 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300813
814 if (ar->nw_type == AP_NETWORK && !pairwise &&
815 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
816 ar->ap_mode_bkey.valid = true;
817 ar->ap_mode_bkey.key_index = key_index;
818 ar->ap_mode_bkey.key_type = key_type;
819 ar->ap_mode_bkey.key_len = key->key_len;
820 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
821 if (!test_bit(CONNECTED, &ar->flag)) {
822 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
823 "key configuration until AP mode has been "
824 "started\n");
825 /*
826 * The key will be set in ath6kl_connect_ap_mode() once
827 * the connected event is received from the target.
828 */
829 return 0;
830 }
831 }
832
Jouni Malinen151411e2011-09-15 15:10:16 +0300833 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
834 !test_bit(CONNECTED, &ar->flag)) {
835 /*
836 * Store the key locally so that it can be re-configured after
837 * the AP mode has properly started
838 * (ath6kl_install_statioc_wep_keys).
839 */
840 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
841 "until AP mode has been started\n");
842 ar->wep_key_list[key_index].key_len = key->key_len;
843 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
844 return 0;
845 }
846
Kalle Valobdcd8172011-07-18 00:22:30 +0300847 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
848 key_type, key_usage, key->key_len,
849 key->seq, key->key, KEY_OP_INIT_VAL,
850 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
851
852 if (status)
853 return -EIO;
854
855 return 0;
856}
857
858static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
859 u8 key_index, bool pairwise,
860 const u8 *mac_addr)
861{
862 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
863
864 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
865
866 if (!ath6kl_cfg80211_ready(ar))
867 return -EIO;
868
869 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
870 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
871 "%s: key index %d out of bounds\n", __func__,
872 key_index);
873 return -ENOENT;
874 }
875
876 if (!ar->keys[key_index].key_len) {
877 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
878 "%s: index %d is empty\n", __func__, key_index);
879 return 0;
880 }
881
882 ar->keys[key_index].key_len = 0;
883
884 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
885}
886
887static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
888 u8 key_index, bool pairwise,
889 const u8 *mac_addr, void *cookie,
890 void (*callback) (void *cookie,
891 struct key_params *))
892{
893 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
894 struct ath6kl_key *key = NULL;
895 struct key_params params;
896
897 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
898
899 if (!ath6kl_cfg80211_ready(ar))
900 return -EIO;
901
902 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
903 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
904 "%s: key index %d out of bounds\n", __func__,
905 key_index);
906 return -ENOENT;
907 }
908
909 key = &ar->keys[key_index];
910 memset(&params, 0, sizeof(params));
911 params.cipher = key->cipher;
912 params.key_len = key->key_len;
913 params.seq_len = key->seq_len;
914 params.seq = key->seq;
915 params.key = key->key;
916
917 callback(cookie, &params);
918
919 return key->key_len ? 0 : -ENOENT;
920}
921
922static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
923 struct net_device *ndev,
924 u8 key_index, bool unicast,
925 bool multicast)
926{
927 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
928 struct ath6kl_key *key = NULL;
929 int status = 0;
930 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300931 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300932
933 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
934
935 if (!ath6kl_cfg80211_ready(ar))
936 return -EIO;
937
938 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
939 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
940 "%s: key index %d out of bounds\n",
941 __func__, key_index);
942 return -ENOENT;
943 }
944
945 if (!ar->keys[key_index].key_len) {
946 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
947 __func__, key_index);
948 return -EINVAL;
949 }
950
951 ar->def_txkey_index = key_index;
952 key = &ar->keys[ar->def_txkey_index];
953 key_usage = GROUP_USAGE;
954 if (ar->prwise_crypto == WEP_CRYPT)
955 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +0300956 if (unicast)
957 key_type = ar->prwise_crypto;
958 if (multicast)
959 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +0300960
Jouni Malinen151411e2011-09-15 15:10:16 +0300961 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300962 return 0; /* Delay until AP mode has been started */
963
Kalle Valobdcd8172011-07-18 00:22:30 +0300964 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +0300965 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +0300966 key->key_len, key->seq, key->key,
967 KEY_OP_INIT_VAL, NULL,
968 SYNC_BOTH_WMIFLAG);
969 if (status)
970 return -EIO;
971
972 return 0;
973}
974
975void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
976 bool ismcast)
977{
978 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
979 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
980
981 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
982 (ismcast ? NL80211_KEYTYPE_GROUP :
983 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
984 GFP_KERNEL);
985}
986
987static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
988{
989 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
990 int ret;
991
992 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
993 changed);
994
995 if (!ath6kl_cfg80211_ready(ar))
996 return -EIO;
997
998 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
999 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1000 if (ret != 0) {
1001 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1002 return -EIO;
1003 }
1004 }
1005
1006 return 0;
1007}
1008
1009/*
1010 * The type nl80211_tx_power_setting replaces the following
1011 * data type from 2.6.36 onwards
1012*/
1013static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1014 enum nl80211_tx_power_setting type,
1015 int dbm)
1016{
1017 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1018 u8 ath6kl_dbm;
1019
1020 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1021 type, dbm);
1022
1023 if (!ath6kl_cfg80211_ready(ar))
1024 return -EIO;
1025
1026 switch (type) {
1027 case NL80211_TX_POWER_AUTOMATIC:
1028 return 0;
1029 case NL80211_TX_POWER_LIMITED:
1030 ar->tx_pwr = ath6kl_dbm = dbm;
1031 break;
1032 default:
1033 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1034 __func__, type);
1035 return -EOPNOTSUPP;
1036 }
1037
1038 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1039
1040 return 0;
1041}
1042
1043static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1044{
1045 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1046
1047 if (!ath6kl_cfg80211_ready(ar))
1048 return -EIO;
1049
1050 if (test_bit(CONNECTED, &ar->flag)) {
1051 ar->tx_pwr = 0;
1052
1053 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1054 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1055 return -EIO;
1056 }
1057
1058 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1059 5 * HZ);
1060
1061 if (signal_pending(current)) {
1062 ath6kl_err("target did not respond\n");
1063 return -EINTR;
1064 }
1065 }
1066
1067 *dbm = ar->tx_pwr;
1068 return 0;
1069}
1070
1071static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1072 struct net_device *dev,
1073 bool pmgmt, int timeout)
1074{
1075 struct ath6kl *ar = ath6kl_priv(dev);
1076 struct wmi_power_mode_cmd mode;
1077
1078 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1079 __func__, pmgmt, timeout);
1080
1081 if (!ath6kl_cfg80211_ready(ar))
1082 return -EIO;
1083
1084 if (pmgmt) {
1085 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1086 mode.pwr_mode = REC_POWER;
1087 } else {
1088 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1089 mode.pwr_mode = MAX_PERF_POWER;
1090 }
1091
1092 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1093 ath6kl_err("wmi_powermode_cmd failed\n");
1094 return -EIO;
1095 }
1096
1097 return 0;
1098}
1099
1100static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1101 struct net_device *ndev,
1102 enum nl80211_iftype type, u32 *flags,
1103 struct vif_params *params)
1104{
1105 struct ath6kl *ar = ath6kl_priv(ndev);
1106 struct wireless_dev *wdev = ar->wdev;
1107
1108 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1109
1110 if (!ath6kl_cfg80211_ready(ar))
1111 return -EIO;
1112
1113 switch (type) {
1114 case NL80211_IFTYPE_STATION:
1115 ar->next_mode = INFRA_NETWORK;
1116 break;
1117 case NL80211_IFTYPE_ADHOC:
1118 ar->next_mode = ADHOC_NETWORK;
1119 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001120 case NL80211_IFTYPE_AP:
1121 ar->next_mode = AP_NETWORK;
1122 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001123 case NL80211_IFTYPE_P2P_CLIENT:
1124 ar->next_mode = INFRA_NETWORK;
1125 break;
1126 case NL80211_IFTYPE_P2P_GO:
1127 ar->next_mode = AP_NETWORK;
1128 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001129 default:
1130 ath6kl_err("invalid interface type %u\n", type);
1131 return -EOPNOTSUPP;
1132 }
1133
1134 wdev->iftype = type;
1135
1136 return 0;
1137}
1138
1139static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1140 struct net_device *dev,
1141 struct cfg80211_ibss_params *ibss_param)
1142{
1143 struct ath6kl *ar = ath6kl_priv(dev);
1144 int status;
1145
1146 if (!ath6kl_cfg80211_ready(ar))
1147 return -EIO;
1148
1149 ar->ssid_len = ibss_param->ssid_len;
1150 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1151
1152 if (ibss_param->channel)
1153 ar->ch_hint = ibss_param->channel->center_freq;
1154
1155 if (ibss_param->channel_fixed) {
1156 /*
1157 * TODO: channel_fixed: The channel should be fixed, do not
1158 * search for IBSSs to join on other channels. Target
1159 * firmware does not support this feature, needs to be
1160 * updated.
1161 */
1162 return -EOPNOTSUPP;
1163 }
1164
1165 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1166 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1167 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1168
1169 ath6kl_set_wpa_version(ar, 0);
1170
1171 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1172 if (status)
1173 return status;
1174
1175 if (ibss_param->privacy) {
1176 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1177 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1178 } else {
1179 ath6kl_set_cipher(ar, 0, true);
1180 ath6kl_set_cipher(ar, 0, false);
1181 }
1182
1183 ar->nw_type = ar->next_mode;
1184
1185 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1186 "%s: connect called with authmode %d dot11 auth %d"
1187 " PW crypto %d PW crypto len %d GRP crypto %d"
1188 " GRP crypto len %d channel hint %u\n",
1189 __func__,
1190 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1191 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001192 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001193
1194 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1195 ar->dot11_auth_mode, ar->auth_mode,
1196 ar->prwise_crypto,
1197 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001198 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001199 ar->ssid_len, ar->ssid,
1200 ar->req_bssid, ar->ch_hint,
1201 ar->connect_ctrl_flags);
1202 set_bit(CONNECT_PEND, &ar->flag);
1203
1204 return 0;
1205}
1206
1207static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1208 struct net_device *dev)
1209{
1210 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1211
1212 if (!ath6kl_cfg80211_ready(ar))
1213 return -EIO;
1214
1215 ath6kl_disconnect(ar);
1216 memset(ar->ssid, 0, sizeof(ar->ssid));
1217 ar->ssid_len = 0;
1218
1219 return 0;
1220}
1221
1222static const u32 cipher_suites[] = {
1223 WLAN_CIPHER_SUITE_WEP40,
1224 WLAN_CIPHER_SUITE_WEP104,
1225 WLAN_CIPHER_SUITE_TKIP,
1226 WLAN_CIPHER_SUITE_CCMP,
1227};
1228
1229static bool is_rate_legacy(s32 rate)
1230{
1231 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1232 6000, 9000, 12000, 18000, 24000,
1233 36000, 48000, 54000
1234 };
1235 u8 i;
1236
1237 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1238 if (rate == legacy[i])
1239 return true;
1240
1241 return false;
1242}
1243
1244static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1245{
1246 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1247 52000, 58500, 65000, 72200
1248 };
1249 u8 i;
1250
1251 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1252 if (rate == ht20[i]) {
1253 if (i == ARRAY_SIZE(ht20) - 1)
1254 /* last rate uses sgi */
1255 *sgi = true;
1256 else
1257 *sgi = false;
1258
1259 *mcs = i;
1260 return true;
1261 }
1262 }
1263 return false;
1264}
1265
1266static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1267{
1268 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1269 81000, 108000, 121500, 135000,
1270 150000
1271 };
1272 u8 i;
1273
1274 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1275 if (rate == ht40[i]) {
1276 if (i == ARRAY_SIZE(ht40) - 1)
1277 /* last rate uses sgi */
1278 *sgi = true;
1279 else
1280 *sgi = false;
1281
1282 *mcs = i;
1283 return true;
1284 }
1285 }
1286
1287 return false;
1288}
1289
1290static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1291 u8 *mac, struct station_info *sinfo)
1292{
1293 struct ath6kl *ar = ath6kl_priv(dev);
1294 long left;
1295 bool sgi;
1296 s32 rate;
1297 int ret;
1298 u8 mcs;
1299
1300 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1301 return -ENOENT;
1302
1303 if (down_interruptible(&ar->sem))
1304 return -EBUSY;
1305
1306 set_bit(STATS_UPDATE_PEND, &ar->flag);
1307
1308 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1309
1310 if (ret != 0) {
1311 up(&ar->sem);
1312 return -EIO;
1313 }
1314
1315 left = wait_event_interruptible_timeout(ar->event_wq,
1316 !test_bit(STATS_UPDATE_PEND,
1317 &ar->flag),
1318 WMI_TIMEOUT);
1319
1320 up(&ar->sem);
1321
1322 if (left == 0)
1323 return -ETIMEDOUT;
1324 else if (left < 0)
1325 return left;
1326
1327 if (ar->target_stats.rx_byte) {
1328 sinfo->rx_bytes = ar->target_stats.rx_byte;
1329 sinfo->filled |= STATION_INFO_RX_BYTES;
1330 sinfo->rx_packets = ar->target_stats.rx_pkt;
1331 sinfo->filled |= STATION_INFO_RX_PACKETS;
1332 }
1333
1334 if (ar->target_stats.tx_byte) {
1335 sinfo->tx_bytes = ar->target_stats.tx_byte;
1336 sinfo->filled |= STATION_INFO_TX_BYTES;
1337 sinfo->tx_packets = ar->target_stats.tx_pkt;
1338 sinfo->filled |= STATION_INFO_TX_PACKETS;
1339 }
1340
1341 sinfo->signal = ar->target_stats.cs_rssi;
1342 sinfo->filled |= STATION_INFO_SIGNAL;
1343
1344 rate = ar->target_stats.tx_ucast_rate;
1345
1346 if (is_rate_legacy(rate)) {
1347 sinfo->txrate.legacy = rate / 100;
1348 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1349 if (sgi) {
1350 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1351 sinfo->txrate.mcs = mcs - 1;
1352 } else {
1353 sinfo->txrate.mcs = mcs;
1354 }
1355
1356 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1357 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1358 if (sgi) {
1359 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1360 sinfo->txrate.mcs = mcs - 1;
1361 } else {
1362 sinfo->txrate.mcs = mcs;
1363 }
1364
1365 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1366 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1367 } else {
1368 ath6kl_warn("invalid rate: %d\n", rate);
1369 return 0;
1370 }
1371
1372 sinfo->filled |= STATION_INFO_TX_BITRATE;
1373
Jouni Malinen32c10872011-09-19 19:15:07 +03001374 if (test_bit(CONNECTED, &ar->flag) &&
1375 test_bit(DTIM_PERIOD_AVAIL, &ar->flag) &&
1376 ar->nw_type == INFRA_NETWORK) {
1377 sinfo->filled |= STATION_INFO_BSS_PARAM;
1378 sinfo->bss_param.flags = 0;
1379 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1380 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1381 }
1382
Kalle Valobdcd8172011-07-18 00:22:30 +03001383 return 0;
1384}
1385
1386static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1387 struct cfg80211_pmksa *pmksa)
1388{
1389 struct ath6kl *ar = ath6kl_priv(netdev);
1390 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1391 pmksa->pmkid, true);
1392}
1393
1394static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1395 struct cfg80211_pmksa *pmksa)
1396{
1397 struct ath6kl *ar = ath6kl_priv(netdev);
1398 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1399 pmksa->pmkid, false);
1400}
1401
1402static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1403{
1404 struct ath6kl *ar = ath6kl_priv(netdev);
1405 if (test_bit(CONNECTED, &ar->flag))
1406 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1407 return 0;
1408}
1409
Kalle Valoabcb3442011-07-22 08:26:20 +03001410#ifdef CONFIG_PM
1411static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1412 struct cfg80211_wowlan *wow)
1413{
1414 struct ath6kl *ar = wiphy_priv(wiphy);
1415
1416 return ath6kl_hif_suspend(ar);
1417}
1418#endif
1419
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001420static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1421 struct ieee80211_channel *chan,
1422 enum nl80211_channel_type channel_type)
1423{
1424 struct ath6kl *ar = ath6kl_priv(dev);
1425
1426 if (!ath6kl_cfg80211_ready(ar))
1427 return -EIO;
1428
1429 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1430 __func__, chan->center_freq, chan->hw_value);
1431 ar->next_chan = chan->center_freq;
1432
1433 return 0;
1434}
1435
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001436static bool ath6kl_is_p2p_ie(const u8 *pos)
1437{
1438 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1439 pos[2] == 0x50 && pos[3] == 0x6f &&
1440 pos[4] == 0x9a && pos[5] == 0x09;
1441}
1442
1443static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1444 size_t ies_len)
1445{
1446 const u8 *pos;
1447 u8 *buf = NULL;
1448 size_t len = 0;
1449 int ret;
1450
1451 /*
1452 * Filter out P2P IE(s) since they will be included depending on
1453 * the Probe Request frame in ath6kl_send_go_probe_resp().
1454 */
1455
1456 if (ies && ies_len) {
1457 buf = kmalloc(ies_len, GFP_KERNEL);
1458 if (buf == NULL)
1459 return -ENOMEM;
1460 pos = ies;
1461 while (pos + 1 < ies + ies_len) {
1462 if (pos + 2 + pos[1] > ies + ies_len)
1463 break;
1464 if (!ath6kl_is_p2p_ie(pos)) {
1465 memcpy(buf + len, pos, 2 + pos[1]);
1466 len += 2 + pos[1];
1467 }
1468 pos += 2 + pos[1];
1469 }
1470 }
1471
1472 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1473 buf, len);
1474 kfree(buf);
1475 return ret;
1476}
1477
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001478static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1479 struct beacon_parameters *info, bool add)
1480{
1481 struct ath6kl *ar = ath6kl_priv(dev);
1482 struct ieee80211_mgmt *mgmt;
1483 u8 *ies;
1484 int ies_len;
1485 struct wmi_connect_cmd p;
1486 int res;
1487 int i;
1488
1489 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1490
1491 if (!ath6kl_cfg80211_ready(ar))
1492 return -EIO;
1493
1494 if (ar->next_mode != AP_NETWORK)
1495 return -EOPNOTSUPP;
1496
1497 if (info->beacon_ies) {
1498 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1499 info->beacon_ies,
1500 info->beacon_ies_len);
1501 if (res)
1502 return res;
1503 }
1504 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001505 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1506 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001507 if (res)
1508 return res;
1509 }
1510 if (info->assocresp_ies) {
1511 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1512 info->assocresp_ies,
1513 info->assocresp_ies_len);
1514 if (res)
1515 return res;
1516 }
1517
1518 if (!add)
1519 return 0;
1520
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001521 ar->ap_mode_bkey.valid = false;
1522
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001523 /* TODO:
1524 * info->interval
1525 * info->dtim_period
1526 */
1527
1528 if (info->head == NULL)
1529 return -EINVAL;
1530 mgmt = (struct ieee80211_mgmt *) info->head;
1531 ies = mgmt->u.beacon.variable;
1532 if (ies > info->head + info->head_len)
1533 return -EINVAL;
1534 ies_len = info->head + info->head_len - ies;
1535
1536 if (info->ssid == NULL)
1537 return -EINVAL;
1538 memcpy(ar->ssid, info->ssid, info->ssid_len);
1539 ar->ssid_len = info->ssid_len;
1540 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1541 return -EOPNOTSUPP; /* TODO */
1542
1543 ar->dot11_auth_mode = OPEN_AUTH;
1544
1545 memset(&p, 0, sizeof(p));
1546
1547 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1548 switch (info->crypto.akm_suites[i]) {
1549 case WLAN_AKM_SUITE_8021X:
1550 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1551 p.auth_mode |= WPA_AUTH;
1552 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1553 p.auth_mode |= WPA2_AUTH;
1554 break;
1555 case WLAN_AKM_SUITE_PSK:
1556 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1557 p.auth_mode |= WPA_PSK_AUTH;
1558 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1559 p.auth_mode |= WPA2_PSK_AUTH;
1560 break;
1561 }
1562 }
1563 if (p.auth_mode == 0)
1564 p.auth_mode = NONE_AUTH;
1565 ar->auth_mode = p.auth_mode;
1566
1567 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1568 switch (info->crypto.ciphers_pairwise[i]) {
1569 case WLAN_CIPHER_SUITE_WEP40:
1570 case WLAN_CIPHER_SUITE_WEP104:
1571 p.prwise_crypto_type |= WEP_CRYPT;
1572 break;
1573 case WLAN_CIPHER_SUITE_TKIP:
1574 p.prwise_crypto_type |= TKIP_CRYPT;
1575 break;
1576 case WLAN_CIPHER_SUITE_CCMP:
1577 p.prwise_crypto_type |= AES_CRYPT;
1578 break;
1579 }
1580 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001581 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001582 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001583 ath6kl_set_cipher(ar, 0, true);
1584 } else if (info->crypto.n_ciphers_pairwise == 1)
1585 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001586
1587 switch (info->crypto.cipher_group) {
1588 case WLAN_CIPHER_SUITE_WEP40:
1589 case WLAN_CIPHER_SUITE_WEP104:
1590 p.grp_crypto_type = WEP_CRYPT;
1591 break;
1592 case WLAN_CIPHER_SUITE_TKIP:
1593 p.grp_crypto_type = TKIP_CRYPT;
1594 break;
1595 case WLAN_CIPHER_SUITE_CCMP:
1596 p.grp_crypto_type = AES_CRYPT;
1597 break;
1598 default:
1599 p.grp_crypto_type = NONE_CRYPT;
1600 break;
1601 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001602 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001603
1604 p.nw_type = AP_NETWORK;
1605 ar->nw_type = ar->next_mode;
1606
1607 p.ssid_len = ar->ssid_len;
1608 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1609 p.dot11_auth_mode = ar->dot11_auth_mode;
1610 p.ch = cpu_to_le16(ar->next_chan);
1611
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001612 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1613 if (res < 0)
1614 return res;
1615
1616 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001617}
1618
1619static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1620 struct beacon_parameters *info)
1621{
1622 return ath6kl_ap_beacon(wiphy, dev, info, true);
1623}
1624
1625static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1626 struct beacon_parameters *info)
1627{
1628 return ath6kl_ap_beacon(wiphy, dev, info, false);
1629}
1630
1631static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1632{
1633 struct ath6kl *ar = ath6kl_priv(dev);
1634
1635 if (ar->nw_type != AP_NETWORK)
1636 return -EOPNOTSUPP;
1637 if (!test_bit(CONNECTED, &ar->flag))
1638 return -ENOTCONN;
1639
1640 ath6kl_wmi_disconnect_cmd(ar->wmi);
1641 clear_bit(CONNECTED, &ar->flag);
1642
1643 return 0;
1644}
1645
Jouni Malinen23875132011-08-30 21:57:53 +03001646static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1647 u8 *mac, struct station_parameters *params)
1648{
1649 struct ath6kl *ar = ath6kl_priv(dev);
1650
1651 if (ar->nw_type != AP_NETWORK)
1652 return -EOPNOTSUPP;
1653
1654 /* Use this only for authorizing/unauthorizing a station */
1655 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1656 return -EOPNOTSUPP;
1657
1658 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1659 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1660 mac, 0);
1661 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1662 0);
1663}
1664
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001665static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1666 struct net_device *dev,
1667 struct ieee80211_channel *chan,
1668 enum nl80211_channel_type channel_type,
1669 unsigned int duration,
1670 u64 *cookie)
1671{
1672 struct ath6kl *ar = ath6kl_priv(dev);
1673
1674 /* TODO: if already pending or ongoing remain-on-channel,
1675 * return -EBUSY */
1676 *cookie = 1; /* only a single pending request is supported */
1677
1678 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1679 duration);
1680}
1681
1682static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1683 struct net_device *dev,
1684 u64 cookie)
1685{
1686 struct ath6kl *ar = ath6kl_priv(dev);
1687
1688 if (cookie != 1)
1689 return -ENOENT;
1690
1691 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1692}
1693
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001694static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1695 size_t len, unsigned int freq)
1696{
1697 const u8 *pos;
1698 u8 *p2p;
1699 int p2p_len;
1700 int ret;
1701 const struct ieee80211_mgmt *mgmt;
1702
1703 mgmt = (const struct ieee80211_mgmt *) buf;
1704
1705 /* Include P2P IE(s) from the frame generated in user space. */
1706
1707 p2p = kmalloc(len, GFP_KERNEL);
1708 if (p2p == NULL)
1709 return -ENOMEM;
1710 p2p_len = 0;
1711
1712 pos = mgmt->u.probe_resp.variable;
1713 while (pos + 1 < buf + len) {
1714 if (pos + 2 + pos[1] > buf + len)
1715 break;
1716 if (ath6kl_is_p2p_ie(pos)) {
1717 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1718 p2p_len += 2 + pos[1];
1719 }
1720 pos += 2 + pos[1];
1721 }
1722
1723 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1724 p2p, p2p_len);
1725 kfree(p2p);
1726 return ret;
1727}
1728
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001729static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1730 struct ieee80211_channel *chan, bool offchan,
1731 enum nl80211_channel_type channel_type,
1732 bool channel_type_valid, unsigned int wait,
1733 const u8 *buf, size_t len, u64 *cookie)
1734{
1735 struct ath6kl *ar = ath6kl_priv(dev);
1736 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001737 const struct ieee80211_mgmt *mgmt;
1738
1739 mgmt = (const struct ieee80211_mgmt *) buf;
1740 if (buf + len >= mgmt->u.probe_resp.variable &&
1741 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1742 ieee80211_is_probe_resp(mgmt->frame_control)) {
1743 /*
1744 * Send Probe Response frame in AP mode using a separate WMI
1745 * command to allow the target to fill in the generic IEs.
1746 */
1747 *cookie = 0; /* TX status not supported */
1748 return ath6kl_send_go_probe_resp(ar, buf, len,
1749 chan->center_freq);
1750 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001751
1752 id = ar->send_action_id++;
1753 if (id == 0) {
1754 /*
1755 * 0 is a reserved value in the WMI command and shall not be
1756 * used for the command.
1757 */
1758 id = ar->send_action_id++;
1759 }
1760
1761 *cookie = id;
1762 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1763 buf, len);
1764}
1765
Jouni Malinenae32c302011-08-30 21:58:01 +03001766static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1767 struct net_device *dev,
1768 u16 frame_type, bool reg)
1769{
1770 struct ath6kl *ar = ath6kl_priv(dev);
1771
1772 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1773 __func__, frame_type, reg);
1774 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1775 /*
1776 * Note: This notification callback is not allowed to sleep, so
1777 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1778 * hardcode target to report Probe Request frames all the time.
1779 */
1780 ar->probe_req_report = reg;
1781 }
1782}
1783
Jouni Malinenf80574a2011-08-30 21:58:04 +03001784static const struct ieee80211_txrx_stypes
1785ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1786 [NL80211_IFTYPE_STATION] = {
1787 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1788 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1789 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1790 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1791 },
1792 [NL80211_IFTYPE_P2P_CLIENT] = {
1793 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1794 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1795 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1796 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1797 },
1798 [NL80211_IFTYPE_P2P_GO] = {
1799 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1800 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1801 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1802 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1803 },
1804};
1805
Kalle Valobdcd8172011-07-18 00:22:30 +03001806static struct cfg80211_ops ath6kl_cfg80211_ops = {
1807 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1808 .scan = ath6kl_cfg80211_scan,
1809 .connect = ath6kl_cfg80211_connect,
1810 .disconnect = ath6kl_cfg80211_disconnect,
1811 .add_key = ath6kl_cfg80211_add_key,
1812 .get_key = ath6kl_cfg80211_get_key,
1813 .del_key = ath6kl_cfg80211_del_key,
1814 .set_default_key = ath6kl_cfg80211_set_default_key,
1815 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1816 .set_tx_power = ath6kl_cfg80211_set_txpower,
1817 .get_tx_power = ath6kl_cfg80211_get_txpower,
1818 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1819 .join_ibss = ath6kl_cfg80211_join_ibss,
1820 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1821 .get_station = ath6kl_get_station,
1822 .set_pmksa = ath6kl_set_pmksa,
1823 .del_pmksa = ath6kl_del_pmksa,
1824 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001825 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001826#ifdef CONFIG_PM
1827 .suspend = ar6k_cfg80211_suspend,
1828#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001829 .set_channel = ath6kl_set_channel,
1830 .add_beacon = ath6kl_add_beacon,
1831 .set_beacon = ath6kl_set_beacon,
1832 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001833 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001834 .remain_on_channel = ath6kl_remain_on_channel,
1835 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001836 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001837 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001838};
1839
1840struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1841{
1842 int ret = 0;
1843 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001844 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001845
1846 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1847 if (!wdev) {
1848 ath6kl_err("couldn't allocate wireless device\n");
1849 return NULL;
1850 }
1851
1852 /* create a new wiphy for use with cfg80211 */
1853 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1854 if (!wdev->wiphy) {
1855 ath6kl_err("couldn't allocate wiphy device\n");
1856 kfree(wdev);
1857 return NULL;
1858 }
1859
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001860 ar = wiphy_priv(wdev->wiphy);
1861 ar->p2p = !!ath6kl_p2p;
1862
Jouni Malinenf80574a2011-08-30 21:58:04 +03001863 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1864
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001865 wdev->wiphy->max_remain_on_channel_duration = 5000;
1866
Kalle Valobdcd8172011-07-18 00:22:30 +03001867 /* set device pointer for wiphy */
1868 set_wiphy_dev(wdev->wiphy, dev);
1869
1870 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001871 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001872 if (ar->p2p) {
1873 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1874 BIT(NL80211_IFTYPE_P2P_CLIENT);
1875 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001876 /* max num of ssids that can be probed during scanning */
1877 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001878 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001879 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1880 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1881 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1882
1883 wdev->wiphy->cipher_suites = cipher_suites;
1884 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1885
1886 ret = wiphy_register(wdev->wiphy);
1887 if (ret < 0) {
1888 ath6kl_err("couldn't register wiphy device\n");
1889 wiphy_free(wdev->wiphy);
1890 kfree(wdev);
1891 return NULL;
1892 }
1893
1894 return wdev;
1895}
1896
1897void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1898{
1899 struct wireless_dev *wdev = ar->wdev;
1900
1901 if (ar->scan_req) {
1902 cfg80211_scan_done(ar->scan_req, true);
1903 ar->scan_req = NULL;
1904 }
1905
1906 if (!wdev)
1907 return;
1908
1909 wiphy_unregister(wdev->wiphy);
1910 wiphy_free(wdev->wiphy);
1911 kfree(wdev);
1912}