blob: fcef417884b85309700630c90de524fa382f9894 [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
416void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
417 u8 *bssid, u16 listen_intvl,
418 u16 beacon_intvl,
419 enum network_type nw_type,
420 u8 beacon_ie_len, u8 assoc_req_len,
421 u8 assoc_resp_len, u8 *assoc_info)
422{
423 u16 size = 0;
424 u16 capability = 0;
425 struct cfg80211_bss *bss = NULL;
426 struct ieee80211_mgmt *mgmt = NULL;
427 struct ieee80211_channel *ibss_ch = NULL;
428 s32 signal = 50 * 100;
429 u8 ie_buf_len = 0;
430 unsigned char ie_buf[256];
431 unsigned char *ptr_ie_buf = ie_buf;
432 unsigned char *ieeemgmtbuf = NULL;
433 u8 source_mac[ETH_ALEN];
Kalle Valobdcd8172011-07-18 00:22:30 +0300434
435 /* capinfo + listen interval */
436 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
437
438 /* capinfo + status code + associd */
439 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
440
441 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
442 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
443 assoc_resp_ie_offset;
444
445 assoc_req_len -= assoc_req_ie_offset;
446 assoc_resp_len -= assoc_resp_ie_offset;
447
Kalle Valobdcd8172011-07-18 00:22:30 +0300448 if (nw_type & ADHOC_NETWORK) {
449 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
450 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
451 "%s: ath6k not in ibss mode\n", __func__);
452 return;
453 }
454 }
455
456 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300457 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
458 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300459 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
460 "%s: ath6k not in station mode\n", __func__);
461 return;
462 }
463 }
464
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 /*
466 * Earlier we were updating the cfg about bss by making a beacon frame
467 * only if the entry for bss is not there. This can have some issue if
468 * ROAM event is generated and a heavy traffic is ongoing. The ROAM
469 * event is handled through a work queue and by the time it really gets
470 * handled, BSS would have been aged out. So it is better to update the
471 * cfg about BSS irrespective of its entry being present right now or
472 * not.
473 */
474
475 if (nw_type & ADHOC_NETWORK) {
476 /* construct 802.11 mgmt beacon */
477 if (ptr_ie_buf) {
478 *ptr_ie_buf++ = WLAN_EID_SSID;
479 *ptr_ie_buf++ = ar->ssid_len;
480 memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len);
481 ptr_ie_buf += ar->ssid_len;
482
483 *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS;
484 *ptr_ie_buf++ = 2; /* length */
485 *ptr_ie_buf++ = 0; /* ATIM window */
486 *ptr_ie_buf++ = 0; /* ATIM window */
487
488 /* TODO: update ibss params and include supported rates,
489 * DS param set, extened support rates, wmm. */
490
491 ie_buf_len = ptr_ie_buf - ie_buf;
492 }
493
494 capability |= WLAN_CAPABILITY_IBSS;
495
496 if (ar->prwise_crypto == WEP_CRYPT)
497 capability |= WLAN_CAPABILITY_PRIVACY;
498
499 memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN);
500 ptr_ie_buf = ie_buf;
501 } else {
502 capability = *(u16 *) (&assoc_info[beacon_ie_len]);
503 memcpy(source_mac, bssid, ETH_ALEN);
504 ptr_ie_buf = assoc_req_ie;
505 ie_buf_len = assoc_req_len;
506 }
507
508 size = offsetof(struct ieee80211_mgmt, u)
509 + sizeof(mgmt->u.beacon)
510 + ie_buf_len;
511
512 ieeemgmtbuf = kzalloc(size, GFP_ATOMIC);
513 if (!ieeemgmtbuf) {
514 ath6kl_err("ieee mgmt buf alloc error\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300515 return;
516 }
517
518 mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf;
519 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
520 IEEE80211_STYPE_BEACON);
521 memset(mgmt->da, 0xff, ETH_ALEN); /* broadcast addr */
522 memcpy(mgmt->sa, source_mac, ETH_ALEN);
523 memcpy(mgmt->bssid, bssid, ETH_ALEN);
524 mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl);
525 mgmt->u.beacon.capab_info = cpu_to_le16(capability);
526 memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len);
527
528 ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel);
529
530 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
531 "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n",
532 __func__, mgmt->bssid, ibss_ch->hw_value,
533 beacon_intvl, capability);
534
535 bss = cfg80211_inform_bss_frame(ar->wdev->wiphy,
536 ibss_ch, mgmt,
537 size, signal, GFP_KERNEL);
538 kfree(ieeemgmtbuf);
539 cfg80211_put_bss(bss);
540
541 if (nw_type & ADHOC_NETWORK) {
542 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
543 return;
544 }
545
Raja Mani9aa60352011-08-04 19:26:29 +0530546 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300547 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530548 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300549 cfg80211_connect_result(ar->net_dev, bssid,
550 assoc_req_ie, assoc_req_len,
551 assoc_resp_ie, assoc_resp_len,
552 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530553 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300554 /* inform roam event to cfg80211 */
555 cfg80211_roamed(ar->net_dev, ibss_ch, bssid,
556 assoc_req_ie, assoc_req_len,
557 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
558 }
559}
560
561static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
562 struct net_device *dev, u16 reason_code)
563{
564 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
565
566 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
567 reason_code);
568
569 if (!ath6kl_cfg80211_ready(ar))
570 return -EIO;
571
572 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
573 ath6kl_err("busy, destroy in progress\n");
574 return -EBUSY;
575 }
576
577 if (down_interruptible(&ar->sem)) {
578 ath6kl_err("busy, couldn't get access\n");
579 return -ERESTARTSYS;
580 }
581
582 ar->reconnect_flag = 0;
583 ath6kl_disconnect(ar);
584 memset(ar->ssid, 0, sizeof(ar->ssid));
585 ar->ssid_len = 0;
586
587 if (!test_bit(SKIP_SCAN, &ar->flag))
588 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
589
590 up(&ar->sem);
591
592 return 0;
593}
594
595void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
596 u8 *bssid, u8 assoc_resp_len,
597 u8 *assoc_info, u16 proto_reason)
598{
Kalle Valobdcd8172011-07-18 00:22:30 +0300599 if (ar->scan_req) {
600 cfg80211_scan_done(ar->scan_req, true);
601 ar->scan_req = NULL;
602 }
603
604 if (ar->nw_type & ADHOC_NETWORK) {
605 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
606 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
607 "%s: ath6k not in ibss mode\n", __func__);
608 return;
609 }
610 memset(bssid, 0, ETH_ALEN);
611 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
612 return;
613 }
614
615 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300616 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
617 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300618 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
619 "%s: ath6k not in station mode\n", __func__);
620 return;
621 }
622 }
623
624 if (!test_bit(CONNECT_PEND, &ar->flag)) {
625 if (reason != DISCONNECT_CMD)
626 ath6kl_wmi_disconnect_cmd(ar->wmi);
627
628 return;
629 }
630
631 if (reason == NO_NETWORK_AVAIL) {
632 /* connect cmd failed */
633 ath6kl_wmi_disconnect_cmd(ar->wmi);
634 return;
635 }
636
637 if (reason != DISCONNECT_CMD)
638 return;
639
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530640 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300641
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530642 if (ar->sme_state == SME_CONNECTING) {
643 cfg80211_connect_result(ar->net_dev,
644 bssid, NULL, 0,
645 NULL, 0,
646 WLAN_STATUS_UNSPECIFIED_FAILURE,
647 GFP_KERNEL);
648 } else if (ar->sme_state == SME_CONNECTED) {
649 cfg80211_disconnected(ar->net_dev, reason,
650 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300651 }
652
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530653 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300654}
655
656static inline bool is_ch_11a(u16 ch)
657{
658 return (!((ch >= 2412) && (ch <= 2484)));
659}
660
Kalle Valocf104c22011-07-21 10:04:54 +0300661/* struct ath6kl_node_table::nt_nodelock is locked when calling this */
Vasanthakumar Thiagarajan91db35d2011-07-21 18:12:15 +0530662void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni)
Kalle Valobdcd8172011-07-18 00:22:30 +0300663{
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 struct ieee80211_mgmt *mgmt;
665 struct ieee80211_channel *channel;
666 struct ieee80211_supported_band *band;
667 struct ath6kl_common_ie *cie;
668 s32 signal;
669 int freq;
670
671 cie = &ni->ni_cie;
672
673 if (is_ch_11a(cie->ie_chan))
674 band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */
675 else if ((cie->ie_erp) || (cie->ie_xrates))
676 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */
677 else
678 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */
679
Kalle Valobdcd8172011-07-18 00:22:30 +0300680 freq = cie->ie_chan;
681 channel = ieee80211_get_channel(wiphy, freq);
682 signal = ni->ni_snr * 100;
683
684 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
685 "%s: bssid %pM ch %d freq %d size %d\n", __func__,
Jouni Malinen0ce77922011-08-11 00:32:49 +0300686 ni->ni_macaddr, channel->hw_value, freq, ni->ni_framelen);
687 /*
688 * Both Beacon and Probe Response frames have same payload structure,
689 * so it is fine to share the parser for both.
690 */
691 if (ni->ni_framelen < 8 + 2 + 2)
692 return;
693 mgmt = (struct ieee80211_mgmt *) (ni->ni_buf -
694 offsetof(struct ieee80211_mgmt, u));
695 cfg80211_inform_bss(wiphy, channel, ni->ni_macaddr,
696 le64_to_cpu(mgmt->u.beacon.timestamp),
697 le16_to_cpu(mgmt->u.beacon.capab_info),
698 le16_to_cpu(mgmt->u.beacon.beacon_int),
699 mgmt->u.beacon.variable,
700 ni->ni_buf + ni->ni_framelen -
701 mgmt->u.beacon.variable,
702 signal, GFP_ATOMIC);
Kalle Valobdcd8172011-07-18 00:22:30 +0300703}
704
705static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
706 struct cfg80211_scan_request *request)
707{
708 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300709 s8 n_channels = 0;
710 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300711 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300712
713 if (!ath6kl_cfg80211_ready(ar))
714 return -EIO;
715
716 if (!ar->usr_bss_filter) {
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300717 ret = ath6kl_wmi_bssfilter_cmd(
718 ar->wmi,
719 (test_bit(CONNECTED, &ar->flag) ?
720 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
721 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300722 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300723 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300724 }
725 }
726
727 if (request->n_ssids && request->ssids[0].ssid_len) {
728 u8 i;
729
730 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
731 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
732
733 for (i = 0; i < request->n_ssids; i++)
734 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
735 SPECIFIC_SSID_FLAG,
736 request->ssids[i].ssid_len,
737 request->ssids[i].ssid);
738 }
739
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300740 if (request->ie) {
741 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
742 request->ie, request->ie_len);
743 if (ret) {
744 ath6kl_err("failed to set Probe Request appie for "
745 "scan");
746 return ret;
747 }
748 }
749
Jouni Malinen11869be2011-09-02 20:07:06 +0300750 /*
751 * Scan only the requested channels if the request specifies a set of
752 * channels. If the list is longer than the target supports, do not
753 * configure the list and instead, scan all available channels.
754 */
755 if (request->n_channels > 0 &&
756 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300757 u8 i;
758
Jouni Malinen11869be2011-09-02 20:07:06 +0300759 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300760
761 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
762 if (channels == NULL) {
763 ath6kl_warn("failed to set scan channels, "
764 "scan all channels");
765 n_channels = 0;
766 }
767
768 for (i = 0; i < n_channels; i++)
769 channels[i] = request->channels[i]->center_freq;
770 }
771
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300772 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
773 false, 0, 0, n_channels, channels);
774 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300775 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300776 else
777 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300778
Edward Lu1276c9e2011-08-30 21:58:00 +0300779 kfree(channels);
780
Kalle Valobdcd8172011-07-18 00:22:30 +0300781 return ret;
782}
783
784void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
785{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300786 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300787
788 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
789
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300790 if (!ar->scan_req)
791 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300792
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300793 if ((status == -ECANCELED) || (status == -EBUSY)) {
794 cfg80211_scan_done(ar->scan_req, true);
795 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300796 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300797
798 /* Translate data to cfg80211 mgmt format */
Vasanthakumar Thiagarajan8a8bc5a2011-07-21 14:42:52 +0530799 wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300800
801 cfg80211_scan_done(ar->scan_req, false);
802
803 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
804 for (i = 0; i < ar->scan_req->n_ssids; i++) {
805 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
806 DISABLE_SSID_FLAG,
807 0, NULL);
808 }
809 }
810
811out:
812 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300813}
814
815static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
816 u8 key_index, bool pairwise,
817 const u8 *mac_addr,
818 struct key_params *params)
819{
820 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
821 struct ath6kl_key *key = NULL;
822 u8 key_usage;
823 u8 key_type;
824 int status = 0;
825
826 if (!ath6kl_cfg80211_ready(ar))
827 return -EIO;
828
829 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
830 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
831 "%s: key index %d out of bounds\n", __func__,
832 key_index);
833 return -ENOENT;
834 }
835
836 key = &ar->keys[key_index];
837 memset(key, 0, sizeof(struct ath6kl_key));
838
839 if (pairwise)
840 key_usage = PAIRWISE_USAGE;
841 else
842 key_usage = GROUP_USAGE;
843
844 if (params) {
845 if (params->key_len > WLAN_MAX_KEY_LEN ||
846 params->seq_len > sizeof(key->seq))
847 return -EINVAL;
848
849 key->key_len = params->key_len;
850 memcpy(key->key, params->key, key->key_len);
851 key->seq_len = params->seq_len;
852 memcpy(key->seq, params->seq, key->seq_len);
853 key->cipher = params->cipher;
854 }
855
856 switch (key->cipher) {
857 case WLAN_CIPHER_SUITE_WEP40:
858 case WLAN_CIPHER_SUITE_WEP104:
859 key_type = WEP_CRYPT;
860 break;
861
862 case WLAN_CIPHER_SUITE_TKIP:
863 key_type = TKIP_CRYPT;
864 break;
865
866 case WLAN_CIPHER_SUITE_CCMP:
867 key_type = AES_CRYPT;
868 break;
869
870 default:
871 return -ENOTSUPP;
872 }
873
874 if (((ar->auth_mode == WPA_PSK_AUTH)
875 || (ar->auth_mode == WPA2_PSK_AUTH))
876 && (key_usage & GROUP_USAGE))
877 del_timer(&ar->disconnect_timer);
878
879 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
880 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
881 __func__, key_index, key->key_len, key_type,
882 key_usage, key->seq_len);
883
884 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300885
886 if (ar->nw_type == AP_NETWORK && !pairwise &&
887 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
888 ar->ap_mode_bkey.valid = true;
889 ar->ap_mode_bkey.key_index = key_index;
890 ar->ap_mode_bkey.key_type = key_type;
891 ar->ap_mode_bkey.key_len = key->key_len;
892 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
893 if (!test_bit(CONNECTED, &ar->flag)) {
894 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
895 "key configuration until AP mode has been "
896 "started\n");
897 /*
898 * The key will be set in ath6kl_connect_ap_mode() once
899 * the connected event is received from the target.
900 */
901 return 0;
902 }
903 }
904
Kalle Valobdcd8172011-07-18 00:22:30 +0300905 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
906 key_type, key_usage, key->key_len,
907 key->seq, key->key, KEY_OP_INIT_VAL,
908 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
909
910 if (status)
911 return -EIO;
912
913 return 0;
914}
915
916static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
917 u8 key_index, bool pairwise,
918 const u8 *mac_addr)
919{
920 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
921
922 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
923
924 if (!ath6kl_cfg80211_ready(ar))
925 return -EIO;
926
927 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
928 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
929 "%s: key index %d out of bounds\n", __func__,
930 key_index);
931 return -ENOENT;
932 }
933
934 if (!ar->keys[key_index].key_len) {
935 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
936 "%s: index %d is empty\n", __func__, key_index);
937 return 0;
938 }
939
940 ar->keys[key_index].key_len = 0;
941
942 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
943}
944
945static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
946 u8 key_index, bool pairwise,
947 const u8 *mac_addr, void *cookie,
948 void (*callback) (void *cookie,
949 struct key_params *))
950{
951 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
952 struct ath6kl_key *key = NULL;
953 struct key_params params;
954
955 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
956
957 if (!ath6kl_cfg80211_ready(ar))
958 return -EIO;
959
960 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
961 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
962 "%s: key index %d out of bounds\n", __func__,
963 key_index);
964 return -ENOENT;
965 }
966
967 key = &ar->keys[key_index];
968 memset(&params, 0, sizeof(params));
969 params.cipher = key->cipher;
970 params.key_len = key->key_len;
971 params.seq_len = key->seq_len;
972 params.seq = key->seq;
973 params.key = key->key;
974
975 callback(cookie, &params);
976
977 return key->key_len ? 0 : -ENOENT;
978}
979
980static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
981 struct net_device *ndev,
982 u8 key_index, bool unicast,
983 bool multicast)
984{
985 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
986 struct ath6kl_key *key = NULL;
987 int status = 0;
988 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300989 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300990
991 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
992
993 if (!ath6kl_cfg80211_ready(ar))
994 return -EIO;
995
996 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
997 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
998 "%s: key index %d out of bounds\n",
999 __func__, key_index);
1000 return -ENOENT;
1001 }
1002
1003 if (!ar->keys[key_index].key_len) {
1004 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1005 __func__, key_index);
1006 return -EINVAL;
1007 }
1008
1009 ar->def_txkey_index = key_index;
1010 key = &ar->keys[ar->def_txkey_index];
1011 key_usage = GROUP_USAGE;
1012 if (ar->prwise_crypto == WEP_CRYPT)
1013 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001014 if (unicast)
1015 key_type = ar->prwise_crypto;
1016 if (multicast)
1017 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001018
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001019 if (ar->nw_type == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
1020 return 0; /* Delay until AP mode has been started */
1021
Kalle Valobdcd8172011-07-18 00:22:30 +03001022 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001023 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001024 key->key_len, key->seq, key->key,
1025 KEY_OP_INIT_VAL, NULL,
1026 SYNC_BOTH_WMIFLAG);
1027 if (status)
1028 return -EIO;
1029
1030 return 0;
1031}
1032
1033void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1034 bool ismcast)
1035{
1036 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1037 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1038
1039 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1040 (ismcast ? NL80211_KEYTYPE_GROUP :
1041 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1042 GFP_KERNEL);
1043}
1044
1045static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1046{
1047 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1048 int ret;
1049
1050 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1051 changed);
1052
1053 if (!ath6kl_cfg80211_ready(ar))
1054 return -EIO;
1055
1056 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1057 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1058 if (ret != 0) {
1059 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1060 return -EIO;
1061 }
1062 }
1063
1064 return 0;
1065}
1066
1067/*
1068 * The type nl80211_tx_power_setting replaces the following
1069 * data type from 2.6.36 onwards
1070*/
1071static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1072 enum nl80211_tx_power_setting type,
1073 int dbm)
1074{
1075 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1076 u8 ath6kl_dbm;
1077
1078 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1079 type, dbm);
1080
1081 if (!ath6kl_cfg80211_ready(ar))
1082 return -EIO;
1083
1084 switch (type) {
1085 case NL80211_TX_POWER_AUTOMATIC:
1086 return 0;
1087 case NL80211_TX_POWER_LIMITED:
1088 ar->tx_pwr = ath6kl_dbm = dbm;
1089 break;
1090 default:
1091 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1092 __func__, type);
1093 return -EOPNOTSUPP;
1094 }
1095
1096 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1097
1098 return 0;
1099}
1100
1101static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1102{
1103 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1104
1105 if (!ath6kl_cfg80211_ready(ar))
1106 return -EIO;
1107
1108 if (test_bit(CONNECTED, &ar->flag)) {
1109 ar->tx_pwr = 0;
1110
1111 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1112 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1113 return -EIO;
1114 }
1115
1116 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1117 5 * HZ);
1118
1119 if (signal_pending(current)) {
1120 ath6kl_err("target did not respond\n");
1121 return -EINTR;
1122 }
1123 }
1124
1125 *dbm = ar->tx_pwr;
1126 return 0;
1127}
1128
1129static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1130 struct net_device *dev,
1131 bool pmgmt, int timeout)
1132{
1133 struct ath6kl *ar = ath6kl_priv(dev);
1134 struct wmi_power_mode_cmd mode;
1135
1136 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1137 __func__, pmgmt, timeout);
1138
1139 if (!ath6kl_cfg80211_ready(ar))
1140 return -EIO;
1141
1142 if (pmgmt) {
1143 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1144 mode.pwr_mode = REC_POWER;
1145 } else {
1146 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1147 mode.pwr_mode = MAX_PERF_POWER;
1148 }
1149
1150 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1151 ath6kl_err("wmi_powermode_cmd failed\n");
1152 return -EIO;
1153 }
1154
1155 return 0;
1156}
1157
1158static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1159 struct net_device *ndev,
1160 enum nl80211_iftype type, u32 *flags,
1161 struct vif_params *params)
1162{
1163 struct ath6kl *ar = ath6kl_priv(ndev);
1164 struct wireless_dev *wdev = ar->wdev;
1165
1166 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1167
1168 if (!ath6kl_cfg80211_ready(ar))
1169 return -EIO;
1170
1171 switch (type) {
1172 case NL80211_IFTYPE_STATION:
1173 ar->next_mode = INFRA_NETWORK;
1174 break;
1175 case NL80211_IFTYPE_ADHOC:
1176 ar->next_mode = ADHOC_NETWORK;
1177 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001178 case NL80211_IFTYPE_AP:
1179 ar->next_mode = AP_NETWORK;
1180 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001181 case NL80211_IFTYPE_P2P_CLIENT:
1182 ar->next_mode = INFRA_NETWORK;
1183 break;
1184 case NL80211_IFTYPE_P2P_GO:
1185 ar->next_mode = AP_NETWORK;
1186 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001187 default:
1188 ath6kl_err("invalid interface type %u\n", type);
1189 return -EOPNOTSUPP;
1190 }
1191
1192 wdev->iftype = type;
1193
1194 return 0;
1195}
1196
1197static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1198 struct net_device *dev,
1199 struct cfg80211_ibss_params *ibss_param)
1200{
1201 struct ath6kl *ar = ath6kl_priv(dev);
1202 int status;
1203
1204 if (!ath6kl_cfg80211_ready(ar))
1205 return -EIO;
1206
1207 ar->ssid_len = ibss_param->ssid_len;
1208 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1209
1210 if (ibss_param->channel)
1211 ar->ch_hint = ibss_param->channel->center_freq;
1212
1213 if (ibss_param->channel_fixed) {
1214 /*
1215 * TODO: channel_fixed: The channel should be fixed, do not
1216 * search for IBSSs to join on other channels. Target
1217 * firmware does not support this feature, needs to be
1218 * updated.
1219 */
1220 return -EOPNOTSUPP;
1221 }
1222
1223 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1224 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1225 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1226
1227 ath6kl_set_wpa_version(ar, 0);
1228
1229 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1230 if (status)
1231 return status;
1232
1233 if (ibss_param->privacy) {
1234 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1235 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1236 } else {
1237 ath6kl_set_cipher(ar, 0, true);
1238 ath6kl_set_cipher(ar, 0, false);
1239 }
1240
1241 ar->nw_type = ar->next_mode;
1242
1243 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1244 "%s: connect called with authmode %d dot11 auth %d"
1245 " PW crypto %d PW crypto len %d GRP crypto %d"
1246 " GRP crypto len %d channel hint %u\n",
1247 __func__,
1248 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1249 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001250 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001251
1252 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1253 ar->dot11_auth_mode, ar->auth_mode,
1254 ar->prwise_crypto,
1255 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001256 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001257 ar->ssid_len, ar->ssid,
1258 ar->req_bssid, ar->ch_hint,
1259 ar->connect_ctrl_flags);
1260 set_bit(CONNECT_PEND, &ar->flag);
1261
1262 return 0;
1263}
1264
1265static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1266 struct net_device *dev)
1267{
1268 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1269
1270 if (!ath6kl_cfg80211_ready(ar))
1271 return -EIO;
1272
1273 ath6kl_disconnect(ar);
1274 memset(ar->ssid, 0, sizeof(ar->ssid));
1275 ar->ssid_len = 0;
1276
1277 return 0;
1278}
1279
1280static const u32 cipher_suites[] = {
1281 WLAN_CIPHER_SUITE_WEP40,
1282 WLAN_CIPHER_SUITE_WEP104,
1283 WLAN_CIPHER_SUITE_TKIP,
1284 WLAN_CIPHER_SUITE_CCMP,
1285};
1286
1287static bool is_rate_legacy(s32 rate)
1288{
1289 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1290 6000, 9000, 12000, 18000, 24000,
1291 36000, 48000, 54000
1292 };
1293 u8 i;
1294
1295 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1296 if (rate == legacy[i])
1297 return true;
1298
1299 return false;
1300}
1301
1302static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1303{
1304 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1305 52000, 58500, 65000, 72200
1306 };
1307 u8 i;
1308
1309 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1310 if (rate == ht20[i]) {
1311 if (i == ARRAY_SIZE(ht20) - 1)
1312 /* last rate uses sgi */
1313 *sgi = true;
1314 else
1315 *sgi = false;
1316
1317 *mcs = i;
1318 return true;
1319 }
1320 }
1321 return false;
1322}
1323
1324static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1325{
1326 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1327 81000, 108000, 121500, 135000,
1328 150000
1329 };
1330 u8 i;
1331
1332 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1333 if (rate == ht40[i]) {
1334 if (i == ARRAY_SIZE(ht40) - 1)
1335 /* last rate uses sgi */
1336 *sgi = true;
1337 else
1338 *sgi = false;
1339
1340 *mcs = i;
1341 return true;
1342 }
1343 }
1344
1345 return false;
1346}
1347
1348static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1349 u8 *mac, struct station_info *sinfo)
1350{
1351 struct ath6kl *ar = ath6kl_priv(dev);
1352 long left;
1353 bool sgi;
1354 s32 rate;
1355 int ret;
1356 u8 mcs;
1357
1358 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1359 return -ENOENT;
1360
1361 if (down_interruptible(&ar->sem))
1362 return -EBUSY;
1363
1364 set_bit(STATS_UPDATE_PEND, &ar->flag);
1365
1366 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1367
1368 if (ret != 0) {
1369 up(&ar->sem);
1370 return -EIO;
1371 }
1372
1373 left = wait_event_interruptible_timeout(ar->event_wq,
1374 !test_bit(STATS_UPDATE_PEND,
1375 &ar->flag),
1376 WMI_TIMEOUT);
1377
1378 up(&ar->sem);
1379
1380 if (left == 0)
1381 return -ETIMEDOUT;
1382 else if (left < 0)
1383 return left;
1384
1385 if (ar->target_stats.rx_byte) {
1386 sinfo->rx_bytes = ar->target_stats.rx_byte;
1387 sinfo->filled |= STATION_INFO_RX_BYTES;
1388 sinfo->rx_packets = ar->target_stats.rx_pkt;
1389 sinfo->filled |= STATION_INFO_RX_PACKETS;
1390 }
1391
1392 if (ar->target_stats.tx_byte) {
1393 sinfo->tx_bytes = ar->target_stats.tx_byte;
1394 sinfo->filled |= STATION_INFO_TX_BYTES;
1395 sinfo->tx_packets = ar->target_stats.tx_pkt;
1396 sinfo->filled |= STATION_INFO_TX_PACKETS;
1397 }
1398
1399 sinfo->signal = ar->target_stats.cs_rssi;
1400 sinfo->filled |= STATION_INFO_SIGNAL;
1401
1402 rate = ar->target_stats.tx_ucast_rate;
1403
1404 if (is_rate_legacy(rate)) {
1405 sinfo->txrate.legacy = rate / 100;
1406 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1407 if (sgi) {
1408 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1409 sinfo->txrate.mcs = mcs - 1;
1410 } else {
1411 sinfo->txrate.mcs = mcs;
1412 }
1413
1414 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1415 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1416 if (sgi) {
1417 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1418 sinfo->txrate.mcs = mcs - 1;
1419 } else {
1420 sinfo->txrate.mcs = mcs;
1421 }
1422
1423 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1424 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1425 } else {
1426 ath6kl_warn("invalid rate: %d\n", rate);
1427 return 0;
1428 }
1429
1430 sinfo->filled |= STATION_INFO_TX_BITRATE;
1431
1432 return 0;
1433}
1434
1435static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1436 struct cfg80211_pmksa *pmksa)
1437{
1438 struct ath6kl *ar = ath6kl_priv(netdev);
1439 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1440 pmksa->pmkid, true);
1441}
1442
1443static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1444 struct cfg80211_pmksa *pmksa)
1445{
1446 struct ath6kl *ar = ath6kl_priv(netdev);
1447 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1448 pmksa->pmkid, false);
1449}
1450
1451static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1452{
1453 struct ath6kl *ar = ath6kl_priv(netdev);
1454 if (test_bit(CONNECTED, &ar->flag))
1455 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1456 return 0;
1457}
1458
Kalle Valoabcb3442011-07-22 08:26:20 +03001459#ifdef CONFIG_PM
1460static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1461 struct cfg80211_wowlan *wow)
1462{
1463 struct ath6kl *ar = wiphy_priv(wiphy);
1464
1465 return ath6kl_hif_suspend(ar);
1466}
1467#endif
1468
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001469static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1470 struct ieee80211_channel *chan,
1471 enum nl80211_channel_type channel_type)
1472{
1473 struct ath6kl *ar = ath6kl_priv(dev);
1474
1475 if (!ath6kl_cfg80211_ready(ar))
1476 return -EIO;
1477
1478 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1479 __func__, chan->center_freq, chan->hw_value);
1480 ar->next_chan = chan->center_freq;
1481
1482 return 0;
1483}
1484
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001485static bool ath6kl_is_p2p_ie(const u8 *pos)
1486{
1487 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1488 pos[2] == 0x50 && pos[3] == 0x6f &&
1489 pos[4] == 0x9a && pos[5] == 0x09;
1490}
1491
1492static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1493 size_t ies_len)
1494{
1495 const u8 *pos;
1496 u8 *buf = NULL;
1497 size_t len = 0;
1498 int ret;
1499
1500 /*
1501 * Filter out P2P IE(s) since they will be included depending on
1502 * the Probe Request frame in ath6kl_send_go_probe_resp().
1503 */
1504
1505 if (ies && ies_len) {
1506 buf = kmalloc(ies_len, GFP_KERNEL);
1507 if (buf == NULL)
1508 return -ENOMEM;
1509 pos = ies;
1510 while (pos + 1 < ies + ies_len) {
1511 if (pos + 2 + pos[1] > ies + ies_len)
1512 break;
1513 if (!ath6kl_is_p2p_ie(pos)) {
1514 memcpy(buf + len, pos, 2 + pos[1]);
1515 len += 2 + pos[1];
1516 }
1517 pos += 2 + pos[1];
1518 }
1519 }
1520
1521 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1522 buf, len);
1523 kfree(buf);
1524 return ret;
1525}
1526
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001527static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1528 struct beacon_parameters *info, bool add)
1529{
1530 struct ath6kl *ar = ath6kl_priv(dev);
1531 struct ieee80211_mgmt *mgmt;
1532 u8 *ies;
1533 int ies_len;
1534 struct wmi_connect_cmd p;
1535 int res;
1536 int i;
1537
1538 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1539
1540 if (!ath6kl_cfg80211_ready(ar))
1541 return -EIO;
1542
1543 if (ar->next_mode != AP_NETWORK)
1544 return -EOPNOTSUPP;
1545
1546 if (info->beacon_ies) {
1547 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1548 info->beacon_ies,
1549 info->beacon_ies_len);
1550 if (res)
1551 return res;
1552 }
1553 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001554 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1555 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001556 if (res)
1557 return res;
1558 }
1559 if (info->assocresp_ies) {
1560 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1561 info->assocresp_ies,
1562 info->assocresp_ies_len);
1563 if (res)
1564 return res;
1565 }
1566
1567 if (!add)
1568 return 0;
1569
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001570 ar->ap_mode_bkey.valid = false;
1571
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001572 /* TODO:
1573 * info->interval
1574 * info->dtim_period
1575 */
1576
1577 if (info->head == NULL)
1578 return -EINVAL;
1579 mgmt = (struct ieee80211_mgmt *) info->head;
1580 ies = mgmt->u.beacon.variable;
1581 if (ies > info->head + info->head_len)
1582 return -EINVAL;
1583 ies_len = info->head + info->head_len - ies;
1584
1585 if (info->ssid == NULL)
1586 return -EINVAL;
1587 memcpy(ar->ssid, info->ssid, info->ssid_len);
1588 ar->ssid_len = info->ssid_len;
1589 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1590 return -EOPNOTSUPP; /* TODO */
1591
1592 ar->dot11_auth_mode = OPEN_AUTH;
1593
1594 memset(&p, 0, sizeof(p));
1595
1596 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1597 switch (info->crypto.akm_suites[i]) {
1598 case WLAN_AKM_SUITE_8021X:
1599 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1600 p.auth_mode |= WPA_AUTH;
1601 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1602 p.auth_mode |= WPA2_AUTH;
1603 break;
1604 case WLAN_AKM_SUITE_PSK:
1605 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1606 p.auth_mode |= WPA_PSK_AUTH;
1607 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1608 p.auth_mode |= WPA2_PSK_AUTH;
1609 break;
1610 }
1611 }
1612 if (p.auth_mode == 0)
1613 p.auth_mode = NONE_AUTH;
1614 ar->auth_mode = p.auth_mode;
1615
1616 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1617 switch (info->crypto.ciphers_pairwise[i]) {
1618 case WLAN_CIPHER_SUITE_WEP40:
1619 case WLAN_CIPHER_SUITE_WEP104:
1620 p.prwise_crypto_type |= WEP_CRYPT;
1621 break;
1622 case WLAN_CIPHER_SUITE_TKIP:
1623 p.prwise_crypto_type |= TKIP_CRYPT;
1624 break;
1625 case WLAN_CIPHER_SUITE_CCMP:
1626 p.prwise_crypto_type |= AES_CRYPT;
1627 break;
1628 }
1629 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001630 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001631 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001632 ath6kl_set_cipher(ar, 0, true);
1633 } else if (info->crypto.n_ciphers_pairwise == 1)
1634 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001635
1636 switch (info->crypto.cipher_group) {
1637 case WLAN_CIPHER_SUITE_WEP40:
1638 case WLAN_CIPHER_SUITE_WEP104:
1639 p.grp_crypto_type = WEP_CRYPT;
1640 break;
1641 case WLAN_CIPHER_SUITE_TKIP:
1642 p.grp_crypto_type = TKIP_CRYPT;
1643 break;
1644 case WLAN_CIPHER_SUITE_CCMP:
1645 p.grp_crypto_type = AES_CRYPT;
1646 break;
1647 default:
1648 p.grp_crypto_type = NONE_CRYPT;
1649 break;
1650 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001651 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001652
1653 p.nw_type = AP_NETWORK;
1654 ar->nw_type = ar->next_mode;
1655
1656 p.ssid_len = ar->ssid_len;
1657 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1658 p.dot11_auth_mode = ar->dot11_auth_mode;
1659 p.ch = cpu_to_le16(ar->next_chan);
1660
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001661 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1662 if (res < 0)
1663 return res;
1664
1665 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001666}
1667
1668static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1669 struct beacon_parameters *info)
1670{
1671 return ath6kl_ap_beacon(wiphy, dev, info, true);
1672}
1673
1674static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1675 struct beacon_parameters *info)
1676{
1677 return ath6kl_ap_beacon(wiphy, dev, info, false);
1678}
1679
1680static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1681{
1682 struct ath6kl *ar = ath6kl_priv(dev);
1683
1684 if (ar->nw_type != AP_NETWORK)
1685 return -EOPNOTSUPP;
1686 if (!test_bit(CONNECTED, &ar->flag))
1687 return -ENOTCONN;
1688
1689 ath6kl_wmi_disconnect_cmd(ar->wmi);
1690 clear_bit(CONNECTED, &ar->flag);
1691
1692 return 0;
1693}
1694
Jouni Malinen23875132011-08-30 21:57:53 +03001695static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1696 u8 *mac, struct station_parameters *params)
1697{
1698 struct ath6kl *ar = ath6kl_priv(dev);
1699
1700 if (ar->nw_type != AP_NETWORK)
1701 return -EOPNOTSUPP;
1702
1703 /* Use this only for authorizing/unauthorizing a station */
1704 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1705 return -EOPNOTSUPP;
1706
1707 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1708 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1709 mac, 0);
1710 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1711 0);
1712}
1713
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001714static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1715 struct net_device *dev,
1716 struct ieee80211_channel *chan,
1717 enum nl80211_channel_type channel_type,
1718 unsigned int duration,
1719 u64 *cookie)
1720{
1721 struct ath6kl *ar = ath6kl_priv(dev);
1722
1723 /* TODO: if already pending or ongoing remain-on-channel,
1724 * return -EBUSY */
1725 *cookie = 1; /* only a single pending request is supported */
1726
1727 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1728 duration);
1729}
1730
1731static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1732 struct net_device *dev,
1733 u64 cookie)
1734{
1735 struct ath6kl *ar = ath6kl_priv(dev);
1736
1737 if (cookie != 1)
1738 return -ENOENT;
1739
1740 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1741}
1742
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001743static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1744 size_t len, unsigned int freq)
1745{
1746 const u8 *pos;
1747 u8 *p2p;
1748 int p2p_len;
1749 int ret;
1750 const struct ieee80211_mgmt *mgmt;
1751
1752 mgmt = (const struct ieee80211_mgmt *) buf;
1753
1754 /* Include P2P IE(s) from the frame generated in user space. */
1755
1756 p2p = kmalloc(len, GFP_KERNEL);
1757 if (p2p == NULL)
1758 return -ENOMEM;
1759 p2p_len = 0;
1760
1761 pos = mgmt->u.probe_resp.variable;
1762 while (pos + 1 < buf + len) {
1763 if (pos + 2 + pos[1] > buf + len)
1764 break;
1765 if (ath6kl_is_p2p_ie(pos)) {
1766 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1767 p2p_len += 2 + pos[1];
1768 }
1769 pos += 2 + pos[1];
1770 }
1771
1772 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1773 p2p, p2p_len);
1774 kfree(p2p);
1775 return ret;
1776}
1777
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001778static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1779 struct ieee80211_channel *chan, bool offchan,
1780 enum nl80211_channel_type channel_type,
1781 bool channel_type_valid, unsigned int wait,
1782 const u8 *buf, size_t len, u64 *cookie)
1783{
1784 struct ath6kl *ar = ath6kl_priv(dev);
1785 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001786 const struct ieee80211_mgmt *mgmt;
1787
1788 mgmt = (const struct ieee80211_mgmt *) buf;
1789 if (buf + len >= mgmt->u.probe_resp.variable &&
1790 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1791 ieee80211_is_probe_resp(mgmt->frame_control)) {
1792 /*
1793 * Send Probe Response frame in AP mode using a separate WMI
1794 * command to allow the target to fill in the generic IEs.
1795 */
1796 *cookie = 0; /* TX status not supported */
1797 return ath6kl_send_go_probe_resp(ar, buf, len,
1798 chan->center_freq);
1799 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001800
1801 id = ar->send_action_id++;
1802 if (id == 0) {
1803 /*
1804 * 0 is a reserved value in the WMI command and shall not be
1805 * used for the command.
1806 */
1807 id = ar->send_action_id++;
1808 }
1809
1810 *cookie = id;
1811 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1812 buf, len);
1813}
1814
Jouni Malinenae32c302011-08-30 21:58:01 +03001815static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1816 struct net_device *dev,
1817 u16 frame_type, bool reg)
1818{
1819 struct ath6kl *ar = ath6kl_priv(dev);
1820
1821 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1822 __func__, frame_type, reg);
1823 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1824 /*
1825 * Note: This notification callback is not allowed to sleep, so
1826 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1827 * hardcode target to report Probe Request frames all the time.
1828 */
1829 ar->probe_req_report = reg;
1830 }
1831}
1832
Jouni Malinenf80574a2011-08-30 21:58:04 +03001833static const struct ieee80211_txrx_stypes
1834ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1835 [NL80211_IFTYPE_STATION] = {
1836 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1837 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1838 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1839 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1840 },
1841 [NL80211_IFTYPE_P2P_CLIENT] = {
1842 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1843 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1844 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1845 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1846 },
1847 [NL80211_IFTYPE_P2P_GO] = {
1848 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1849 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1850 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1851 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1852 },
1853};
1854
Kalle Valobdcd8172011-07-18 00:22:30 +03001855static struct cfg80211_ops ath6kl_cfg80211_ops = {
1856 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1857 .scan = ath6kl_cfg80211_scan,
1858 .connect = ath6kl_cfg80211_connect,
1859 .disconnect = ath6kl_cfg80211_disconnect,
1860 .add_key = ath6kl_cfg80211_add_key,
1861 .get_key = ath6kl_cfg80211_get_key,
1862 .del_key = ath6kl_cfg80211_del_key,
1863 .set_default_key = ath6kl_cfg80211_set_default_key,
1864 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1865 .set_tx_power = ath6kl_cfg80211_set_txpower,
1866 .get_tx_power = ath6kl_cfg80211_get_txpower,
1867 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1868 .join_ibss = ath6kl_cfg80211_join_ibss,
1869 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1870 .get_station = ath6kl_get_station,
1871 .set_pmksa = ath6kl_set_pmksa,
1872 .del_pmksa = ath6kl_del_pmksa,
1873 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001874 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001875#ifdef CONFIG_PM
1876 .suspend = ar6k_cfg80211_suspend,
1877#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001878 .set_channel = ath6kl_set_channel,
1879 .add_beacon = ath6kl_add_beacon,
1880 .set_beacon = ath6kl_set_beacon,
1881 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001882 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001883 .remain_on_channel = ath6kl_remain_on_channel,
1884 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001885 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001886 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001887};
1888
1889struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1890{
1891 int ret = 0;
1892 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001893 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001894
1895 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1896 if (!wdev) {
1897 ath6kl_err("couldn't allocate wireless device\n");
1898 return NULL;
1899 }
1900
1901 /* create a new wiphy for use with cfg80211 */
1902 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1903 if (!wdev->wiphy) {
1904 ath6kl_err("couldn't allocate wiphy device\n");
1905 kfree(wdev);
1906 return NULL;
1907 }
1908
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001909 ar = wiphy_priv(wdev->wiphy);
1910 ar->p2p = !!ath6kl_p2p;
1911
Jouni Malinenf80574a2011-08-30 21:58:04 +03001912 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1913
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001914 wdev->wiphy->max_remain_on_channel_duration = 5000;
1915
Kalle Valobdcd8172011-07-18 00:22:30 +03001916 /* set device pointer for wiphy */
1917 set_wiphy_dev(wdev->wiphy, dev);
1918
1919 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001920 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001921 if (ar->p2p) {
1922 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1923 BIT(NL80211_IFTYPE_P2P_CLIENT);
1924 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001925 /* max num of ssids that can be probed during scanning */
1926 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001927 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001928 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1929 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1930 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1931
1932 wdev->wiphy->cipher_suites = cipher_suites;
1933 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1934
1935 ret = wiphy_register(wdev->wiphy);
1936 if (ret < 0) {
1937 ath6kl_err("couldn't register wiphy device\n");
1938 wiphy_free(wdev->wiphy);
1939 kfree(wdev);
1940 return NULL;
1941 }
1942
1943 return wdev;
1944}
1945
1946void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1947{
1948 struct wireless_dev *wdev = ar->wdev;
1949
1950 if (ar->scan_req) {
1951 cfg80211_scan_done(ar->scan_req, true);
1952 ar->scan_req = NULL;
1953 }
1954
1955 if (!wdev)
1956 return;
1957
1958 wiphy_unregister(wdev->wiphy);
1959 wiphy_free(wdev->wiphy);
1960 kfree(wdev);
1961}