blob: 5ede3d2f1f2ac0fa3dc585e2bd53a17bf7ea9ebc [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) {
363 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
364 ath6kl_err("couldn't set bss filtering\n");
365 up(&ar->sem);
366 return -EIO;
367 }
368 }
369
370 ar->nw_type = ar->next_mode;
371
372 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
373 "%s: connect called with authmode %d dot11 auth %d"
374 " PW crypto %d PW crypto len %d GRP crypto %d"
375 " GRP crypto len %d channel hint %u\n",
376 __func__,
377 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
378 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +0300379 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300380
381 ar->reconnect_flag = 0;
382 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
383 ar->dot11_auth_mode, ar->auth_mode,
384 ar->prwise_crypto,
385 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +0300386 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +0300387 ar->ssid_len, ar->ssid,
388 ar->req_bssid, ar->ch_hint,
389 ar->connect_ctrl_flags);
390
391 up(&ar->sem);
392
393 if (status == -EINVAL) {
394 memset(ar->ssid, 0, sizeof(ar->ssid));
395 ar->ssid_len = 0;
396 ath6kl_err("invalid request\n");
397 return -ENOENT;
398 } else if (status) {
399 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
400 return -EIO;
401 }
402
403 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
404 ((ar->auth_mode == WPA_PSK_AUTH)
405 || (ar->auth_mode == WPA2_PSK_AUTH))) {
406 mod_timer(&ar->disconnect_timer,
407 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
408 }
409
410 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
411 set_bit(CONNECT_PEND, &ar->flag);
412
413 return 0;
414}
415
Jouni Malinen01cac472011-09-19 19:14:59 +0300416static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
417 struct ieee80211_channel *chan,
418 const u8 *beacon_ie, size_t beacon_ie_len)
419{
420 struct cfg80211_bss *bss;
421 u8 *ie;
422
423 bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid,
424 ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
425 WLAN_CAPABILITY_ESS);
426 if (bss == NULL) {
427 /*
428 * Since cfg80211 may not yet know about the BSS,
429 * generate a partial entry until the first BSS info
430 * event becomes available.
431 *
432 * Prepend SSID element since it is not included in the Beacon
433 * IEs from the target.
434 */
435 ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
436 if (ie == NULL)
437 return -ENOMEM;
438 ie[0] = WLAN_EID_SSID;
439 ie[1] = ar->ssid_len;
440 memcpy(ie + 2, ar->ssid, ar->ssid_len);
441 memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
442 bss = cfg80211_inform_bss(ar->wdev->wiphy, chan,
443 bssid, 0, WLAN_CAPABILITY_ESS, 100,
444 ie, 2 + ar->ssid_len + beacon_ie_len,
445 0, GFP_KERNEL);
446 if (bss)
447 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
448 "%pM prior to indicating connect/roamed "
449 "event\n", bssid);
450 kfree(ie);
451 } else
452 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
453 "entry\n");
454
455 if (bss == NULL)
456 return -ENOMEM;
457
458 cfg80211_put_bss(bss);
459
460 return 0;
461}
462
Kalle Valobdcd8172011-07-18 00:22:30 +0300463void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
464 u8 *bssid, u16 listen_intvl,
465 u16 beacon_intvl,
466 enum network_type nw_type,
467 u8 beacon_ie_len, u8 assoc_req_len,
468 u8 assoc_resp_len, u8 *assoc_info)
469{
Jouni Malinen01cac472011-09-19 19:14:59 +0300470 struct ieee80211_channel *chan;
Kalle Valobdcd8172011-07-18 00:22:30 +0300471
472 /* capinfo + listen interval */
473 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
474
475 /* capinfo + status code + associd */
476 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
477
478 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
479 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
480 assoc_resp_ie_offset;
481
482 assoc_req_len -= assoc_req_ie_offset;
483 assoc_resp_len -= assoc_resp_ie_offset;
484
Kalle Valobdcd8172011-07-18 00:22:30 +0300485 if (nw_type & ADHOC_NETWORK) {
486 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
487 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
488 "%s: ath6k not in ibss mode\n", __func__);
489 return;
490 }
491 }
492
493 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300494 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
495 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300496 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
497 "%s: ath6k not in station mode\n", __func__);
498 return;
499 }
500 }
501
Jouni Malinen01cac472011-09-19 19:14:59 +0300502 chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300503
Kalle Valobdcd8172011-07-18 00:22:30 +0300504
505 if (nw_type & ADHOC_NETWORK) {
506 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
507 return;
508 }
509
Jouni Malinen01cac472011-09-19 19:14:59 +0300510 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
511 beacon_ie_len) < 0) {
512 ath6kl_err("could not add cfg80211 bss entry for "
513 "connect/roamed notification\n");
514 return;
515 }
516
Raja Mani9aa60352011-08-04 19:26:29 +0530517 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300518 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530519 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300520 cfg80211_connect_result(ar->net_dev, bssid,
521 assoc_req_ie, assoc_req_len,
522 assoc_resp_ie, assoc_resp_len,
523 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530524 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300525 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300526 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300527 assoc_req_ie, assoc_req_len,
528 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
529 }
530}
531
532static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
533 struct net_device *dev, u16 reason_code)
534{
535 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
536
537 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
538 reason_code);
539
540 if (!ath6kl_cfg80211_ready(ar))
541 return -EIO;
542
543 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
544 ath6kl_err("busy, destroy in progress\n");
545 return -EBUSY;
546 }
547
548 if (down_interruptible(&ar->sem)) {
549 ath6kl_err("busy, couldn't get access\n");
550 return -ERESTARTSYS;
551 }
552
553 ar->reconnect_flag = 0;
554 ath6kl_disconnect(ar);
555 memset(ar->ssid, 0, sizeof(ar->ssid));
556 ar->ssid_len = 0;
557
558 if (!test_bit(SKIP_SCAN, &ar->flag))
559 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
560
561 up(&ar->sem);
562
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530563 ar->sme_state = SME_DISCONNECTED;
564
Kalle Valobdcd8172011-07-18 00:22:30 +0300565 return 0;
566}
567
568void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
569 u8 *bssid, u8 assoc_resp_len,
570 u8 *assoc_info, u16 proto_reason)
571{
Kalle Valobdcd8172011-07-18 00:22:30 +0300572 if (ar->scan_req) {
573 cfg80211_scan_done(ar->scan_req, true);
574 ar->scan_req = NULL;
575 }
576
577 if (ar->nw_type & ADHOC_NETWORK) {
578 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
579 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
580 "%s: ath6k not in ibss mode\n", __func__);
581 return;
582 }
583 memset(bssid, 0, ETH_ALEN);
584 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
585 return;
586 }
587
588 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300589 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
590 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300591 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
592 "%s: ath6k not in station mode\n", __func__);
593 return;
594 }
595 }
596
597 if (!test_bit(CONNECT_PEND, &ar->flag)) {
598 if (reason != DISCONNECT_CMD)
599 ath6kl_wmi_disconnect_cmd(ar->wmi);
600
601 return;
602 }
603
604 if (reason == NO_NETWORK_AVAIL) {
605 /* connect cmd failed */
606 ath6kl_wmi_disconnect_cmd(ar->wmi);
607 return;
608 }
609
610 if (reason != DISCONNECT_CMD)
611 return;
612
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530613 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300614
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530615 if (ar->sme_state == SME_CONNECTING) {
616 cfg80211_connect_result(ar->net_dev,
617 bssid, NULL, 0,
618 NULL, 0,
619 WLAN_STATUS_UNSPECIFIED_FAILURE,
620 GFP_KERNEL);
621 } else if (ar->sme_state == SME_CONNECTED) {
622 cfg80211_disconnected(ar->net_dev, reason,
623 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300624 }
625
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530626 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300627}
628
629static inline bool is_ch_11a(u16 ch)
630{
631 return (!((ch >= 2412) && (ch <= 2484)));
632}
633
Kalle Valocf104c22011-07-21 10:04:54 +0300634/* struct ath6kl_node_table::nt_nodelock is locked when calling this */
Vasanthakumar Thiagarajan91db35d2011-07-21 18:12:15 +0530635void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni)
Kalle Valobdcd8172011-07-18 00:22:30 +0300636{
Kalle Valobdcd8172011-07-18 00:22:30 +0300637 struct ieee80211_mgmt *mgmt;
638 struct ieee80211_channel *channel;
639 struct ieee80211_supported_band *band;
640 struct ath6kl_common_ie *cie;
641 s32 signal;
642 int freq;
643
644 cie = &ni->ni_cie;
645
646 if (is_ch_11a(cie->ie_chan))
647 band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */
648 else if ((cie->ie_erp) || (cie->ie_xrates))
649 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */
650 else
651 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */
652
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 freq = cie->ie_chan;
654 channel = ieee80211_get_channel(wiphy, freq);
655 signal = ni->ni_snr * 100;
656
657 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
658 "%s: bssid %pM ch %d freq %d size %d\n", __func__,
Jouni Malinen0ce77922011-08-11 00:32:49 +0300659 ni->ni_macaddr, channel->hw_value, freq, ni->ni_framelen);
660 /*
661 * Both Beacon and Probe Response frames have same payload structure,
662 * so it is fine to share the parser for both.
663 */
664 if (ni->ni_framelen < 8 + 2 + 2)
665 return;
666 mgmt = (struct ieee80211_mgmt *) (ni->ni_buf -
667 offsetof(struct ieee80211_mgmt, u));
668 cfg80211_inform_bss(wiphy, channel, ni->ni_macaddr,
669 le64_to_cpu(mgmt->u.beacon.timestamp),
670 le16_to_cpu(mgmt->u.beacon.capab_info),
671 le16_to_cpu(mgmt->u.beacon.beacon_int),
672 mgmt->u.beacon.variable,
673 ni->ni_buf + ni->ni_framelen -
674 mgmt->u.beacon.variable,
675 signal, GFP_ATOMIC);
Kalle Valobdcd8172011-07-18 00:22:30 +0300676}
677
678static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
679 struct cfg80211_scan_request *request)
680{
681 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300682 s8 n_channels = 0;
683 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300684 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300685
686 if (!ath6kl_cfg80211_ready(ar))
687 return -EIO;
688
689 if (!ar->usr_bss_filter) {
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300690 ret = ath6kl_wmi_bssfilter_cmd(
691 ar->wmi,
692 (test_bit(CONNECTED, &ar->flag) ?
693 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
694 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300695 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300696 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300697 }
698 }
699
700 if (request->n_ssids && request->ssids[0].ssid_len) {
701 u8 i;
702
703 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
704 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
705
706 for (i = 0; i < request->n_ssids; i++)
707 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
708 SPECIFIC_SSID_FLAG,
709 request->ssids[i].ssid_len,
710 request->ssids[i].ssid);
711 }
712
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300713 if (request->ie) {
714 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
715 request->ie, request->ie_len);
716 if (ret) {
717 ath6kl_err("failed to set Probe Request appie for "
718 "scan");
719 return ret;
720 }
721 }
722
Jouni Malinen11869be2011-09-02 20:07:06 +0300723 /*
724 * Scan only the requested channels if the request specifies a set of
725 * channels. If the list is longer than the target supports, do not
726 * configure the list and instead, scan all available channels.
727 */
728 if (request->n_channels > 0 &&
729 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300730 u8 i;
731
Jouni Malinen11869be2011-09-02 20:07:06 +0300732 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300733
734 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
735 if (channels == NULL) {
736 ath6kl_warn("failed to set scan channels, "
737 "scan all channels");
738 n_channels = 0;
739 }
740
741 for (i = 0; i < n_channels; i++)
742 channels[i] = request->channels[i]->center_freq;
743 }
744
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300745 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
746 false, 0, 0, n_channels, channels);
747 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300748 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300749 else
750 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300751
Edward Lu1276c9e2011-08-30 21:58:00 +0300752 kfree(channels);
753
Kalle Valobdcd8172011-07-18 00:22:30 +0300754 return ret;
755}
756
757void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
758{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300759 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300760
761 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
762
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300763 if (!ar->scan_req)
764 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300765
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300766 if ((status == -ECANCELED) || (status == -EBUSY)) {
767 cfg80211_scan_done(ar->scan_req, true);
768 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300769 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300770
771 /* Translate data to cfg80211 mgmt format */
Vasanthakumar Thiagarajan8a8bc5a2011-07-21 14:42:52 +0530772 wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300773
774 cfg80211_scan_done(ar->scan_req, false);
775
776 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
777 for (i = 0; i < ar->scan_req->n_ssids; i++) {
778 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
779 DISABLE_SSID_FLAG,
780 0, NULL);
781 }
782 }
783
784out:
785 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300786}
787
788static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
789 u8 key_index, bool pairwise,
790 const u8 *mac_addr,
791 struct key_params *params)
792{
793 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
794 struct ath6kl_key *key = NULL;
795 u8 key_usage;
796 u8 key_type;
797 int status = 0;
798
799 if (!ath6kl_cfg80211_ready(ar))
800 return -EIO;
801
802 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
803 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
804 "%s: key index %d out of bounds\n", __func__,
805 key_index);
806 return -ENOENT;
807 }
808
809 key = &ar->keys[key_index];
810 memset(key, 0, sizeof(struct ath6kl_key));
811
812 if (pairwise)
813 key_usage = PAIRWISE_USAGE;
814 else
815 key_usage = GROUP_USAGE;
816
817 if (params) {
818 if (params->key_len > WLAN_MAX_KEY_LEN ||
819 params->seq_len > sizeof(key->seq))
820 return -EINVAL;
821
822 key->key_len = params->key_len;
823 memcpy(key->key, params->key, key->key_len);
824 key->seq_len = params->seq_len;
825 memcpy(key->seq, params->seq, key->seq_len);
826 key->cipher = params->cipher;
827 }
828
829 switch (key->cipher) {
830 case WLAN_CIPHER_SUITE_WEP40:
831 case WLAN_CIPHER_SUITE_WEP104:
832 key_type = WEP_CRYPT;
833 break;
834
835 case WLAN_CIPHER_SUITE_TKIP:
836 key_type = TKIP_CRYPT;
837 break;
838
839 case WLAN_CIPHER_SUITE_CCMP:
840 key_type = AES_CRYPT;
841 break;
842
843 default:
844 return -ENOTSUPP;
845 }
846
847 if (((ar->auth_mode == WPA_PSK_AUTH)
848 || (ar->auth_mode == WPA2_PSK_AUTH))
849 && (key_usage & GROUP_USAGE))
850 del_timer(&ar->disconnect_timer);
851
852 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
853 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
854 __func__, key_index, key->key_len, key_type,
855 key_usage, key->seq_len);
856
857 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300858
859 if (ar->nw_type == AP_NETWORK && !pairwise &&
860 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
861 ar->ap_mode_bkey.valid = true;
862 ar->ap_mode_bkey.key_index = key_index;
863 ar->ap_mode_bkey.key_type = key_type;
864 ar->ap_mode_bkey.key_len = key->key_len;
865 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
866 if (!test_bit(CONNECTED, &ar->flag)) {
867 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
868 "key configuration until AP mode has been "
869 "started\n");
870 /*
871 * The key will be set in ath6kl_connect_ap_mode() once
872 * the connected event is received from the target.
873 */
874 return 0;
875 }
876 }
877
Jouni Malinen151411e2011-09-15 15:10:16 +0300878 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
879 !test_bit(CONNECTED, &ar->flag)) {
880 /*
881 * Store the key locally so that it can be re-configured after
882 * the AP mode has properly started
883 * (ath6kl_install_statioc_wep_keys).
884 */
885 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
886 "until AP mode has been started\n");
887 ar->wep_key_list[key_index].key_len = key->key_len;
888 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
889 return 0;
890 }
891
Kalle Valobdcd8172011-07-18 00:22:30 +0300892 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
893 key_type, key_usage, key->key_len,
894 key->seq, key->key, KEY_OP_INIT_VAL,
895 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
896
897 if (status)
898 return -EIO;
899
900 return 0;
901}
902
903static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
904 u8 key_index, bool pairwise,
905 const u8 *mac_addr)
906{
907 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
908
909 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
910
911 if (!ath6kl_cfg80211_ready(ar))
912 return -EIO;
913
914 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
915 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
916 "%s: key index %d out of bounds\n", __func__,
917 key_index);
918 return -ENOENT;
919 }
920
921 if (!ar->keys[key_index].key_len) {
922 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
923 "%s: index %d is empty\n", __func__, key_index);
924 return 0;
925 }
926
927 ar->keys[key_index].key_len = 0;
928
929 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
930}
931
932static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
933 u8 key_index, bool pairwise,
934 const u8 *mac_addr, void *cookie,
935 void (*callback) (void *cookie,
936 struct key_params *))
937{
938 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
939 struct ath6kl_key *key = NULL;
940 struct key_params params;
941
942 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
943
944 if (!ath6kl_cfg80211_ready(ar))
945 return -EIO;
946
947 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
948 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
949 "%s: key index %d out of bounds\n", __func__,
950 key_index);
951 return -ENOENT;
952 }
953
954 key = &ar->keys[key_index];
955 memset(&params, 0, sizeof(params));
956 params.cipher = key->cipher;
957 params.key_len = key->key_len;
958 params.seq_len = key->seq_len;
959 params.seq = key->seq;
960 params.key = key->key;
961
962 callback(cookie, &params);
963
964 return key->key_len ? 0 : -ENOENT;
965}
966
967static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
968 struct net_device *ndev,
969 u8 key_index, bool unicast,
970 bool multicast)
971{
972 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
973 struct ath6kl_key *key = NULL;
974 int status = 0;
975 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300976 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300977
978 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
979
980 if (!ath6kl_cfg80211_ready(ar))
981 return -EIO;
982
983 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
984 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
985 "%s: key index %d out of bounds\n",
986 __func__, key_index);
987 return -ENOENT;
988 }
989
990 if (!ar->keys[key_index].key_len) {
991 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
992 __func__, key_index);
993 return -EINVAL;
994 }
995
996 ar->def_txkey_index = key_index;
997 key = &ar->keys[ar->def_txkey_index];
998 key_usage = GROUP_USAGE;
999 if (ar->prwise_crypto == WEP_CRYPT)
1000 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001001 if (unicast)
1002 key_type = ar->prwise_crypto;
1003 if (multicast)
1004 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001005
Jouni Malinen151411e2011-09-15 15:10:16 +03001006 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001007 return 0; /* Delay until AP mode has been started */
1008
Kalle Valobdcd8172011-07-18 00:22:30 +03001009 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001010 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001011 key->key_len, key->seq, key->key,
1012 KEY_OP_INIT_VAL, NULL,
1013 SYNC_BOTH_WMIFLAG);
1014 if (status)
1015 return -EIO;
1016
1017 return 0;
1018}
1019
1020void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1021 bool ismcast)
1022{
1023 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1024 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1025
1026 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1027 (ismcast ? NL80211_KEYTYPE_GROUP :
1028 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1029 GFP_KERNEL);
1030}
1031
1032static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1033{
1034 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1035 int ret;
1036
1037 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1038 changed);
1039
1040 if (!ath6kl_cfg80211_ready(ar))
1041 return -EIO;
1042
1043 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1044 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1045 if (ret != 0) {
1046 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1047 return -EIO;
1048 }
1049 }
1050
1051 return 0;
1052}
1053
1054/*
1055 * The type nl80211_tx_power_setting replaces the following
1056 * data type from 2.6.36 onwards
1057*/
1058static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1059 enum nl80211_tx_power_setting type,
1060 int dbm)
1061{
1062 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1063 u8 ath6kl_dbm;
1064
1065 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1066 type, dbm);
1067
1068 if (!ath6kl_cfg80211_ready(ar))
1069 return -EIO;
1070
1071 switch (type) {
1072 case NL80211_TX_POWER_AUTOMATIC:
1073 return 0;
1074 case NL80211_TX_POWER_LIMITED:
1075 ar->tx_pwr = ath6kl_dbm = dbm;
1076 break;
1077 default:
1078 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1079 __func__, type);
1080 return -EOPNOTSUPP;
1081 }
1082
1083 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1084
1085 return 0;
1086}
1087
1088static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1089{
1090 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1091
1092 if (!ath6kl_cfg80211_ready(ar))
1093 return -EIO;
1094
1095 if (test_bit(CONNECTED, &ar->flag)) {
1096 ar->tx_pwr = 0;
1097
1098 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1099 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1100 return -EIO;
1101 }
1102
1103 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1104 5 * HZ);
1105
1106 if (signal_pending(current)) {
1107 ath6kl_err("target did not respond\n");
1108 return -EINTR;
1109 }
1110 }
1111
1112 *dbm = ar->tx_pwr;
1113 return 0;
1114}
1115
1116static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1117 struct net_device *dev,
1118 bool pmgmt, int timeout)
1119{
1120 struct ath6kl *ar = ath6kl_priv(dev);
1121 struct wmi_power_mode_cmd mode;
1122
1123 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1124 __func__, pmgmt, timeout);
1125
1126 if (!ath6kl_cfg80211_ready(ar))
1127 return -EIO;
1128
1129 if (pmgmt) {
1130 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1131 mode.pwr_mode = REC_POWER;
1132 } else {
1133 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1134 mode.pwr_mode = MAX_PERF_POWER;
1135 }
1136
1137 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1138 ath6kl_err("wmi_powermode_cmd failed\n");
1139 return -EIO;
1140 }
1141
1142 return 0;
1143}
1144
1145static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1146 struct net_device *ndev,
1147 enum nl80211_iftype type, u32 *flags,
1148 struct vif_params *params)
1149{
1150 struct ath6kl *ar = ath6kl_priv(ndev);
1151 struct wireless_dev *wdev = ar->wdev;
1152
1153 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1154
1155 if (!ath6kl_cfg80211_ready(ar))
1156 return -EIO;
1157
1158 switch (type) {
1159 case NL80211_IFTYPE_STATION:
1160 ar->next_mode = INFRA_NETWORK;
1161 break;
1162 case NL80211_IFTYPE_ADHOC:
1163 ar->next_mode = ADHOC_NETWORK;
1164 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001165 case NL80211_IFTYPE_AP:
1166 ar->next_mode = AP_NETWORK;
1167 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001168 case NL80211_IFTYPE_P2P_CLIENT:
1169 ar->next_mode = INFRA_NETWORK;
1170 break;
1171 case NL80211_IFTYPE_P2P_GO:
1172 ar->next_mode = AP_NETWORK;
1173 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001174 default:
1175 ath6kl_err("invalid interface type %u\n", type);
1176 return -EOPNOTSUPP;
1177 }
1178
1179 wdev->iftype = type;
1180
1181 return 0;
1182}
1183
1184static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1185 struct net_device *dev,
1186 struct cfg80211_ibss_params *ibss_param)
1187{
1188 struct ath6kl *ar = ath6kl_priv(dev);
1189 int status;
1190
1191 if (!ath6kl_cfg80211_ready(ar))
1192 return -EIO;
1193
1194 ar->ssid_len = ibss_param->ssid_len;
1195 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1196
1197 if (ibss_param->channel)
1198 ar->ch_hint = ibss_param->channel->center_freq;
1199
1200 if (ibss_param->channel_fixed) {
1201 /*
1202 * TODO: channel_fixed: The channel should be fixed, do not
1203 * search for IBSSs to join on other channels. Target
1204 * firmware does not support this feature, needs to be
1205 * updated.
1206 */
1207 return -EOPNOTSUPP;
1208 }
1209
1210 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1211 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1212 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1213
1214 ath6kl_set_wpa_version(ar, 0);
1215
1216 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1217 if (status)
1218 return status;
1219
1220 if (ibss_param->privacy) {
1221 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1222 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1223 } else {
1224 ath6kl_set_cipher(ar, 0, true);
1225 ath6kl_set_cipher(ar, 0, false);
1226 }
1227
1228 ar->nw_type = ar->next_mode;
1229
1230 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1231 "%s: connect called with authmode %d dot11 auth %d"
1232 " PW crypto %d PW crypto len %d GRP crypto %d"
1233 " GRP crypto len %d channel hint %u\n",
1234 __func__,
1235 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1236 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001237 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001238
1239 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1240 ar->dot11_auth_mode, ar->auth_mode,
1241 ar->prwise_crypto,
1242 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001243 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001244 ar->ssid_len, ar->ssid,
1245 ar->req_bssid, ar->ch_hint,
1246 ar->connect_ctrl_flags);
1247 set_bit(CONNECT_PEND, &ar->flag);
1248
1249 return 0;
1250}
1251
1252static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1253 struct net_device *dev)
1254{
1255 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1256
1257 if (!ath6kl_cfg80211_ready(ar))
1258 return -EIO;
1259
1260 ath6kl_disconnect(ar);
1261 memset(ar->ssid, 0, sizeof(ar->ssid));
1262 ar->ssid_len = 0;
1263
1264 return 0;
1265}
1266
1267static const u32 cipher_suites[] = {
1268 WLAN_CIPHER_SUITE_WEP40,
1269 WLAN_CIPHER_SUITE_WEP104,
1270 WLAN_CIPHER_SUITE_TKIP,
1271 WLAN_CIPHER_SUITE_CCMP,
1272};
1273
1274static bool is_rate_legacy(s32 rate)
1275{
1276 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1277 6000, 9000, 12000, 18000, 24000,
1278 36000, 48000, 54000
1279 };
1280 u8 i;
1281
1282 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1283 if (rate == legacy[i])
1284 return true;
1285
1286 return false;
1287}
1288
1289static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1290{
1291 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1292 52000, 58500, 65000, 72200
1293 };
1294 u8 i;
1295
1296 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1297 if (rate == ht20[i]) {
1298 if (i == ARRAY_SIZE(ht20) - 1)
1299 /* last rate uses sgi */
1300 *sgi = true;
1301 else
1302 *sgi = false;
1303
1304 *mcs = i;
1305 return true;
1306 }
1307 }
1308 return false;
1309}
1310
1311static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1312{
1313 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1314 81000, 108000, 121500, 135000,
1315 150000
1316 };
1317 u8 i;
1318
1319 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1320 if (rate == ht40[i]) {
1321 if (i == ARRAY_SIZE(ht40) - 1)
1322 /* last rate uses sgi */
1323 *sgi = true;
1324 else
1325 *sgi = false;
1326
1327 *mcs = i;
1328 return true;
1329 }
1330 }
1331
1332 return false;
1333}
1334
1335static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1336 u8 *mac, struct station_info *sinfo)
1337{
1338 struct ath6kl *ar = ath6kl_priv(dev);
1339 long left;
1340 bool sgi;
1341 s32 rate;
1342 int ret;
1343 u8 mcs;
1344
1345 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1346 return -ENOENT;
1347
1348 if (down_interruptible(&ar->sem))
1349 return -EBUSY;
1350
1351 set_bit(STATS_UPDATE_PEND, &ar->flag);
1352
1353 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1354
1355 if (ret != 0) {
1356 up(&ar->sem);
1357 return -EIO;
1358 }
1359
1360 left = wait_event_interruptible_timeout(ar->event_wq,
1361 !test_bit(STATS_UPDATE_PEND,
1362 &ar->flag),
1363 WMI_TIMEOUT);
1364
1365 up(&ar->sem);
1366
1367 if (left == 0)
1368 return -ETIMEDOUT;
1369 else if (left < 0)
1370 return left;
1371
1372 if (ar->target_stats.rx_byte) {
1373 sinfo->rx_bytes = ar->target_stats.rx_byte;
1374 sinfo->filled |= STATION_INFO_RX_BYTES;
1375 sinfo->rx_packets = ar->target_stats.rx_pkt;
1376 sinfo->filled |= STATION_INFO_RX_PACKETS;
1377 }
1378
1379 if (ar->target_stats.tx_byte) {
1380 sinfo->tx_bytes = ar->target_stats.tx_byte;
1381 sinfo->filled |= STATION_INFO_TX_BYTES;
1382 sinfo->tx_packets = ar->target_stats.tx_pkt;
1383 sinfo->filled |= STATION_INFO_TX_PACKETS;
1384 }
1385
1386 sinfo->signal = ar->target_stats.cs_rssi;
1387 sinfo->filled |= STATION_INFO_SIGNAL;
1388
1389 rate = ar->target_stats.tx_ucast_rate;
1390
1391 if (is_rate_legacy(rate)) {
1392 sinfo->txrate.legacy = rate / 100;
1393 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1394 if (sgi) {
1395 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1396 sinfo->txrate.mcs = mcs - 1;
1397 } else {
1398 sinfo->txrate.mcs = mcs;
1399 }
1400
1401 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1402 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1403 if (sgi) {
1404 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1405 sinfo->txrate.mcs = mcs - 1;
1406 } else {
1407 sinfo->txrate.mcs = mcs;
1408 }
1409
1410 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1411 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1412 } else {
1413 ath6kl_warn("invalid rate: %d\n", rate);
1414 return 0;
1415 }
1416
1417 sinfo->filled |= STATION_INFO_TX_BITRATE;
1418
1419 return 0;
1420}
1421
1422static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1423 struct cfg80211_pmksa *pmksa)
1424{
1425 struct ath6kl *ar = ath6kl_priv(netdev);
1426 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1427 pmksa->pmkid, true);
1428}
1429
1430static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1431 struct cfg80211_pmksa *pmksa)
1432{
1433 struct ath6kl *ar = ath6kl_priv(netdev);
1434 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1435 pmksa->pmkid, false);
1436}
1437
1438static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1439{
1440 struct ath6kl *ar = ath6kl_priv(netdev);
1441 if (test_bit(CONNECTED, &ar->flag))
1442 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1443 return 0;
1444}
1445
Kalle Valoabcb3442011-07-22 08:26:20 +03001446#ifdef CONFIG_PM
1447static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1448 struct cfg80211_wowlan *wow)
1449{
1450 struct ath6kl *ar = wiphy_priv(wiphy);
1451
1452 return ath6kl_hif_suspend(ar);
1453}
1454#endif
1455
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001456static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1457 struct ieee80211_channel *chan,
1458 enum nl80211_channel_type channel_type)
1459{
1460 struct ath6kl *ar = ath6kl_priv(dev);
1461
1462 if (!ath6kl_cfg80211_ready(ar))
1463 return -EIO;
1464
1465 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1466 __func__, chan->center_freq, chan->hw_value);
1467 ar->next_chan = chan->center_freq;
1468
1469 return 0;
1470}
1471
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001472static bool ath6kl_is_p2p_ie(const u8 *pos)
1473{
1474 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1475 pos[2] == 0x50 && pos[3] == 0x6f &&
1476 pos[4] == 0x9a && pos[5] == 0x09;
1477}
1478
1479static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1480 size_t ies_len)
1481{
1482 const u8 *pos;
1483 u8 *buf = NULL;
1484 size_t len = 0;
1485 int ret;
1486
1487 /*
1488 * Filter out P2P IE(s) since they will be included depending on
1489 * the Probe Request frame in ath6kl_send_go_probe_resp().
1490 */
1491
1492 if (ies && ies_len) {
1493 buf = kmalloc(ies_len, GFP_KERNEL);
1494 if (buf == NULL)
1495 return -ENOMEM;
1496 pos = ies;
1497 while (pos + 1 < ies + ies_len) {
1498 if (pos + 2 + pos[1] > ies + ies_len)
1499 break;
1500 if (!ath6kl_is_p2p_ie(pos)) {
1501 memcpy(buf + len, pos, 2 + pos[1]);
1502 len += 2 + pos[1];
1503 }
1504 pos += 2 + pos[1];
1505 }
1506 }
1507
1508 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1509 buf, len);
1510 kfree(buf);
1511 return ret;
1512}
1513
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001514static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1515 struct beacon_parameters *info, bool add)
1516{
1517 struct ath6kl *ar = ath6kl_priv(dev);
1518 struct ieee80211_mgmt *mgmt;
1519 u8 *ies;
1520 int ies_len;
1521 struct wmi_connect_cmd p;
1522 int res;
1523 int i;
1524
1525 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1526
1527 if (!ath6kl_cfg80211_ready(ar))
1528 return -EIO;
1529
1530 if (ar->next_mode != AP_NETWORK)
1531 return -EOPNOTSUPP;
1532
1533 if (info->beacon_ies) {
1534 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1535 info->beacon_ies,
1536 info->beacon_ies_len);
1537 if (res)
1538 return res;
1539 }
1540 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001541 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1542 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001543 if (res)
1544 return res;
1545 }
1546 if (info->assocresp_ies) {
1547 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1548 info->assocresp_ies,
1549 info->assocresp_ies_len);
1550 if (res)
1551 return res;
1552 }
1553
1554 if (!add)
1555 return 0;
1556
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001557 ar->ap_mode_bkey.valid = false;
1558
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001559 /* TODO:
1560 * info->interval
1561 * info->dtim_period
1562 */
1563
1564 if (info->head == NULL)
1565 return -EINVAL;
1566 mgmt = (struct ieee80211_mgmt *) info->head;
1567 ies = mgmt->u.beacon.variable;
1568 if (ies > info->head + info->head_len)
1569 return -EINVAL;
1570 ies_len = info->head + info->head_len - ies;
1571
1572 if (info->ssid == NULL)
1573 return -EINVAL;
1574 memcpy(ar->ssid, info->ssid, info->ssid_len);
1575 ar->ssid_len = info->ssid_len;
1576 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1577 return -EOPNOTSUPP; /* TODO */
1578
1579 ar->dot11_auth_mode = OPEN_AUTH;
1580
1581 memset(&p, 0, sizeof(p));
1582
1583 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1584 switch (info->crypto.akm_suites[i]) {
1585 case WLAN_AKM_SUITE_8021X:
1586 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1587 p.auth_mode |= WPA_AUTH;
1588 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1589 p.auth_mode |= WPA2_AUTH;
1590 break;
1591 case WLAN_AKM_SUITE_PSK:
1592 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1593 p.auth_mode |= WPA_PSK_AUTH;
1594 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1595 p.auth_mode |= WPA2_PSK_AUTH;
1596 break;
1597 }
1598 }
1599 if (p.auth_mode == 0)
1600 p.auth_mode = NONE_AUTH;
1601 ar->auth_mode = p.auth_mode;
1602
1603 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1604 switch (info->crypto.ciphers_pairwise[i]) {
1605 case WLAN_CIPHER_SUITE_WEP40:
1606 case WLAN_CIPHER_SUITE_WEP104:
1607 p.prwise_crypto_type |= WEP_CRYPT;
1608 break;
1609 case WLAN_CIPHER_SUITE_TKIP:
1610 p.prwise_crypto_type |= TKIP_CRYPT;
1611 break;
1612 case WLAN_CIPHER_SUITE_CCMP:
1613 p.prwise_crypto_type |= AES_CRYPT;
1614 break;
1615 }
1616 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001617 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001618 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001619 ath6kl_set_cipher(ar, 0, true);
1620 } else if (info->crypto.n_ciphers_pairwise == 1)
1621 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001622
1623 switch (info->crypto.cipher_group) {
1624 case WLAN_CIPHER_SUITE_WEP40:
1625 case WLAN_CIPHER_SUITE_WEP104:
1626 p.grp_crypto_type = WEP_CRYPT;
1627 break;
1628 case WLAN_CIPHER_SUITE_TKIP:
1629 p.grp_crypto_type = TKIP_CRYPT;
1630 break;
1631 case WLAN_CIPHER_SUITE_CCMP:
1632 p.grp_crypto_type = AES_CRYPT;
1633 break;
1634 default:
1635 p.grp_crypto_type = NONE_CRYPT;
1636 break;
1637 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001638 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001639
1640 p.nw_type = AP_NETWORK;
1641 ar->nw_type = ar->next_mode;
1642
1643 p.ssid_len = ar->ssid_len;
1644 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1645 p.dot11_auth_mode = ar->dot11_auth_mode;
1646 p.ch = cpu_to_le16(ar->next_chan);
1647
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001648 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1649 if (res < 0)
1650 return res;
1651
1652 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001653}
1654
1655static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1656 struct beacon_parameters *info)
1657{
1658 return ath6kl_ap_beacon(wiphy, dev, info, true);
1659}
1660
1661static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1662 struct beacon_parameters *info)
1663{
1664 return ath6kl_ap_beacon(wiphy, dev, info, false);
1665}
1666
1667static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1668{
1669 struct ath6kl *ar = ath6kl_priv(dev);
1670
1671 if (ar->nw_type != AP_NETWORK)
1672 return -EOPNOTSUPP;
1673 if (!test_bit(CONNECTED, &ar->flag))
1674 return -ENOTCONN;
1675
1676 ath6kl_wmi_disconnect_cmd(ar->wmi);
1677 clear_bit(CONNECTED, &ar->flag);
1678
1679 return 0;
1680}
1681
Jouni Malinen23875132011-08-30 21:57:53 +03001682static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1683 u8 *mac, struct station_parameters *params)
1684{
1685 struct ath6kl *ar = ath6kl_priv(dev);
1686
1687 if (ar->nw_type != AP_NETWORK)
1688 return -EOPNOTSUPP;
1689
1690 /* Use this only for authorizing/unauthorizing a station */
1691 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1692 return -EOPNOTSUPP;
1693
1694 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1695 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1696 mac, 0);
1697 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1698 0);
1699}
1700
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001701static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1702 struct net_device *dev,
1703 struct ieee80211_channel *chan,
1704 enum nl80211_channel_type channel_type,
1705 unsigned int duration,
1706 u64 *cookie)
1707{
1708 struct ath6kl *ar = ath6kl_priv(dev);
1709
1710 /* TODO: if already pending or ongoing remain-on-channel,
1711 * return -EBUSY */
1712 *cookie = 1; /* only a single pending request is supported */
1713
1714 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1715 duration);
1716}
1717
1718static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1719 struct net_device *dev,
1720 u64 cookie)
1721{
1722 struct ath6kl *ar = ath6kl_priv(dev);
1723
1724 if (cookie != 1)
1725 return -ENOENT;
1726
1727 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1728}
1729
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001730static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1731 size_t len, unsigned int freq)
1732{
1733 const u8 *pos;
1734 u8 *p2p;
1735 int p2p_len;
1736 int ret;
1737 const struct ieee80211_mgmt *mgmt;
1738
1739 mgmt = (const struct ieee80211_mgmt *) buf;
1740
1741 /* Include P2P IE(s) from the frame generated in user space. */
1742
1743 p2p = kmalloc(len, GFP_KERNEL);
1744 if (p2p == NULL)
1745 return -ENOMEM;
1746 p2p_len = 0;
1747
1748 pos = mgmt->u.probe_resp.variable;
1749 while (pos + 1 < buf + len) {
1750 if (pos + 2 + pos[1] > buf + len)
1751 break;
1752 if (ath6kl_is_p2p_ie(pos)) {
1753 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1754 p2p_len += 2 + pos[1];
1755 }
1756 pos += 2 + pos[1];
1757 }
1758
1759 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1760 p2p, p2p_len);
1761 kfree(p2p);
1762 return ret;
1763}
1764
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001765static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1766 struct ieee80211_channel *chan, bool offchan,
1767 enum nl80211_channel_type channel_type,
1768 bool channel_type_valid, unsigned int wait,
1769 const u8 *buf, size_t len, u64 *cookie)
1770{
1771 struct ath6kl *ar = ath6kl_priv(dev);
1772 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001773 const struct ieee80211_mgmt *mgmt;
1774
1775 mgmt = (const struct ieee80211_mgmt *) buf;
1776 if (buf + len >= mgmt->u.probe_resp.variable &&
1777 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1778 ieee80211_is_probe_resp(mgmt->frame_control)) {
1779 /*
1780 * Send Probe Response frame in AP mode using a separate WMI
1781 * command to allow the target to fill in the generic IEs.
1782 */
1783 *cookie = 0; /* TX status not supported */
1784 return ath6kl_send_go_probe_resp(ar, buf, len,
1785 chan->center_freq);
1786 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001787
1788 id = ar->send_action_id++;
1789 if (id == 0) {
1790 /*
1791 * 0 is a reserved value in the WMI command and shall not be
1792 * used for the command.
1793 */
1794 id = ar->send_action_id++;
1795 }
1796
1797 *cookie = id;
1798 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1799 buf, len);
1800}
1801
Jouni Malinenae32c302011-08-30 21:58:01 +03001802static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1803 struct net_device *dev,
1804 u16 frame_type, bool reg)
1805{
1806 struct ath6kl *ar = ath6kl_priv(dev);
1807
1808 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1809 __func__, frame_type, reg);
1810 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1811 /*
1812 * Note: This notification callback is not allowed to sleep, so
1813 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1814 * hardcode target to report Probe Request frames all the time.
1815 */
1816 ar->probe_req_report = reg;
1817 }
1818}
1819
Jouni Malinenf80574a2011-08-30 21:58:04 +03001820static const struct ieee80211_txrx_stypes
1821ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1822 [NL80211_IFTYPE_STATION] = {
1823 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1824 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1825 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1826 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1827 },
1828 [NL80211_IFTYPE_P2P_CLIENT] = {
1829 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1830 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1831 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1832 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1833 },
1834 [NL80211_IFTYPE_P2P_GO] = {
1835 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1836 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1837 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1838 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1839 },
1840};
1841
Kalle Valobdcd8172011-07-18 00:22:30 +03001842static struct cfg80211_ops ath6kl_cfg80211_ops = {
1843 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1844 .scan = ath6kl_cfg80211_scan,
1845 .connect = ath6kl_cfg80211_connect,
1846 .disconnect = ath6kl_cfg80211_disconnect,
1847 .add_key = ath6kl_cfg80211_add_key,
1848 .get_key = ath6kl_cfg80211_get_key,
1849 .del_key = ath6kl_cfg80211_del_key,
1850 .set_default_key = ath6kl_cfg80211_set_default_key,
1851 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1852 .set_tx_power = ath6kl_cfg80211_set_txpower,
1853 .get_tx_power = ath6kl_cfg80211_get_txpower,
1854 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1855 .join_ibss = ath6kl_cfg80211_join_ibss,
1856 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1857 .get_station = ath6kl_get_station,
1858 .set_pmksa = ath6kl_set_pmksa,
1859 .del_pmksa = ath6kl_del_pmksa,
1860 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001861 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001862#ifdef CONFIG_PM
1863 .suspend = ar6k_cfg80211_suspend,
1864#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001865 .set_channel = ath6kl_set_channel,
1866 .add_beacon = ath6kl_add_beacon,
1867 .set_beacon = ath6kl_set_beacon,
1868 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001869 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001870 .remain_on_channel = ath6kl_remain_on_channel,
1871 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001872 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001873 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001874};
1875
1876struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1877{
1878 int ret = 0;
1879 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001880 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001881
1882 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1883 if (!wdev) {
1884 ath6kl_err("couldn't allocate wireless device\n");
1885 return NULL;
1886 }
1887
1888 /* create a new wiphy for use with cfg80211 */
1889 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1890 if (!wdev->wiphy) {
1891 ath6kl_err("couldn't allocate wiphy device\n");
1892 kfree(wdev);
1893 return NULL;
1894 }
1895
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001896 ar = wiphy_priv(wdev->wiphy);
1897 ar->p2p = !!ath6kl_p2p;
1898
Jouni Malinenf80574a2011-08-30 21:58:04 +03001899 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1900
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001901 wdev->wiphy->max_remain_on_channel_duration = 5000;
1902
Kalle Valobdcd8172011-07-18 00:22:30 +03001903 /* set device pointer for wiphy */
1904 set_wiphy_dev(wdev->wiphy, dev);
1905
1906 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001907 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001908 if (ar->p2p) {
1909 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1910 BIT(NL80211_IFTYPE_P2P_CLIENT);
1911 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001912 /* max num of ssids that can be probed during scanning */
1913 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001914 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001915 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1916 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1917 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1918
1919 wdev->wiphy->cipher_suites = cipher_suites;
1920 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1921
1922 ret = wiphy_register(wdev->wiphy);
1923 if (ret < 0) {
1924 ath6kl_err("couldn't register wiphy device\n");
1925 wiphy_free(wdev->wiphy);
1926 kfree(wdev);
1927 return NULL;
1928 }
1929
1930 return wdev;
1931}
1932
1933void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1934{
1935 struct wireless_dev *wdev = ar->wdev;
1936
1937 if (ar->scan_req) {
1938 cfg80211_scan_done(ar->scan_req, true);
1939 ar->scan_req = NULL;
1940 }
1941
1942 if (!wdev)
1943 return;
1944
1945 wiphy_unregister(wdev->wiphy);
1946 wiphy_free(wdev->wiphy);
1947 kfree(wdev);
1948}