blob: 17bb8e28b338746f60822a740dae07fc93dce0c5 [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
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530592 ar->sme_state = SME_DISCONNECTED;
593
Kalle Valobdcd8172011-07-18 00:22:30 +0300594 return 0;
595}
596
597void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
598 u8 *bssid, u8 assoc_resp_len,
599 u8 *assoc_info, u16 proto_reason)
600{
Kalle Valobdcd8172011-07-18 00:22:30 +0300601 if (ar->scan_req) {
602 cfg80211_scan_done(ar->scan_req, true);
603 ar->scan_req = NULL;
604 }
605
606 if (ar->nw_type & ADHOC_NETWORK) {
607 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
608 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
609 "%s: ath6k not in ibss mode\n", __func__);
610 return;
611 }
612 memset(bssid, 0, ETH_ALEN);
613 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
614 return;
615 }
616
617 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300618 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
619 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300620 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
621 "%s: ath6k not in station mode\n", __func__);
622 return;
623 }
624 }
625
626 if (!test_bit(CONNECT_PEND, &ar->flag)) {
627 if (reason != DISCONNECT_CMD)
628 ath6kl_wmi_disconnect_cmd(ar->wmi);
629
630 return;
631 }
632
633 if (reason == NO_NETWORK_AVAIL) {
634 /* connect cmd failed */
635 ath6kl_wmi_disconnect_cmd(ar->wmi);
636 return;
637 }
638
639 if (reason != DISCONNECT_CMD)
640 return;
641
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530642 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300643
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530644 if (ar->sme_state == SME_CONNECTING) {
645 cfg80211_connect_result(ar->net_dev,
646 bssid, NULL, 0,
647 NULL, 0,
648 WLAN_STATUS_UNSPECIFIED_FAILURE,
649 GFP_KERNEL);
650 } else if (ar->sme_state == SME_CONNECTED) {
651 cfg80211_disconnected(ar->net_dev, reason,
652 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 }
654
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530655 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300656}
657
658static inline bool is_ch_11a(u16 ch)
659{
660 return (!((ch >= 2412) && (ch <= 2484)));
661}
662
Kalle Valocf104c22011-07-21 10:04:54 +0300663/* struct ath6kl_node_table::nt_nodelock is locked when calling this */
Vasanthakumar Thiagarajan91db35d2011-07-21 18:12:15 +0530664void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni)
Kalle Valobdcd8172011-07-18 00:22:30 +0300665{
Kalle Valobdcd8172011-07-18 00:22:30 +0300666 struct ieee80211_mgmt *mgmt;
667 struct ieee80211_channel *channel;
668 struct ieee80211_supported_band *band;
669 struct ath6kl_common_ie *cie;
670 s32 signal;
671 int freq;
672
673 cie = &ni->ni_cie;
674
675 if (is_ch_11a(cie->ie_chan))
676 band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */
677 else if ((cie->ie_erp) || (cie->ie_xrates))
678 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */
679 else
680 band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */
681
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 freq = cie->ie_chan;
683 channel = ieee80211_get_channel(wiphy, freq);
684 signal = ni->ni_snr * 100;
685
686 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
687 "%s: bssid %pM ch %d freq %d size %d\n", __func__,
Jouni Malinen0ce77922011-08-11 00:32:49 +0300688 ni->ni_macaddr, channel->hw_value, freq, ni->ni_framelen);
689 /*
690 * Both Beacon and Probe Response frames have same payload structure,
691 * so it is fine to share the parser for both.
692 */
693 if (ni->ni_framelen < 8 + 2 + 2)
694 return;
695 mgmt = (struct ieee80211_mgmt *) (ni->ni_buf -
696 offsetof(struct ieee80211_mgmt, u));
697 cfg80211_inform_bss(wiphy, channel, ni->ni_macaddr,
698 le64_to_cpu(mgmt->u.beacon.timestamp),
699 le16_to_cpu(mgmt->u.beacon.capab_info),
700 le16_to_cpu(mgmt->u.beacon.beacon_int),
701 mgmt->u.beacon.variable,
702 ni->ni_buf + ni->ni_framelen -
703 mgmt->u.beacon.variable,
704 signal, GFP_ATOMIC);
Kalle Valobdcd8172011-07-18 00:22:30 +0300705}
706
707static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
708 struct cfg80211_scan_request *request)
709{
710 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300711 s8 n_channels = 0;
712 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300713 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300714
715 if (!ath6kl_cfg80211_ready(ar))
716 return -EIO;
717
718 if (!ar->usr_bss_filter) {
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300719 ret = ath6kl_wmi_bssfilter_cmd(
720 ar->wmi,
721 (test_bit(CONNECTED, &ar->flag) ?
722 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
723 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300724 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300725 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300726 }
727 }
728
729 if (request->n_ssids && request->ssids[0].ssid_len) {
730 u8 i;
731
732 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
733 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
734
735 for (i = 0; i < request->n_ssids; i++)
736 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
737 SPECIFIC_SSID_FLAG,
738 request->ssids[i].ssid_len,
739 request->ssids[i].ssid);
740 }
741
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300742 if (request->ie) {
743 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
744 request->ie, request->ie_len);
745 if (ret) {
746 ath6kl_err("failed to set Probe Request appie for "
747 "scan");
748 return ret;
749 }
750 }
751
Jouni Malinen11869be2011-09-02 20:07:06 +0300752 /*
753 * Scan only the requested channels if the request specifies a set of
754 * channels. If the list is longer than the target supports, do not
755 * configure the list and instead, scan all available channels.
756 */
757 if (request->n_channels > 0 &&
758 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300759 u8 i;
760
Jouni Malinen11869be2011-09-02 20:07:06 +0300761 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300762
763 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
764 if (channels == NULL) {
765 ath6kl_warn("failed to set scan channels, "
766 "scan all channels");
767 n_channels = 0;
768 }
769
770 for (i = 0; i < n_channels; i++)
771 channels[i] = request->channels[i]->center_freq;
772 }
773
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300774 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
775 false, 0, 0, n_channels, channels);
776 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300777 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300778 else
779 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300780
Edward Lu1276c9e2011-08-30 21:58:00 +0300781 kfree(channels);
782
Kalle Valobdcd8172011-07-18 00:22:30 +0300783 return ret;
784}
785
786void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
787{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300788 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300789
790 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
791
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300792 if (!ar->scan_req)
793 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300794
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300795 if ((status == -ECANCELED) || (status == -EBUSY)) {
796 cfg80211_scan_done(ar->scan_req, true);
797 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300798 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300799
800 /* Translate data to cfg80211 mgmt format */
Vasanthakumar Thiagarajan8a8bc5a2011-07-21 14:42:52 +0530801 wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300802
803 cfg80211_scan_done(ar->scan_req, false);
804
805 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
806 for (i = 0; i < ar->scan_req->n_ssids; i++) {
807 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
808 DISABLE_SSID_FLAG,
809 0, NULL);
810 }
811 }
812
813out:
814 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300815}
816
817static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
818 u8 key_index, bool pairwise,
819 const u8 *mac_addr,
820 struct key_params *params)
821{
822 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
823 struct ath6kl_key *key = NULL;
824 u8 key_usage;
825 u8 key_type;
826 int status = 0;
827
828 if (!ath6kl_cfg80211_ready(ar))
829 return -EIO;
830
831 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
832 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
833 "%s: key index %d out of bounds\n", __func__,
834 key_index);
835 return -ENOENT;
836 }
837
838 key = &ar->keys[key_index];
839 memset(key, 0, sizeof(struct ath6kl_key));
840
841 if (pairwise)
842 key_usage = PAIRWISE_USAGE;
843 else
844 key_usage = GROUP_USAGE;
845
846 if (params) {
847 if (params->key_len > WLAN_MAX_KEY_LEN ||
848 params->seq_len > sizeof(key->seq))
849 return -EINVAL;
850
851 key->key_len = params->key_len;
852 memcpy(key->key, params->key, key->key_len);
853 key->seq_len = params->seq_len;
854 memcpy(key->seq, params->seq, key->seq_len);
855 key->cipher = params->cipher;
856 }
857
858 switch (key->cipher) {
859 case WLAN_CIPHER_SUITE_WEP40:
860 case WLAN_CIPHER_SUITE_WEP104:
861 key_type = WEP_CRYPT;
862 break;
863
864 case WLAN_CIPHER_SUITE_TKIP:
865 key_type = TKIP_CRYPT;
866 break;
867
868 case WLAN_CIPHER_SUITE_CCMP:
869 key_type = AES_CRYPT;
870 break;
871
872 default:
873 return -ENOTSUPP;
874 }
875
876 if (((ar->auth_mode == WPA_PSK_AUTH)
877 || (ar->auth_mode == WPA2_PSK_AUTH))
878 && (key_usage & GROUP_USAGE))
879 del_timer(&ar->disconnect_timer);
880
881 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
882 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
883 __func__, key_index, key->key_len, key_type,
884 key_usage, key->seq_len);
885
886 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300887
888 if (ar->nw_type == AP_NETWORK && !pairwise &&
889 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
890 ar->ap_mode_bkey.valid = true;
891 ar->ap_mode_bkey.key_index = key_index;
892 ar->ap_mode_bkey.key_type = key_type;
893 ar->ap_mode_bkey.key_len = key->key_len;
894 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
895 if (!test_bit(CONNECTED, &ar->flag)) {
896 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
897 "key configuration until AP mode has been "
898 "started\n");
899 /*
900 * The key will be set in ath6kl_connect_ap_mode() once
901 * the connected event is received from the target.
902 */
903 return 0;
904 }
905 }
906
Kalle Valobdcd8172011-07-18 00:22:30 +0300907 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
908 key_type, key_usage, key->key_len,
909 key->seq, key->key, KEY_OP_INIT_VAL,
910 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
911
912 if (status)
913 return -EIO;
914
915 return 0;
916}
917
918static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
919 u8 key_index, bool pairwise,
920 const u8 *mac_addr)
921{
922 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
923
924 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
925
926 if (!ath6kl_cfg80211_ready(ar))
927 return -EIO;
928
929 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
930 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
931 "%s: key index %d out of bounds\n", __func__,
932 key_index);
933 return -ENOENT;
934 }
935
936 if (!ar->keys[key_index].key_len) {
937 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
938 "%s: index %d is empty\n", __func__, key_index);
939 return 0;
940 }
941
942 ar->keys[key_index].key_len = 0;
943
944 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
945}
946
947static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
948 u8 key_index, bool pairwise,
949 const u8 *mac_addr, void *cookie,
950 void (*callback) (void *cookie,
951 struct key_params *))
952{
953 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
954 struct ath6kl_key *key = NULL;
955 struct key_params params;
956
957 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
958
959 if (!ath6kl_cfg80211_ready(ar))
960 return -EIO;
961
962 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
963 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
964 "%s: key index %d out of bounds\n", __func__,
965 key_index);
966 return -ENOENT;
967 }
968
969 key = &ar->keys[key_index];
970 memset(&params, 0, sizeof(params));
971 params.cipher = key->cipher;
972 params.key_len = key->key_len;
973 params.seq_len = key->seq_len;
974 params.seq = key->seq;
975 params.key = key->key;
976
977 callback(cookie, &params);
978
979 return key->key_len ? 0 : -ENOENT;
980}
981
982static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
983 struct net_device *ndev,
984 u8 key_index, bool unicast,
985 bool multicast)
986{
987 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
988 struct ath6kl_key *key = NULL;
989 int status = 0;
990 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300991 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300992
993 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
994
995 if (!ath6kl_cfg80211_ready(ar))
996 return -EIO;
997
998 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
999 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1000 "%s: key index %d out of bounds\n",
1001 __func__, key_index);
1002 return -ENOENT;
1003 }
1004
1005 if (!ar->keys[key_index].key_len) {
1006 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1007 __func__, key_index);
1008 return -EINVAL;
1009 }
1010
1011 ar->def_txkey_index = key_index;
1012 key = &ar->keys[ar->def_txkey_index];
1013 key_usage = GROUP_USAGE;
1014 if (ar->prwise_crypto == WEP_CRYPT)
1015 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001016 if (unicast)
1017 key_type = ar->prwise_crypto;
1018 if (multicast)
1019 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001020
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001021 if (ar->nw_type == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
1022 return 0; /* Delay until AP mode has been started */
1023
Kalle Valobdcd8172011-07-18 00:22:30 +03001024 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001025 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001026 key->key_len, key->seq, key->key,
1027 KEY_OP_INIT_VAL, NULL,
1028 SYNC_BOTH_WMIFLAG);
1029 if (status)
1030 return -EIO;
1031
1032 return 0;
1033}
1034
1035void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1036 bool ismcast)
1037{
1038 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1039 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1040
1041 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1042 (ismcast ? NL80211_KEYTYPE_GROUP :
1043 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1044 GFP_KERNEL);
1045}
1046
1047static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1048{
1049 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1050 int ret;
1051
1052 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1053 changed);
1054
1055 if (!ath6kl_cfg80211_ready(ar))
1056 return -EIO;
1057
1058 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1059 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1060 if (ret != 0) {
1061 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1062 return -EIO;
1063 }
1064 }
1065
1066 return 0;
1067}
1068
1069/*
1070 * The type nl80211_tx_power_setting replaces the following
1071 * data type from 2.6.36 onwards
1072*/
1073static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1074 enum nl80211_tx_power_setting type,
1075 int dbm)
1076{
1077 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1078 u8 ath6kl_dbm;
1079
1080 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1081 type, dbm);
1082
1083 if (!ath6kl_cfg80211_ready(ar))
1084 return -EIO;
1085
1086 switch (type) {
1087 case NL80211_TX_POWER_AUTOMATIC:
1088 return 0;
1089 case NL80211_TX_POWER_LIMITED:
1090 ar->tx_pwr = ath6kl_dbm = dbm;
1091 break;
1092 default:
1093 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1094 __func__, type);
1095 return -EOPNOTSUPP;
1096 }
1097
1098 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1099
1100 return 0;
1101}
1102
1103static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1104{
1105 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1106
1107 if (!ath6kl_cfg80211_ready(ar))
1108 return -EIO;
1109
1110 if (test_bit(CONNECTED, &ar->flag)) {
1111 ar->tx_pwr = 0;
1112
1113 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1114 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1115 return -EIO;
1116 }
1117
1118 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1119 5 * HZ);
1120
1121 if (signal_pending(current)) {
1122 ath6kl_err("target did not respond\n");
1123 return -EINTR;
1124 }
1125 }
1126
1127 *dbm = ar->tx_pwr;
1128 return 0;
1129}
1130
1131static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1132 struct net_device *dev,
1133 bool pmgmt, int timeout)
1134{
1135 struct ath6kl *ar = ath6kl_priv(dev);
1136 struct wmi_power_mode_cmd mode;
1137
1138 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1139 __func__, pmgmt, timeout);
1140
1141 if (!ath6kl_cfg80211_ready(ar))
1142 return -EIO;
1143
1144 if (pmgmt) {
1145 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1146 mode.pwr_mode = REC_POWER;
1147 } else {
1148 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1149 mode.pwr_mode = MAX_PERF_POWER;
1150 }
1151
1152 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1153 ath6kl_err("wmi_powermode_cmd failed\n");
1154 return -EIO;
1155 }
1156
1157 return 0;
1158}
1159
1160static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1161 struct net_device *ndev,
1162 enum nl80211_iftype type, u32 *flags,
1163 struct vif_params *params)
1164{
1165 struct ath6kl *ar = ath6kl_priv(ndev);
1166 struct wireless_dev *wdev = ar->wdev;
1167
1168 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1169
1170 if (!ath6kl_cfg80211_ready(ar))
1171 return -EIO;
1172
1173 switch (type) {
1174 case NL80211_IFTYPE_STATION:
1175 ar->next_mode = INFRA_NETWORK;
1176 break;
1177 case NL80211_IFTYPE_ADHOC:
1178 ar->next_mode = ADHOC_NETWORK;
1179 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001180 case NL80211_IFTYPE_AP:
1181 ar->next_mode = AP_NETWORK;
1182 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001183 case NL80211_IFTYPE_P2P_CLIENT:
1184 ar->next_mode = INFRA_NETWORK;
1185 break;
1186 case NL80211_IFTYPE_P2P_GO:
1187 ar->next_mode = AP_NETWORK;
1188 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001189 default:
1190 ath6kl_err("invalid interface type %u\n", type);
1191 return -EOPNOTSUPP;
1192 }
1193
1194 wdev->iftype = type;
1195
1196 return 0;
1197}
1198
1199static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1200 struct net_device *dev,
1201 struct cfg80211_ibss_params *ibss_param)
1202{
1203 struct ath6kl *ar = ath6kl_priv(dev);
1204 int status;
1205
1206 if (!ath6kl_cfg80211_ready(ar))
1207 return -EIO;
1208
1209 ar->ssid_len = ibss_param->ssid_len;
1210 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1211
1212 if (ibss_param->channel)
1213 ar->ch_hint = ibss_param->channel->center_freq;
1214
1215 if (ibss_param->channel_fixed) {
1216 /*
1217 * TODO: channel_fixed: The channel should be fixed, do not
1218 * search for IBSSs to join on other channels. Target
1219 * firmware does not support this feature, needs to be
1220 * updated.
1221 */
1222 return -EOPNOTSUPP;
1223 }
1224
1225 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1226 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1227 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1228
1229 ath6kl_set_wpa_version(ar, 0);
1230
1231 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1232 if (status)
1233 return status;
1234
1235 if (ibss_param->privacy) {
1236 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1237 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1238 } else {
1239 ath6kl_set_cipher(ar, 0, true);
1240 ath6kl_set_cipher(ar, 0, false);
1241 }
1242
1243 ar->nw_type = ar->next_mode;
1244
1245 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1246 "%s: connect called with authmode %d dot11 auth %d"
1247 " PW crypto %d PW crypto len %d GRP crypto %d"
1248 " GRP crypto len %d channel hint %u\n",
1249 __func__,
1250 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1251 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001252 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001253
1254 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1255 ar->dot11_auth_mode, ar->auth_mode,
1256 ar->prwise_crypto,
1257 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001258 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001259 ar->ssid_len, ar->ssid,
1260 ar->req_bssid, ar->ch_hint,
1261 ar->connect_ctrl_flags);
1262 set_bit(CONNECT_PEND, &ar->flag);
1263
1264 return 0;
1265}
1266
1267static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1268 struct net_device *dev)
1269{
1270 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1271
1272 if (!ath6kl_cfg80211_ready(ar))
1273 return -EIO;
1274
1275 ath6kl_disconnect(ar);
1276 memset(ar->ssid, 0, sizeof(ar->ssid));
1277 ar->ssid_len = 0;
1278
1279 return 0;
1280}
1281
1282static const u32 cipher_suites[] = {
1283 WLAN_CIPHER_SUITE_WEP40,
1284 WLAN_CIPHER_SUITE_WEP104,
1285 WLAN_CIPHER_SUITE_TKIP,
1286 WLAN_CIPHER_SUITE_CCMP,
1287};
1288
1289static bool is_rate_legacy(s32 rate)
1290{
1291 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1292 6000, 9000, 12000, 18000, 24000,
1293 36000, 48000, 54000
1294 };
1295 u8 i;
1296
1297 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1298 if (rate == legacy[i])
1299 return true;
1300
1301 return false;
1302}
1303
1304static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1305{
1306 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1307 52000, 58500, 65000, 72200
1308 };
1309 u8 i;
1310
1311 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1312 if (rate == ht20[i]) {
1313 if (i == ARRAY_SIZE(ht20) - 1)
1314 /* last rate uses sgi */
1315 *sgi = true;
1316 else
1317 *sgi = false;
1318
1319 *mcs = i;
1320 return true;
1321 }
1322 }
1323 return false;
1324}
1325
1326static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1327{
1328 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1329 81000, 108000, 121500, 135000,
1330 150000
1331 };
1332 u8 i;
1333
1334 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1335 if (rate == ht40[i]) {
1336 if (i == ARRAY_SIZE(ht40) - 1)
1337 /* last rate uses sgi */
1338 *sgi = true;
1339 else
1340 *sgi = false;
1341
1342 *mcs = i;
1343 return true;
1344 }
1345 }
1346
1347 return false;
1348}
1349
1350static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1351 u8 *mac, struct station_info *sinfo)
1352{
1353 struct ath6kl *ar = ath6kl_priv(dev);
1354 long left;
1355 bool sgi;
1356 s32 rate;
1357 int ret;
1358 u8 mcs;
1359
1360 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1361 return -ENOENT;
1362
1363 if (down_interruptible(&ar->sem))
1364 return -EBUSY;
1365
1366 set_bit(STATS_UPDATE_PEND, &ar->flag);
1367
1368 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1369
1370 if (ret != 0) {
1371 up(&ar->sem);
1372 return -EIO;
1373 }
1374
1375 left = wait_event_interruptible_timeout(ar->event_wq,
1376 !test_bit(STATS_UPDATE_PEND,
1377 &ar->flag),
1378 WMI_TIMEOUT);
1379
1380 up(&ar->sem);
1381
1382 if (left == 0)
1383 return -ETIMEDOUT;
1384 else if (left < 0)
1385 return left;
1386
1387 if (ar->target_stats.rx_byte) {
1388 sinfo->rx_bytes = ar->target_stats.rx_byte;
1389 sinfo->filled |= STATION_INFO_RX_BYTES;
1390 sinfo->rx_packets = ar->target_stats.rx_pkt;
1391 sinfo->filled |= STATION_INFO_RX_PACKETS;
1392 }
1393
1394 if (ar->target_stats.tx_byte) {
1395 sinfo->tx_bytes = ar->target_stats.tx_byte;
1396 sinfo->filled |= STATION_INFO_TX_BYTES;
1397 sinfo->tx_packets = ar->target_stats.tx_pkt;
1398 sinfo->filled |= STATION_INFO_TX_PACKETS;
1399 }
1400
1401 sinfo->signal = ar->target_stats.cs_rssi;
1402 sinfo->filled |= STATION_INFO_SIGNAL;
1403
1404 rate = ar->target_stats.tx_ucast_rate;
1405
1406 if (is_rate_legacy(rate)) {
1407 sinfo->txrate.legacy = rate / 100;
1408 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1409 if (sgi) {
1410 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1411 sinfo->txrate.mcs = mcs - 1;
1412 } else {
1413 sinfo->txrate.mcs = mcs;
1414 }
1415
1416 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1417 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1418 if (sgi) {
1419 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1420 sinfo->txrate.mcs = mcs - 1;
1421 } else {
1422 sinfo->txrate.mcs = mcs;
1423 }
1424
1425 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1426 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1427 } else {
1428 ath6kl_warn("invalid rate: %d\n", rate);
1429 return 0;
1430 }
1431
1432 sinfo->filled |= STATION_INFO_TX_BITRATE;
1433
1434 return 0;
1435}
1436
1437static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1438 struct cfg80211_pmksa *pmksa)
1439{
1440 struct ath6kl *ar = ath6kl_priv(netdev);
1441 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1442 pmksa->pmkid, true);
1443}
1444
1445static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1446 struct cfg80211_pmksa *pmksa)
1447{
1448 struct ath6kl *ar = ath6kl_priv(netdev);
1449 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1450 pmksa->pmkid, false);
1451}
1452
1453static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1454{
1455 struct ath6kl *ar = ath6kl_priv(netdev);
1456 if (test_bit(CONNECTED, &ar->flag))
1457 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1458 return 0;
1459}
1460
Kalle Valoabcb3442011-07-22 08:26:20 +03001461#ifdef CONFIG_PM
1462static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1463 struct cfg80211_wowlan *wow)
1464{
1465 struct ath6kl *ar = wiphy_priv(wiphy);
1466
1467 return ath6kl_hif_suspend(ar);
1468}
1469#endif
1470
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001471static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1472 struct ieee80211_channel *chan,
1473 enum nl80211_channel_type channel_type)
1474{
1475 struct ath6kl *ar = ath6kl_priv(dev);
1476
1477 if (!ath6kl_cfg80211_ready(ar))
1478 return -EIO;
1479
1480 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1481 __func__, chan->center_freq, chan->hw_value);
1482 ar->next_chan = chan->center_freq;
1483
1484 return 0;
1485}
1486
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001487static bool ath6kl_is_p2p_ie(const u8 *pos)
1488{
1489 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1490 pos[2] == 0x50 && pos[3] == 0x6f &&
1491 pos[4] == 0x9a && pos[5] == 0x09;
1492}
1493
1494static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1495 size_t ies_len)
1496{
1497 const u8 *pos;
1498 u8 *buf = NULL;
1499 size_t len = 0;
1500 int ret;
1501
1502 /*
1503 * Filter out P2P IE(s) since they will be included depending on
1504 * the Probe Request frame in ath6kl_send_go_probe_resp().
1505 */
1506
1507 if (ies && ies_len) {
1508 buf = kmalloc(ies_len, GFP_KERNEL);
1509 if (buf == NULL)
1510 return -ENOMEM;
1511 pos = ies;
1512 while (pos + 1 < ies + ies_len) {
1513 if (pos + 2 + pos[1] > ies + ies_len)
1514 break;
1515 if (!ath6kl_is_p2p_ie(pos)) {
1516 memcpy(buf + len, pos, 2 + pos[1]);
1517 len += 2 + pos[1];
1518 }
1519 pos += 2 + pos[1];
1520 }
1521 }
1522
1523 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1524 buf, len);
1525 kfree(buf);
1526 return ret;
1527}
1528
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001529static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1530 struct beacon_parameters *info, bool add)
1531{
1532 struct ath6kl *ar = ath6kl_priv(dev);
1533 struct ieee80211_mgmt *mgmt;
1534 u8 *ies;
1535 int ies_len;
1536 struct wmi_connect_cmd p;
1537 int res;
1538 int i;
1539
1540 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1541
1542 if (!ath6kl_cfg80211_ready(ar))
1543 return -EIO;
1544
1545 if (ar->next_mode != AP_NETWORK)
1546 return -EOPNOTSUPP;
1547
1548 if (info->beacon_ies) {
1549 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1550 info->beacon_ies,
1551 info->beacon_ies_len);
1552 if (res)
1553 return res;
1554 }
1555 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001556 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1557 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001558 if (res)
1559 return res;
1560 }
1561 if (info->assocresp_ies) {
1562 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1563 info->assocresp_ies,
1564 info->assocresp_ies_len);
1565 if (res)
1566 return res;
1567 }
1568
1569 if (!add)
1570 return 0;
1571
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001572 ar->ap_mode_bkey.valid = false;
1573
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001574 /* TODO:
1575 * info->interval
1576 * info->dtim_period
1577 */
1578
1579 if (info->head == NULL)
1580 return -EINVAL;
1581 mgmt = (struct ieee80211_mgmt *) info->head;
1582 ies = mgmt->u.beacon.variable;
1583 if (ies > info->head + info->head_len)
1584 return -EINVAL;
1585 ies_len = info->head + info->head_len - ies;
1586
1587 if (info->ssid == NULL)
1588 return -EINVAL;
1589 memcpy(ar->ssid, info->ssid, info->ssid_len);
1590 ar->ssid_len = info->ssid_len;
1591 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1592 return -EOPNOTSUPP; /* TODO */
1593
1594 ar->dot11_auth_mode = OPEN_AUTH;
1595
1596 memset(&p, 0, sizeof(p));
1597
1598 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1599 switch (info->crypto.akm_suites[i]) {
1600 case WLAN_AKM_SUITE_8021X:
1601 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1602 p.auth_mode |= WPA_AUTH;
1603 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1604 p.auth_mode |= WPA2_AUTH;
1605 break;
1606 case WLAN_AKM_SUITE_PSK:
1607 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1608 p.auth_mode |= WPA_PSK_AUTH;
1609 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1610 p.auth_mode |= WPA2_PSK_AUTH;
1611 break;
1612 }
1613 }
1614 if (p.auth_mode == 0)
1615 p.auth_mode = NONE_AUTH;
1616 ar->auth_mode = p.auth_mode;
1617
1618 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1619 switch (info->crypto.ciphers_pairwise[i]) {
1620 case WLAN_CIPHER_SUITE_WEP40:
1621 case WLAN_CIPHER_SUITE_WEP104:
1622 p.prwise_crypto_type |= WEP_CRYPT;
1623 break;
1624 case WLAN_CIPHER_SUITE_TKIP:
1625 p.prwise_crypto_type |= TKIP_CRYPT;
1626 break;
1627 case WLAN_CIPHER_SUITE_CCMP:
1628 p.prwise_crypto_type |= AES_CRYPT;
1629 break;
1630 }
1631 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001632 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001633 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001634 ath6kl_set_cipher(ar, 0, true);
1635 } else if (info->crypto.n_ciphers_pairwise == 1)
1636 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001637
1638 switch (info->crypto.cipher_group) {
1639 case WLAN_CIPHER_SUITE_WEP40:
1640 case WLAN_CIPHER_SUITE_WEP104:
1641 p.grp_crypto_type = WEP_CRYPT;
1642 break;
1643 case WLAN_CIPHER_SUITE_TKIP:
1644 p.grp_crypto_type = TKIP_CRYPT;
1645 break;
1646 case WLAN_CIPHER_SUITE_CCMP:
1647 p.grp_crypto_type = AES_CRYPT;
1648 break;
1649 default:
1650 p.grp_crypto_type = NONE_CRYPT;
1651 break;
1652 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001653 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001654
1655 p.nw_type = AP_NETWORK;
1656 ar->nw_type = ar->next_mode;
1657
1658 p.ssid_len = ar->ssid_len;
1659 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1660 p.dot11_auth_mode = ar->dot11_auth_mode;
1661 p.ch = cpu_to_le16(ar->next_chan);
1662
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001663 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1664 if (res < 0)
1665 return res;
1666
1667 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001668}
1669
1670static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1671 struct beacon_parameters *info)
1672{
1673 return ath6kl_ap_beacon(wiphy, dev, info, true);
1674}
1675
1676static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1677 struct beacon_parameters *info)
1678{
1679 return ath6kl_ap_beacon(wiphy, dev, info, false);
1680}
1681
1682static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1683{
1684 struct ath6kl *ar = ath6kl_priv(dev);
1685
1686 if (ar->nw_type != AP_NETWORK)
1687 return -EOPNOTSUPP;
1688 if (!test_bit(CONNECTED, &ar->flag))
1689 return -ENOTCONN;
1690
1691 ath6kl_wmi_disconnect_cmd(ar->wmi);
1692 clear_bit(CONNECTED, &ar->flag);
1693
1694 return 0;
1695}
1696
Jouni Malinen23875132011-08-30 21:57:53 +03001697static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1698 u8 *mac, struct station_parameters *params)
1699{
1700 struct ath6kl *ar = ath6kl_priv(dev);
1701
1702 if (ar->nw_type != AP_NETWORK)
1703 return -EOPNOTSUPP;
1704
1705 /* Use this only for authorizing/unauthorizing a station */
1706 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1707 return -EOPNOTSUPP;
1708
1709 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1710 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1711 mac, 0);
1712 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1713 0);
1714}
1715
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001716static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1717 struct net_device *dev,
1718 struct ieee80211_channel *chan,
1719 enum nl80211_channel_type channel_type,
1720 unsigned int duration,
1721 u64 *cookie)
1722{
1723 struct ath6kl *ar = ath6kl_priv(dev);
1724
1725 /* TODO: if already pending or ongoing remain-on-channel,
1726 * return -EBUSY */
1727 *cookie = 1; /* only a single pending request is supported */
1728
1729 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1730 duration);
1731}
1732
1733static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1734 struct net_device *dev,
1735 u64 cookie)
1736{
1737 struct ath6kl *ar = ath6kl_priv(dev);
1738
1739 if (cookie != 1)
1740 return -ENOENT;
1741
1742 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1743}
1744
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001745static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1746 size_t len, unsigned int freq)
1747{
1748 const u8 *pos;
1749 u8 *p2p;
1750 int p2p_len;
1751 int ret;
1752 const struct ieee80211_mgmt *mgmt;
1753
1754 mgmt = (const struct ieee80211_mgmt *) buf;
1755
1756 /* Include P2P IE(s) from the frame generated in user space. */
1757
1758 p2p = kmalloc(len, GFP_KERNEL);
1759 if (p2p == NULL)
1760 return -ENOMEM;
1761 p2p_len = 0;
1762
1763 pos = mgmt->u.probe_resp.variable;
1764 while (pos + 1 < buf + len) {
1765 if (pos + 2 + pos[1] > buf + len)
1766 break;
1767 if (ath6kl_is_p2p_ie(pos)) {
1768 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1769 p2p_len += 2 + pos[1];
1770 }
1771 pos += 2 + pos[1];
1772 }
1773
1774 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1775 p2p, p2p_len);
1776 kfree(p2p);
1777 return ret;
1778}
1779
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001780static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1781 struct ieee80211_channel *chan, bool offchan,
1782 enum nl80211_channel_type channel_type,
1783 bool channel_type_valid, unsigned int wait,
1784 const u8 *buf, size_t len, u64 *cookie)
1785{
1786 struct ath6kl *ar = ath6kl_priv(dev);
1787 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001788 const struct ieee80211_mgmt *mgmt;
1789
1790 mgmt = (const struct ieee80211_mgmt *) buf;
1791 if (buf + len >= mgmt->u.probe_resp.variable &&
1792 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1793 ieee80211_is_probe_resp(mgmt->frame_control)) {
1794 /*
1795 * Send Probe Response frame in AP mode using a separate WMI
1796 * command to allow the target to fill in the generic IEs.
1797 */
1798 *cookie = 0; /* TX status not supported */
1799 return ath6kl_send_go_probe_resp(ar, buf, len,
1800 chan->center_freq);
1801 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001802
1803 id = ar->send_action_id++;
1804 if (id == 0) {
1805 /*
1806 * 0 is a reserved value in the WMI command and shall not be
1807 * used for the command.
1808 */
1809 id = ar->send_action_id++;
1810 }
1811
1812 *cookie = id;
1813 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1814 buf, len);
1815}
1816
Jouni Malinenae32c302011-08-30 21:58:01 +03001817static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1818 struct net_device *dev,
1819 u16 frame_type, bool reg)
1820{
1821 struct ath6kl *ar = ath6kl_priv(dev);
1822
1823 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1824 __func__, frame_type, reg);
1825 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1826 /*
1827 * Note: This notification callback is not allowed to sleep, so
1828 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1829 * hardcode target to report Probe Request frames all the time.
1830 */
1831 ar->probe_req_report = reg;
1832 }
1833}
1834
Jouni Malinenf80574a2011-08-30 21:58:04 +03001835static const struct ieee80211_txrx_stypes
1836ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1837 [NL80211_IFTYPE_STATION] = {
1838 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1839 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1840 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1841 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1842 },
1843 [NL80211_IFTYPE_P2P_CLIENT] = {
1844 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1845 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1846 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1847 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1848 },
1849 [NL80211_IFTYPE_P2P_GO] = {
1850 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1851 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1852 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1853 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1854 },
1855};
1856
Kalle Valobdcd8172011-07-18 00:22:30 +03001857static struct cfg80211_ops ath6kl_cfg80211_ops = {
1858 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1859 .scan = ath6kl_cfg80211_scan,
1860 .connect = ath6kl_cfg80211_connect,
1861 .disconnect = ath6kl_cfg80211_disconnect,
1862 .add_key = ath6kl_cfg80211_add_key,
1863 .get_key = ath6kl_cfg80211_get_key,
1864 .del_key = ath6kl_cfg80211_del_key,
1865 .set_default_key = ath6kl_cfg80211_set_default_key,
1866 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1867 .set_tx_power = ath6kl_cfg80211_set_txpower,
1868 .get_tx_power = ath6kl_cfg80211_get_txpower,
1869 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1870 .join_ibss = ath6kl_cfg80211_join_ibss,
1871 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1872 .get_station = ath6kl_get_station,
1873 .set_pmksa = ath6kl_set_pmksa,
1874 .del_pmksa = ath6kl_del_pmksa,
1875 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001876 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001877#ifdef CONFIG_PM
1878 .suspend = ar6k_cfg80211_suspend,
1879#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001880 .set_channel = ath6kl_set_channel,
1881 .add_beacon = ath6kl_add_beacon,
1882 .set_beacon = ath6kl_set_beacon,
1883 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001884 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001885 .remain_on_channel = ath6kl_remain_on_channel,
1886 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001887 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001888 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001889};
1890
1891struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1892{
1893 int ret = 0;
1894 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001895 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001896
1897 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1898 if (!wdev) {
1899 ath6kl_err("couldn't allocate wireless device\n");
1900 return NULL;
1901 }
1902
1903 /* create a new wiphy for use with cfg80211 */
1904 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1905 if (!wdev->wiphy) {
1906 ath6kl_err("couldn't allocate wiphy device\n");
1907 kfree(wdev);
1908 return NULL;
1909 }
1910
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001911 ar = wiphy_priv(wdev->wiphy);
1912 ar->p2p = !!ath6kl_p2p;
1913
Jouni Malinenf80574a2011-08-30 21:58:04 +03001914 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1915
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001916 wdev->wiphy->max_remain_on_channel_duration = 5000;
1917
Kalle Valobdcd8172011-07-18 00:22:30 +03001918 /* set device pointer for wiphy */
1919 set_wiphy_dev(wdev->wiphy, dev);
1920
1921 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001922 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001923 if (ar->p2p) {
1924 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1925 BIT(NL80211_IFTYPE_P2P_CLIENT);
1926 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001927 /* max num of ssids that can be probed during scanning */
1928 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001929 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001930 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1931 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1932 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1933
1934 wdev->wiphy->cipher_suites = cipher_suites;
1935 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1936
1937 ret = wiphy_register(wdev->wiphy);
1938 if (ret < 0) {
1939 ath6kl_err("couldn't register wiphy device\n");
1940 wiphy_free(wdev->wiphy);
1941 kfree(wdev);
1942 return NULL;
1943 }
1944
1945 return wdev;
1946}
1947
1948void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1949{
1950 struct wireless_dev *wdev = ar->wdev;
1951
1952 if (ar->scan_req) {
1953 cfg80211_scan_done(ar->scan_req, true);
1954 ar->scan_req = NULL;
1955 }
1956
1957 if (!wdev)
1958 return;
1959
1960 wiphy_unregister(wdev->wiphy);
1961 wiphy_free(wdev->wiphy);
1962 kfree(wdev);
1963}