blob: f03cc4a6fbc1dfe6aa8cf6bcb547e8fb307af77e [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;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530642 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300643
644 if (!ath6kl_cfg80211_ready(ar))
645 return -EIO;
646
647 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300648 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300649 ret = ath6kl_wmi_bssfilter_cmd(
650 ar->wmi,
651 (test_bit(CONNECTED, &ar->flag) ?
652 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
653 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300654 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300655 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300656 }
657 }
658
659 if (request->n_ssids && request->ssids[0].ssid_len) {
660 u8 i;
661
662 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
663 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
664
665 for (i = 0; i < request->n_ssids; i++)
666 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
667 SPECIFIC_SSID_FLAG,
668 request->ssids[i].ssid_len,
669 request->ssids[i].ssid);
670 }
671
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300672 if (request->ie) {
673 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
674 request->ie, request->ie_len);
675 if (ret) {
676 ath6kl_err("failed to set Probe Request appie for "
677 "scan");
678 return ret;
679 }
680 }
681
Jouni Malinen11869be2011-09-02 20:07:06 +0300682 /*
683 * Scan only the requested channels if the request specifies a set of
684 * channels. If the list is longer than the target supports, do not
685 * configure the list and instead, scan all available channels.
686 */
687 if (request->n_channels > 0 &&
688 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300689 u8 i;
690
Jouni Malinen11869be2011-09-02 20:07:06 +0300691 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300692
693 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
694 if (channels == NULL) {
695 ath6kl_warn("failed to set scan channels, "
696 "scan all channels");
697 n_channels = 0;
698 }
699
700 for (i = 0; i < n_channels; i++)
701 channels[i] = request->channels[i]->center_freq;
702 }
703
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530704 if (test_bit(CONNECTED, &ar->flag))
705 force_fg_scan = 1;
706
707 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, force_fg_scan,
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300708 false, 0, 0, n_channels, channels);
709 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300710 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300711 else
712 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300713
Edward Lu1276c9e2011-08-30 21:58:00 +0300714 kfree(channels);
715
Kalle Valobdcd8172011-07-18 00:22:30 +0300716 return ret;
717}
718
719void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
720{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300721 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300722
723 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
724
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300725 if (!ar->scan_req)
726 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300727
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300728 if ((status == -ECANCELED) || (status == -EBUSY)) {
729 cfg80211_scan_done(ar->scan_req, true);
730 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300731 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300732
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300733 cfg80211_scan_done(ar->scan_req, false);
734
735 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
736 for (i = 0; i < ar->scan_req->n_ssids; i++) {
737 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
738 DISABLE_SSID_FLAG,
739 0, NULL);
740 }
741 }
742
743out:
744 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300745}
746
747static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
748 u8 key_index, bool pairwise,
749 const u8 *mac_addr,
750 struct key_params *params)
751{
752 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
753 struct ath6kl_key *key = NULL;
754 u8 key_usage;
755 u8 key_type;
756 int status = 0;
757
758 if (!ath6kl_cfg80211_ready(ar))
759 return -EIO;
760
761 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
762 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
763 "%s: key index %d out of bounds\n", __func__,
764 key_index);
765 return -ENOENT;
766 }
767
768 key = &ar->keys[key_index];
769 memset(key, 0, sizeof(struct ath6kl_key));
770
771 if (pairwise)
772 key_usage = PAIRWISE_USAGE;
773 else
774 key_usage = GROUP_USAGE;
775
776 if (params) {
777 if (params->key_len > WLAN_MAX_KEY_LEN ||
778 params->seq_len > sizeof(key->seq))
779 return -EINVAL;
780
781 key->key_len = params->key_len;
782 memcpy(key->key, params->key, key->key_len);
783 key->seq_len = params->seq_len;
784 memcpy(key->seq, params->seq, key->seq_len);
785 key->cipher = params->cipher;
786 }
787
788 switch (key->cipher) {
789 case WLAN_CIPHER_SUITE_WEP40:
790 case WLAN_CIPHER_SUITE_WEP104:
791 key_type = WEP_CRYPT;
792 break;
793
794 case WLAN_CIPHER_SUITE_TKIP:
795 key_type = TKIP_CRYPT;
796 break;
797
798 case WLAN_CIPHER_SUITE_CCMP:
799 key_type = AES_CRYPT;
800 break;
801
802 default:
803 return -ENOTSUPP;
804 }
805
806 if (((ar->auth_mode == WPA_PSK_AUTH)
807 || (ar->auth_mode == WPA2_PSK_AUTH))
808 && (key_usage & GROUP_USAGE))
809 del_timer(&ar->disconnect_timer);
810
811 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
812 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
813 __func__, key_index, key->key_len, key_type,
814 key_usage, key->seq_len);
815
816 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300817
818 if (ar->nw_type == AP_NETWORK && !pairwise &&
819 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
820 ar->ap_mode_bkey.valid = true;
821 ar->ap_mode_bkey.key_index = key_index;
822 ar->ap_mode_bkey.key_type = key_type;
823 ar->ap_mode_bkey.key_len = key->key_len;
824 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
825 if (!test_bit(CONNECTED, &ar->flag)) {
826 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
827 "key configuration until AP mode has been "
828 "started\n");
829 /*
830 * The key will be set in ath6kl_connect_ap_mode() once
831 * the connected event is received from the target.
832 */
833 return 0;
834 }
835 }
836
Jouni Malinen151411e2011-09-15 15:10:16 +0300837 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
838 !test_bit(CONNECTED, &ar->flag)) {
839 /*
840 * Store the key locally so that it can be re-configured after
841 * the AP mode has properly started
842 * (ath6kl_install_statioc_wep_keys).
843 */
844 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
845 "until AP mode has been started\n");
846 ar->wep_key_list[key_index].key_len = key->key_len;
847 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
848 return 0;
849 }
850
Kalle Valobdcd8172011-07-18 00:22:30 +0300851 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
852 key_type, key_usage, key->key_len,
853 key->seq, key->key, KEY_OP_INIT_VAL,
854 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
855
856 if (status)
857 return -EIO;
858
859 return 0;
860}
861
862static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
863 u8 key_index, bool pairwise,
864 const u8 *mac_addr)
865{
866 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
867
868 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
869
870 if (!ath6kl_cfg80211_ready(ar))
871 return -EIO;
872
873 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
874 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
875 "%s: key index %d out of bounds\n", __func__,
876 key_index);
877 return -ENOENT;
878 }
879
880 if (!ar->keys[key_index].key_len) {
881 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
882 "%s: index %d is empty\n", __func__, key_index);
883 return 0;
884 }
885
886 ar->keys[key_index].key_len = 0;
887
888 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
889}
890
891static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
892 u8 key_index, bool pairwise,
893 const u8 *mac_addr, void *cookie,
894 void (*callback) (void *cookie,
895 struct key_params *))
896{
897 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
898 struct ath6kl_key *key = NULL;
899 struct key_params params;
900
901 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
902
903 if (!ath6kl_cfg80211_ready(ar))
904 return -EIO;
905
906 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
907 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
908 "%s: key index %d out of bounds\n", __func__,
909 key_index);
910 return -ENOENT;
911 }
912
913 key = &ar->keys[key_index];
914 memset(&params, 0, sizeof(params));
915 params.cipher = key->cipher;
916 params.key_len = key->key_len;
917 params.seq_len = key->seq_len;
918 params.seq = key->seq;
919 params.key = key->key;
920
921 callback(cookie, &params);
922
923 return key->key_len ? 0 : -ENOENT;
924}
925
926static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
927 struct net_device *ndev,
928 u8 key_index, bool unicast,
929 bool multicast)
930{
931 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
932 struct ath6kl_key *key = NULL;
933 int status = 0;
934 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300935 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300936
937 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
938
939 if (!ath6kl_cfg80211_ready(ar))
940 return -EIO;
941
942 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
943 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
944 "%s: key index %d out of bounds\n",
945 __func__, key_index);
946 return -ENOENT;
947 }
948
949 if (!ar->keys[key_index].key_len) {
950 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
951 __func__, key_index);
952 return -EINVAL;
953 }
954
955 ar->def_txkey_index = key_index;
956 key = &ar->keys[ar->def_txkey_index];
957 key_usage = GROUP_USAGE;
958 if (ar->prwise_crypto == WEP_CRYPT)
959 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +0300960 if (unicast)
961 key_type = ar->prwise_crypto;
962 if (multicast)
963 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +0300964
Jouni Malinen151411e2011-09-15 15:10:16 +0300965 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300966 return 0; /* Delay until AP mode has been started */
967
Kalle Valobdcd8172011-07-18 00:22:30 +0300968 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +0300969 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +0300970 key->key_len, key->seq, key->key,
971 KEY_OP_INIT_VAL, NULL,
972 SYNC_BOTH_WMIFLAG);
973 if (status)
974 return -EIO;
975
976 return 0;
977}
978
979void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
980 bool ismcast)
981{
982 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
983 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
984
985 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
986 (ismcast ? NL80211_KEYTYPE_GROUP :
987 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
988 GFP_KERNEL);
989}
990
991static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
992{
993 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
994 int ret;
995
996 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
997 changed);
998
999 if (!ath6kl_cfg80211_ready(ar))
1000 return -EIO;
1001
1002 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1003 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1004 if (ret != 0) {
1005 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1006 return -EIO;
1007 }
1008 }
1009
1010 return 0;
1011}
1012
1013/*
1014 * The type nl80211_tx_power_setting replaces the following
1015 * data type from 2.6.36 onwards
1016*/
1017static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1018 enum nl80211_tx_power_setting type,
1019 int dbm)
1020{
1021 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1022 u8 ath6kl_dbm;
1023
1024 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1025 type, dbm);
1026
1027 if (!ath6kl_cfg80211_ready(ar))
1028 return -EIO;
1029
1030 switch (type) {
1031 case NL80211_TX_POWER_AUTOMATIC:
1032 return 0;
1033 case NL80211_TX_POWER_LIMITED:
1034 ar->tx_pwr = ath6kl_dbm = dbm;
1035 break;
1036 default:
1037 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1038 __func__, type);
1039 return -EOPNOTSUPP;
1040 }
1041
1042 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1043
1044 return 0;
1045}
1046
1047static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1048{
1049 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1050
1051 if (!ath6kl_cfg80211_ready(ar))
1052 return -EIO;
1053
1054 if (test_bit(CONNECTED, &ar->flag)) {
1055 ar->tx_pwr = 0;
1056
1057 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1058 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1059 return -EIO;
1060 }
1061
1062 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1063 5 * HZ);
1064
1065 if (signal_pending(current)) {
1066 ath6kl_err("target did not respond\n");
1067 return -EINTR;
1068 }
1069 }
1070
1071 *dbm = ar->tx_pwr;
1072 return 0;
1073}
1074
1075static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1076 struct net_device *dev,
1077 bool pmgmt, int timeout)
1078{
1079 struct ath6kl *ar = ath6kl_priv(dev);
1080 struct wmi_power_mode_cmd mode;
1081
1082 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1083 __func__, pmgmt, timeout);
1084
1085 if (!ath6kl_cfg80211_ready(ar))
1086 return -EIO;
1087
1088 if (pmgmt) {
1089 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1090 mode.pwr_mode = REC_POWER;
1091 } else {
1092 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1093 mode.pwr_mode = MAX_PERF_POWER;
1094 }
1095
1096 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1097 ath6kl_err("wmi_powermode_cmd failed\n");
1098 return -EIO;
1099 }
1100
1101 return 0;
1102}
1103
1104static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1105 struct net_device *ndev,
1106 enum nl80211_iftype type, u32 *flags,
1107 struct vif_params *params)
1108{
1109 struct ath6kl *ar = ath6kl_priv(ndev);
1110 struct wireless_dev *wdev = ar->wdev;
1111
1112 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1113
1114 if (!ath6kl_cfg80211_ready(ar))
1115 return -EIO;
1116
1117 switch (type) {
1118 case NL80211_IFTYPE_STATION:
1119 ar->next_mode = INFRA_NETWORK;
1120 break;
1121 case NL80211_IFTYPE_ADHOC:
1122 ar->next_mode = ADHOC_NETWORK;
1123 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001124 case NL80211_IFTYPE_AP:
1125 ar->next_mode = AP_NETWORK;
1126 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001127 case NL80211_IFTYPE_P2P_CLIENT:
1128 ar->next_mode = INFRA_NETWORK;
1129 break;
1130 case NL80211_IFTYPE_P2P_GO:
1131 ar->next_mode = AP_NETWORK;
1132 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001133 default:
1134 ath6kl_err("invalid interface type %u\n", type);
1135 return -EOPNOTSUPP;
1136 }
1137
1138 wdev->iftype = type;
1139
1140 return 0;
1141}
1142
1143static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1144 struct net_device *dev,
1145 struct cfg80211_ibss_params *ibss_param)
1146{
1147 struct ath6kl *ar = ath6kl_priv(dev);
1148 int status;
1149
1150 if (!ath6kl_cfg80211_ready(ar))
1151 return -EIO;
1152
1153 ar->ssid_len = ibss_param->ssid_len;
1154 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1155
1156 if (ibss_param->channel)
1157 ar->ch_hint = ibss_param->channel->center_freq;
1158
1159 if (ibss_param->channel_fixed) {
1160 /*
1161 * TODO: channel_fixed: The channel should be fixed, do not
1162 * search for IBSSs to join on other channels. Target
1163 * firmware does not support this feature, needs to be
1164 * updated.
1165 */
1166 return -EOPNOTSUPP;
1167 }
1168
1169 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1170 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1171 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1172
1173 ath6kl_set_wpa_version(ar, 0);
1174
1175 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1176 if (status)
1177 return status;
1178
1179 if (ibss_param->privacy) {
1180 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1181 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1182 } else {
1183 ath6kl_set_cipher(ar, 0, true);
1184 ath6kl_set_cipher(ar, 0, false);
1185 }
1186
1187 ar->nw_type = ar->next_mode;
1188
1189 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1190 "%s: connect called with authmode %d dot11 auth %d"
1191 " PW crypto %d PW crypto len %d GRP crypto %d"
1192 " GRP crypto len %d channel hint %u\n",
1193 __func__,
1194 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1195 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001196 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001197
1198 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1199 ar->dot11_auth_mode, ar->auth_mode,
1200 ar->prwise_crypto,
1201 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001202 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001203 ar->ssid_len, ar->ssid,
1204 ar->req_bssid, ar->ch_hint,
1205 ar->connect_ctrl_flags);
1206 set_bit(CONNECT_PEND, &ar->flag);
1207
1208 return 0;
1209}
1210
1211static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1212 struct net_device *dev)
1213{
1214 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1215
1216 if (!ath6kl_cfg80211_ready(ar))
1217 return -EIO;
1218
1219 ath6kl_disconnect(ar);
1220 memset(ar->ssid, 0, sizeof(ar->ssid));
1221 ar->ssid_len = 0;
1222
1223 return 0;
1224}
1225
1226static const u32 cipher_suites[] = {
1227 WLAN_CIPHER_SUITE_WEP40,
1228 WLAN_CIPHER_SUITE_WEP104,
1229 WLAN_CIPHER_SUITE_TKIP,
1230 WLAN_CIPHER_SUITE_CCMP,
1231};
1232
1233static bool is_rate_legacy(s32 rate)
1234{
1235 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1236 6000, 9000, 12000, 18000, 24000,
1237 36000, 48000, 54000
1238 };
1239 u8 i;
1240
1241 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1242 if (rate == legacy[i])
1243 return true;
1244
1245 return false;
1246}
1247
1248static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1249{
1250 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1251 52000, 58500, 65000, 72200
1252 };
1253 u8 i;
1254
1255 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1256 if (rate == ht20[i]) {
1257 if (i == ARRAY_SIZE(ht20) - 1)
1258 /* last rate uses sgi */
1259 *sgi = true;
1260 else
1261 *sgi = false;
1262
1263 *mcs = i;
1264 return true;
1265 }
1266 }
1267 return false;
1268}
1269
1270static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1271{
1272 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1273 81000, 108000, 121500, 135000,
1274 150000
1275 };
1276 u8 i;
1277
1278 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1279 if (rate == ht40[i]) {
1280 if (i == ARRAY_SIZE(ht40) - 1)
1281 /* last rate uses sgi */
1282 *sgi = true;
1283 else
1284 *sgi = false;
1285
1286 *mcs = i;
1287 return true;
1288 }
1289 }
1290
1291 return false;
1292}
1293
1294static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1295 u8 *mac, struct station_info *sinfo)
1296{
1297 struct ath6kl *ar = ath6kl_priv(dev);
1298 long left;
1299 bool sgi;
1300 s32 rate;
1301 int ret;
1302 u8 mcs;
1303
1304 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1305 return -ENOENT;
1306
1307 if (down_interruptible(&ar->sem))
1308 return -EBUSY;
1309
1310 set_bit(STATS_UPDATE_PEND, &ar->flag);
1311
1312 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1313
1314 if (ret != 0) {
1315 up(&ar->sem);
1316 return -EIO;
1317 }
1318
1319 left = wait_event_interruptible_timeout(ar->event_wq,
1320 !test_bit(STATS_UPDATE_PEND,
1321 &ar->flag),
1322 WMI_TIMEOUT);
1323
1324 up(&ar->sem);
1325
1326 if (left == 0)
1327 return -ETIMEDOUT;
1328 else if (left < 0)
1329 return left;
1330
1331 if (ar->target_stats.rx_byte) {
1332 sinfo->rx_bytes = ar->target_stats.rx_byte;
1333 sinfo->filled |= STATION_INFO_RX_BYTES;
1334 sinfo->rx_packets = ar->target_stats.rx_pkt;
1335 sinfo->filled |= STATION_INFO_RX_PACKETS;
1336 }
1337
1338 if (ar->target_stats.tx_byte) {
1339 sinfo->tx_bytes = ar->target_stats.tx_byte;
1340 sinfo->filled |= STATION_INFO_TX_BYTES;
1341 sinfo->tx_packets = ar->target_stats.tx_pkt;
1342 sinfo->filled |= STATION_INFO_TX_PACKETS;
1343 }
1344
1345 sinfo->signal = ar->target_stats.cs_rssi;
1346 sinfo->filled |= STATION_INFO_SIGNAL;
1347
1348 rate = ar->target_stats.tx_ucast_rate;
1349
1350 if (is_rate_legacy(rate)) {
1351 sinfo->txrate.legacy = rate / 100;
1352 } else if (is_rate_ht20(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_MCS;
1361 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1362 if (sgi) {
1363 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1364 sinfo->txrate.mcs = mcs - 1;
1365 } else {
1366 sinfo->txrate.mcs = mcs;
1367 }
1368
1369 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1370 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1371 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001372 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1373 "invalid rate from stats: %d\n", rate);
1374 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001375 return 0;
1376 }
1377
1378 sinfo->filled |= STATION_INFO_TX_BITRATE;
1379
Jouni Malinen32c10872011-09-19 19:15:07 +03001380 if (test_bit(CONNECTED, &ar->flag) &&
1381 test_bit(DTIM_PERIOD_AVAIL, &ar->flag) &&
1382 ar->nw_type == INFRA_NETWORK) {
1383 sinfo->filled |= STATION_INFO_BSS_PARAM;
1384 sinfo->bss_param.flags = 0;
1385 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1386 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1387 }
1388
Kalle Valobdcd8172011-07-18 00:22:30 +03001389 return 0;
1390}
1391
1392static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1393 struct cfg80211_pmksa *pmksa)
1394{
1395 struct ath6kl *ar = ath6kl_priv(netdev);
1396 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1397 pmksa->pmkid, true);
1398}
1399
1400static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1401 struct cfg80211_pmksa *pmksa)
1402{
1403 struct ath6kl *ar = ath6kl_priv(netdev);
1404 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1405 pmksa->pmkid, false);
1406}
1407
1408static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1409{
1410 struct ath6kl *ar = ath6kl_priv(netdev);
1411 if (test_bit(CONNECTED, &ar->flag))
1412 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1413 return 0;
1414}
1415
Kalle Valoabcb3442011-07-22 08:26:20 +03001416#ifdef CONFIG_PM
1417static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1418 struct cfg80211_wowlan *wow)
1419{
1420 struct ath6kl *ar = wiphy_priv(wiphy);
1421
1422 return ath6kl_hif_suspend(ar);
1423}
1424#endif
1425
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001426static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1427 struct ieee80211_channel *chan,
1428 enum nl80211_channel_type channel_type)
1429{
1430 struct ath6kl *ar = ath6kl_priv(dev);
1431
1432 if (!ath6kl_cfg80211_ready(ar))
1433 return -EIO;
1434
1435 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1436 __func__, chan->center_freq, chan->hw_value);
1437 ar->next_chan = chan->center_freq;
1438
1439 return 0;
1440}
1441
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001442static bool ath6kl_is_p2p_ie(const u8 *pos)
1443{
1444 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1445 pos[2] == 0x50 && pos[3] == 0x6f &&
1446 pos[4] == 0x9a && pos[5] == 0x09;
1447}
1448
1449static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1450 size_t ies_len)
1451{
1452 const u8 *pos;
1453 u8 *buf = NULL;
1454 size_t len = 0;
1455 int ret;
1456
1457 /*
1458 * Filter out P2P IE(s) since they will be included depending on
1459 * the Probe Request frame in ath6kl_send_go_probe_resp().
1460 */
1461
1462 if (ies && ies_len) {
1463 buf = kmalloc(ies_len, GFP_KERNEL);
1464 if (buf == NULL)
1465 return -ENOMEM;
1466 pos = ies;
1467 while (pos + 1 < ies + ies_len) {
1468 if (pos + 2 + pos[1] > ies + ies_len)
1469 break;
1470 if (!ath6kl_is_p2p_ie(pos)) {
1471 memcpy(buf + len, pos, 2 + pos[1]);
1472 len += 2 + pos[1];
1473 }
1474 pos += 2 + pos[1];
1475 }
1476 }
1477
1478 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1479 buf, len);
1480 kfree(buf);
1481 return ret;
1482}
1483
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001484static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1485 struct beacon_parameters *info, bool add)
1486{
1487 struct ath6kl *ar = ath6kl_priv(dev);
1488 struct ieee80211_mgmt *mgmt;
1489 u8 *ies;
1490 int ies_len;
1491 struct wmi_connect_cmd p;
1492 int res;
1493 int i;
1494
1495 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1496
1497 if (!ath6kl_cfg80211_ready(ar))
1498 return -EIO;
1499
1500 if (ar->next_mode != AP_NETWORK)
1501 return -EOPNOTSUPP;
1502
1503 if (info->beacon_ies) {
1504 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1505 info->beacon_ies,
1506 info->beacon_ies_len);
1507 if (res)
1508 return res;
1509 }
1510 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001511 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1512 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001513 if (res)
1514 return res;
1515 }
1516 if (info->assocresp_ies) {
1517 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1518 info->assocresp_ies,
1519 info->assocresp_ies_len);
1520 if (res)
1521 return res;
1522 }
1523
1524 if (!add)
1525 return 0;
1526
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001527 ar->ap_mode_bkey.valid = false;
1528
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001529 /* TODO:
1530 * info->interval
1531 * info->dtim_period
1532 */
1533
1534 if (info->head == NULL)
1535 return -EINVAL;
1536 mgmt = (struct ieee80211_mgmt *) info->head;
1537 ies = mgmt->u.beacon.variable;
1538 if (ies > info->head + info->head_len)
1539 return -EINVAL;
1540 ies_len = info->head + info->head_len - ies;
1541
1542 if (info->ssid == NULL)
1543 return -EINVAL;
1544 memcpy(ar->ssid, info->ssid, info->ssid_len);
1545 ar->ssid_len = info->ssid_len;
1546 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1547 return -EOPNOTSUPP; /* TODO */
1548
1549 ar->dot11_auth_mode = OPEN_AUTH;
1550
1551 memset(&p, 0, sizeof(p));
1552
1553 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1554 switch (info->crypto.akm_suites[i]) {
1555 case WLAN_AKM_SUITE_8021X:
1556 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1557 p.auth_mode |= WPA_AUTH;
1558 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1559 p.auth_mode |= WPA2_AUTH;
1560 break;
1561 case WLAN_AKM_SUITE_PSK:
1562 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1563 p.auth_mode |= WPA_PSK_AUTH;
1564 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1565 p.auth_mode |= WPA2_PSK_AUTH;
1566 break;
1567 }
1568 }
1569 if (p.auth_mode == 0)
1570 p.auth_mode = NONE_AUTH;
1571 ar->auth_mode = p.auth_mode;
1572
1573 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1574 switch (info->crypto.ciphers_pairwise[i]) {
1575 case WLAN_CIPHER_SUITE_WEP40:
1576 case WLAN_CIPHER_SUITE_WEP104:
1577 p.prwise_crypto_type |= WEP_CRYPT;
1578 break;
1579 case WLAN_CIPHER_SUITE_TKIP:
1580 p.prwise_crypto_type |= TKIP_CRYPT;
1581 break;
1582 case WLAN_CIPHER_SUITE_CCMP:
1583 p.prwise_crypto_type |= AES_CRYPT;
1584 break;
1585 }
1586 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001587 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001588 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001589 ath6kl_set_cipher(ar, 0, true);
1590 } else if (info->crypto.n_ciphers_pairwise == 1)
1591 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001592
1593 switch (info->crypto.cipher_group) {
1594 case WLAN_CIPHER_SUITE_WEP40:
1595 case WLAN_CIPHER_SUITE_WEP104:
1596 p.grp_crypto_type = WEP_CRYPT;
1597 break;
1598 case WLAN_CIPHER_SUITE_TKIP:
1599 p.grp_crypto_type = TKIP_CRYPT;
1600 break;
1601 case WLAN_CIPHER_SUITE_CCMP:
1602 p.grp_crypto_type = AES_CRYPT;
1603 break;
1604 default:
1605 p.grp_crypto_type = NONE_CRYPT;
1606 break;
1607 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001608 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001609
1610 p.nw_type = AP_NETWORK;
1611 ar->nw_type = ar->next_mode;
1612
1613 p.ssid_len = ar->ssid_len;
1614 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1615 p.dot11_auth_mode = ar->dot11_auth_mode;
1616 p.ch = cpu_to_le16(ar->next_chan);
1617
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001618 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1619 if (res < 0)
1620 return res;
1621
1622 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001623}
1624
1625static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1626 struct beacon_parameters *info)
1627{
1628 return ath6kl_ap_beacon(wiphy, dev, info, true);
1629}
1630
1631static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1632 struct beacon_parameters *info)
1633{
1634 return ath6kl_ap_beacon(wiphy, dev, info, false);
1635}
1636
1637static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1638{
1639 struct ath6kl *ar = ath6kl_priv(dev);
1640
1641 if (ar->nw_type != AP_NETWORK)
1642 return -EOPNOTSUPP;
1643 if (!test_bit(CONNECTED, &ar->flag))
1644 return -ENOTCONN;
1645
1646 ath6kl_wmi_disconnect_cmd(ar->wmi);
1647 clear_bit(CONNECTED, &ar->flag);
1648
1649 return 0;
1650}
1651
Jouni Malinen23875132011-08-30 21:57:53 +03001652static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1653 u8 *mac, struct station_parameters *params)
1654{
1655 struct ath6kl *ar = ath6kl_priv(dev);
1656
1657 if (ar->nw_type != AP_NETWORK)
1658 return -EOPNOTSUPP;
1659
1660 /* Use this only for authorizing/unauthorizing a station */
1661 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1662 return -EOPNOTSUPP;
1663
1664 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1665 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1666 mac, 0);
1667 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1668 0);
1669}
1670
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001671static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1672 struct net_device *dev,
1673 struct ieee80211_channel *chan,
1674 enum nl80211_channel_type channel_type,
1675 unsigned int duration,
1676 u64 *cookie)
1677{
1678 struct ath6kl *ar = ath6kl_priv(dev);
1679
1680 /* TODO: if already pending or ongoing remain-on-channel,
1681 * return -EBUSY */
1682 *cookie = 1; /* only a single pending request is supported */
1683
1684 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1685 duration);
1686}
1687
1688static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1689 struct net_device *dev,
1690 u64 cookie)
1691{
1692 struct ath6kl *ar = ath6kl_priv(dev);
1693
1694 if (cookie != 1)
1695 return -ENOENT;
1696
1697 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1698}
1699
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001700static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1701 size_t len, unsigned int freq)
1702{
1703 const u8 *pos;
1704 u8 *p2p;
1705 int p2p_len;
1706 int ret;
1707 const struct ieee80211_mgmt *mgmt;
1708
1709 mgmt = (const struct ieee80211_mgmt *) buf;
1710
1711 /* Include P2P IE(s) from the frame generated in user space. */
1712
1713 p2p = kmalloc(len, GFP_KERNEL);
1714 if (p2p == NULL)
1715 return -ENOMEM;
1716 p2p_len = 0;
1717
1718 pos = mgmt->u.probe_resp.variable;
1719 while (pos + 1 < buf + len) {
1720 if (pos + 2 + pos[1] > buf + len)
1721 break;
1722 if (ath6kl_is_p2p_ie(pos)) {
1723 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1724 p2p_len += 2 + pos[1];
1725 }
1726 pos += 2 + pos[1];
1727 }
1728
1729 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1730 p2p, p2p_len);
1731 kfree(p2p);
1732 return ret;
1733}
1734
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001735static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1736 struct ieee80211_channel *chan, bool offchan,
1737 enum nl80211_channel_type channel_type,
1738 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001739 const u8 *buf, size_t len, bool no_cck,
1740 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001741{
1742 struct ath6kl *ar = ath6kl_priv(dev);
1743 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001744 const struct ieee80211_mgmt *mgmt;
1745
1746 mgmt = (const struct ieee80211_mgmt *) buf;
1747 if (buf + len >= mgmt->u.probe_resp.variable &&
1748 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1749 ieee80211_is_probe_resp(mgmt->frame_control)) {
1750 /*
1751 * Send Probe Response frame in AP mode using a separate WMI
1752 * command to allow the target to fill in the generic IEs.
1753 */
1754 *cookie = 0; /* TX status not supported */
1755 return ath6kl_send_go_probe_resp(ar, buf, len,
1756 chan->center_freq);
1757 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001758
1759 id = ar->send_action_id++;
1760 if (id == 0) {
1761 /*
1762 * 0 is a reserved value in the WMI command and shall not be
1763 * used for the command.
1764 */
1765 id = ar->send_action_id++;
1766 }
1767
1768 *cookie = id;
1769 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1770 buf, len);
1771}
1772
Jouni Malinenae32c302011-08-30 21:58:01 +03001773static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1774 struct net_device *dev,
1775 u16 frame_type, bool reg)
1776{
1777 struct ath6kl *ar = ath6kl_priv(dev);
1778
1779 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1780 __func__, frame_type, reg);
1781 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1782 /*
1783 * Note: This notification callback is not allowed to sleep, so
1784 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1785 * hardcode target to report Probe Request frames all the time.
1786 */
1787 ar->probe_req_report = reg;
1788 }
1789}
1790
Jouni Malinenf80574a2011-08-30 21:58:04 +03001791static const struct ieee80211_txrx_stypes
1792ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1793 [NL80211_IFTYPE_STATION] = {
1794 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1795 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1796 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1797 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1798 },
1799 [NL80211_IFTYPE_P2P_CLIENT] = {
1800 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1801 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1802 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1803 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1804 },
1805 [NL80211_IFTYPE_P2P_GO] = {
1806 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1807 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1808 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1809 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1810 },
1811};
1812
Kalle Valobdcd8172011-07-18 00:22:30 +03001813static struct cfg80211_ops ath6kl_cfg80211_ops = {
1814 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1815 .scan = ath6kl_cfg80211_scan,
1816 .connect = ath6kl_cfg80211_connect,
1817 .disconnect = ath6kl_cfg80211_disconnect,
1818 .add_key = ath6kl_cfg80211_add_key,
1819 .get_key = ath6kl_cfg80211_get_key,
1820 .del_key = ath6kl_cfg80211_del_key,
1821 .set_default_key = ath6kl_cfg80211_set_default_key,
1822 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1823 .set_tx_power = ath6kl_cfg80211_set_txpower,
1824 .get_tx_power = ath6kl_cfg80211_get_txpower,
1825 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1826 .join_ibss = ath6kl_cfg80211_join_ibss,
1827 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1828 .get_station = ath6kl_get_station,
1829 .set_pmksa = ath6kl_set_pmksa,
1830 .del_pmksa = ath6kl_del_pmksa,
1831 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001832 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001833#ifdef CONFIG_PM
1834 .suspend = ar6k_cfg80211_suspend,
1835#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001836 .set_channel = ath6kl_set_channel,
1837 .add_beacon = ath6kl_add_beacon,
1838 .set_beacon = ath6kl_set_beacon,
1839 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001840 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001841 .remain_on_channel = ath6kl_remain_on_channel,
1842 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001843 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001844 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001845};
1846
1847struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1848{
1849 int ret = 0;
1850 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001851 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001852
1853 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1854 if (!wdev) {
1855 ath6kl_err("couldn't allocate wireless device\n");
1856 return NULL;
1857 }
1858
1859 /* create a new wiphy for use with cfg80211 */
1860 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1861 if (!wdev->wiphy) {
1862 ath6kl_err("couldn't allocate wiphy device\n");
1863 kfree(wdev);
1864 return NULL;
1865 }
1866
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001867 ar = wiphy_priv(wdev->wiphy);
1868 ar->p2p = !!ath6kl_p2p;
1869
Jouni Malinenf80574a2011-08-30 21:58:04 +03001870 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1871
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001872 wdev->wiphy->max_remain_on_channel_duration = 5000;
1873
Kalle Valobdcd8172011-07-18 00:22:30 +03001874 /* set device pointer for wiphy */
1875 set_wiphy_dev(wdev->wiphy, dev);
1876
1877 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001878 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001879 if (ar->p2p) {
1880 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1881 BIT(NL80211_IFTYPE_P2P_CLIENT);
1882 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001883 /* max num of ssids that can be probed during scanning */
1884 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001885 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001886 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1887 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1888 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1889
1890 wdev->wiphy->cipher_suites = cipher_suites;
1891 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1892
1893 ret = wiphy_register(wdev->wiphy);
1894 if (ret < 0) {
1895 ath6kl_err("couldn't register wiphy device\n");
1896 wiphy_free(wdev->wiphy);
1897 kfree(wdev);
1898 return NULL;
1899 }
1900
1901 return wdev;
1902}
1903
1904void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1905{
1906 struct wireless_dev *wdev = ar->wdev;
1907
1908 if (ar->scan_req) {
1909 cfg80211_scan_done(ar->scan_req, true);
1910 ar->scan_req = NULL;
1911 }
1912
1913 if (!wdev)
1914 return;
1915
1916 wiphy_unregister(wdev->wiphy);
1917 wiphy_free(wdev->wiphy);
1918 kfree(wdev);
1919}