blob: e196097e7524e8813c4b5d035f462da8052d62de [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
Jouni Malinen151411e2011-09-15 15:10:16 +0300907 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
908 !test_bit(CONNECTED, &ar->flag)) {
909 /*
910 * Store the key locally so that it can be re-configured after
911 * the AP mode has properly started
912 * (ath6kl_install_statioc_wep_keys).
913 */
914 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
915 "until AP mode has been started\n");
916 ar->wep_key_list[key_index].key_len = key->key_len;
917 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
918 return 0;
919 }
920
Kalle Valobdcd8172011-07-18 00:22:30 +0300921 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
922 key_type, key_usage, key->key_len,
923 key->seq, key->key, KEY_OP_INIT_VAL,
924 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
925
926 if (status)
927 return -EIO;
928
929 return 0;
930}
931
932static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
933 u8 key_index, bool pairwise,
934 const u8 *mac_addr)
935{
936 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
937
938 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
939
940 if (!ath6kl_cfg80211_ready(ar))
941 return -EIO;
942
943 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
944 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
945 "%s: key index %d out of bounds\n", __func__,
946 key_index);
947 return -ENOENT;
948 }
949
950 if (!ar->keys[key_index].key_len) {
951 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
952 "%s: index %d is empty\n", __func__, key_index);
953 return 0;
954 }
955
956 ar->keys[key_index].key_len = 0;
957
958 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
959}
960
961static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
962 u8 key_index, bool pairwise,
963 const u8 *mac_addr, void *cookie,
964 void (*callback) (void *cookie,
965 struct key_params *))
966{
967 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
968 struct ath6kl_key *key = NULL;
969 struct key_params params;
970
971 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
972
973 if (!ath6kl_cfg80211_ready(ar))
974 return -EIO;
975
976 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
977 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
978 "%s: key index %d out of bounds\n", __func__,
979 key_index);
980 return -ENOENT;
981 }
982
983 key = &ar->keys[key_index];
984 memset(&params, 0, sizeof(params));
985 params.cipher = key->cipher;
986 params.key_len = key->key_len;
987 params.seq_len = key->seq_len;
988 params.seq = key->seq;
989 params.key = key->key;
990
991 callback(cookie, &params);
992
993 return key->key_len ? 0 : -ENOENT;
994}
995
996static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
997 struct net_device *ndev,
998 u8 key_index, bool unicast,
999 bool multicast)
1000{
1001 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
1002 struct ath6kl_key *key = NULL;
1003 int status = 0;
1004 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001005 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001006
1007 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1008
1009 if (!ath6kl_cfg80211_ready(ar))
1010 return -EIO;
1011
1012 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1013 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1014 "%s: key index %d out of bounds\n",
1015 __func__, key_index);
1016 return -ENOENT;
1017 }
1018
1019 if (!ar->keys[key_index].key_len) {
1020 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1021 __func__, key_index);
1022 return -EINVAL;
1023 }
1024
1025 ar->def_txkey_index = key_index;
1026 key = &ar->keys[ar->def_txkey_index];
1027 key_usage = GROUP_USAGE;
1028 if (ar->prwise_crypto == WEP_CRYPT)
1029 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001030 if (unicast)
1031 key_type = ar->prwise_crypto;
1032 if (multicast)
1033 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001034
Jouni Malinen151411e2011-09-15 15:10:16 +03001035 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001036 return 0; /* Delay until AP mode has been started */
1037
Kalle Valobdcd8172011-07-18 00:22:30 +03001038 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001039 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001040 key->key_len, key->seq, key->key,
1041 KEY_OP_INIT_VAL, NULL,
1042 SYNC_BOTH_WMIFLAG);
1043 if (status)
1044 return -EIO;
1045
1046 return 0;
1047}
1048
1049void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
1050 bool ismcast)
1051{
1052 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1053 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1054
1055 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
1056 (ismcast ? NL80211_KEYTYPE_GROUP :
1057 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1058 GFP_KERNEL);
1059}
1060
1061static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1062{
1063 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1064 int ret;
1065
1066 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1067 changed);
1068
1069 if (!ath6kl_cfg80211_ready(ar))
1070 return -EIO;
1071
1072 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1073 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1074 if (ret != 0) {
1075 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1076 return -EIO;
1077 }
1078 }
1079
1080 return 0;
1081}
1082
1083/*
1084 * The type nl80211_tx_power_setting replaces the following
1085 * data type from 2.6.36 onwards
1086*/
1087static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1088 enum nl80211_tx_power_setting type,
1089 int dbm)
1090{
1091 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1092 u8 ath6kl_dbm;
1093
1094 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1095 type, dbm);
1096
1097 if (!ath6kl_cfg80211_ready(ar))
1098 return -EIO;
1099
1100 switch (type) {
1101 case NL80211_TX_POWER_AUTOMATIC:
1102 return 0;
1103 case NL80211_TX_POWER_LIMITED:
1104 ar->tx_pwr = ath6kl_dbm = dbm;
1105 break;
1106 default:
1107 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1108 __func__, type);
1109 return -EOPNOTSUPP;
1110 }
1111
1112 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1113
1114 return 0;
1115}
1116
1117static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1118{
1119 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1120
1121 if (!ath6kl_cfg80211_ready(ar))
1122 return -EIO;
1123
1124 if (test_bit(CONNECTED, &ar->flag)) {
1125 ar->tx_pwr = 0;
1126
1127 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1128 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1129 return -EIO;
1130 }
1131
1132 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1133 5 * HZ);
1134
1135 if (signal_pending(current)) {
1136 ath6kl_err("target did not respond\n");
1137 return -EINTR;
1138 }
1139 }
1140
1141 *dbm = ar->tx_pwr;
1142 return 0;
1143}
1144
1145static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1146 struct net_device *dev,
1147 bool pmgmt, int timeout)
1148{
1149 struct ath6kl *ar = ath6kl_priv(dev);
1150 struct wmi_power_mode_cmd mode;
1151
1152 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1153 __func__, pmgmt, timeout);
1154
1155 if (!ath6kl_cfg80211_ready(ar))
1156 return -EIO;
1157
1158 if (pmgmt) {
1159 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1160 mode.pwr_mode = REC_POWER;
1161 } else {
1162 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1163 mode.pwr_mode = MAX_PERF_POWER;
1164 }
1165
1166 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1167 ath6kl_err("wmi_powermode_cmd failed\n");
1168 return -EIO;
1169 }
1170
1171 return 0;
1172}
1173
1174static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1175 struct net_device *ndev,
1176 enum nl80211_iftype type, u32 *flags,
1177 struct vif_params *params)
1178{
1179 struct ath6kl *ar = ath6kl_priv(ndev);
1180 struct wireless_dev *wdev = ar->wdev;
1181
1182 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1183
1184 if (!ath6kl_cfg80211_ready(ar))
1185 return -EIO;
1186
1187 switch (type) {
1188 case NL80211_IFTYPE_STATION:
1189 ar->next_mode = INFRA_NETWORK;
1190 break;
1191 case NL80211_IFTYPE_ADHOC:
1192 ar->next_mode = ADHOC_NETWORK;
1193 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001194 case NL80211_IFTYPE_AP:
1195 ar->next_mode = AP_NETWORK;
1196 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001197 case NL80211_IFTYPE_P2P_CLIENT:
1198 ar->next_mode = INFRA_NETWORK;
1199 break;
1200 case NL80211_IFTYPE_P2P_GO:
1201 ar->next_mode = AP_NETWORK;
1202 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001203 default:
1204 ath6kl_err("invalid interface type %u\n", type);
1205 return -EOPNOTSUPP;
1206 }
1207
1208 wdev->iftype = type;
1209
1210 return 0;
1211}
1212
1213static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1214 struct net_device *dev,
1215 struct cfg80211_ibss_params *ibss_param)
1216{
1217 struct ath6kl *ar = ath6kl_priv(dev);
1218 int status;
1219
1220 if (!ath6kl_cfg80211_ready(ar))
1221 return -EIO;
1222
1223 ar->ssid_len = ibss_param->ssid_len;
1224 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1225
1226 if (ibss_param->channel)
1227 ar->ch_hint = ibss_param->channel->center_freq;
1228
1229 if (ibss_param->channel_fixed) {
1230 /*
1231 * TODO: channel_fixed: The channel should be fixed, do not
1232 * search for IBSSs to join on other channels. Target
1233 * firmware does not support this feature, needs to be
1234 * updated.
1235 */
1236 return -EOPNOTSUPP;
1237 }
1238
1239 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1240 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1241 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1242
1243 ath6kl_set_wpa_version(ar, 0);
1244
1245 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1246 if (status)
1247 return status;
1248
1249 if (ibss_param->privacy) {
1250 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1251 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1252 } else {
1253 ath6kl_set_cipher(ar, 0, true);
1254 ath6kl_set_cipher(ar, 0, false);
1255 }
1256
1257 ar->nw_type = ar->next_mode;
1258
1259 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1260 "%s: connect called with authmode %d dot11 auth %d"
1261 " PW crypto %d PW crypto len %d GRP crypto %d"
1262 " GRP crypto len %d channel hint %u\n",
1263 __func__,
1264 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1265 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001266 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001267
1268 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1269 ar->dot11_auth_mode, ar->auth_mode,
1270 ar->prwise_crypto,
1271 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001272 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001273 ar->ssid_len, ar->ssid,
1274 ar->req_bssid, ar->ch_hint,
1275 ar->connect_ctrl_flags);
1276 set_bit(CONNECT_PEND, &ar->flag);
1277
1278 return 0;
1279}
1280
1281static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1282 struct net_device *dev)
1283{
1284 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1285
1286 if (!ath6kl_cfg80211_ready(ar))
1287 return -EIO;
1288
1289 ath6kl_disconnect(ar);
1290 memset(ar->ssid, 0, sizeof(ar->ssid));
1291 ar->ssid_len = 0;
1292
1293 return 0;
1294}
1295
1296static const u32 cipher_suites[] = {
1297 WLAN_CIPHER_SUITE_WEP40,
1298 WLAN_CIPHER_SUITE_WEP104,
1299 WLAN_CIPHER_SUITE_TKIP,
1300 WLAN_CIPHER_SUITE_CCMP,
1301};
1302
1303static bool is_rate_legacy(s32 rate)
1304{
1305 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1306 6000, 9000, 12000, 18000, 24000,
1307 36000, 48000, 54000
1308 };
1309 u8 i;
1310
1311 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1312 if (rate == legacy[i])
1313 return true;
1314
1315 return false;
1316}
1317
1318static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1319{
1320 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1321 52000, 58500, 65000, 72200
1322 };
1323 u8 i;
1324
1325 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1326 if (rate == ht20[i]) {
1327 if (i == ARRAY_SIZE(ht20) - 1)
1328 /* last rate uses sgi */
1329 *sgi = true;
1330 else
1331 *sgi = false;
1332
1333 *mcs = i;
1334 return true;
1335 }
1336 }
1337 return false;
1338}
1339
1340static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1341{
1342 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1343 81000, 108000, 121500, 135000,
1344 150000
1345 };
1346 u8 i;
1347
1348 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1349 if (rate == ht40[i]) {
1350 if (i == ARRAY_SIZE(ht40) - 1)
1351 /* last rate uses sgi */
1352 *sgi = true;
1353 else
1354 *sgi = false;
1355
1356 *mcs = i;
1357 return true;
1358 }
1359 }
1360
1361 return false;
1362}
1363
1364static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1365 u8 *mac, struct station_info *sinfo)
1366{
1367 struct ath6kl *ar = ath6kl_priv(dev);
1368 long left;
1369 bool sgi;
1370 s32 rate;
1371 int ret;
1372 u8 mcs;
1373
1374 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1375 return -ENOENT;
1376
1377 if (down_interruptible(&ar->sem))
1378 return -EBUSY;
1379
1380 set_bit(STATS_UPDATE_PEND, &ar->flag);
1381
1382 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1383
1384 if (ret != 0) {
1385 up(&ar->sem);
1386 return -EIO;
1387 }
1388
1389 left = wait_event_interruptible_timeout(ar->event_wq,
1390 !test_bit(STATS_UPDATE_PEND,
1391 &ar->flag),
1392 WMI_TIMEOUT);
1393
1394 up(&ar->sem);
1395
1396 if (left == 0)
1397 return -ETIMEDOUT;
1398 else if (left < 0)
1399 return left;
1400
1401 if (ar->target_stats.rx_byte) {
1402 sinfo->rx_bytes = ar->target_stats.rx_byte;
1403 sinfo->filled |= STATION_INFO_RX_BYTES;
1404 sinfo->rx_packets = ar->target_stats.rx_pkt;
1405 sinfo->filled |= STATION_INFO_RX_PACKETS;
1406 }
1407
1408 if (ar->target_stats.tx_byte) {
1409 sinfo->tx_bytes = ar->target_stats.tx_byte;
1410 sinfo->filled |= STATION_INFO_TX_BYTES;
1411 sinfo->tx_packets = ar->target_stats.tx_pkt;
1412 sinfo->filled |= STATION_INFO_TX_PACKETS;
1413 }
1414
1415 sinfo->signal = ar->target_stats.cs_rssi;
1416 sinfo->filled |= STATION_INFO_SIGNAL;
1417
1418 rate = ar->target_stats.tx_ucast_rate;
1419
1420 if (is_rate_legacy(rate)) {
1421 sinfo->txrate.legacy = rate / 100;
1422 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1423 if (sgi) {
1424 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1425 sinfo->txrate.mcs = mcs - 1;
1426 } else {
1427 sinfo->txrate.mcs = mcs;
1428 }
1429
1430 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1431 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1432 if (sgi) {
1433 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1434 sinfo->txrate.mcs = mcs - 1;
1435 } else {
1436 sinfo->txrate.mcs = mcs;
1437 }
1438
1439 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1440 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1441 } else {
1442 ath6kl_warn("invalid rate: %d\n", rate);
1443 return 0;
1444 }
1445
1446 sinfo->filled |= STATION_INFO_TX_BITRATE;
1447
1448 return 0;
1449}
1450
1451static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1452 struct cfg80211_pmksa *pmksa)
1453{
1454 struct ath6kl *ar = ath6kl_priv(netdev);
1455 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1456 pmksa->pmkid, true);
1457}
1458
1459static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1460 struct cfg80211_pmksa *pmksa)
1461{
1462 struct ath6kl *ar = ath6kl_priv(netdev);
1463 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1464 pmksa->pmkid, false);
1465}
1466
1467static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1468{
1469 struct ath6kl *ar = ath6kl_priv(netdev);
1470 if (test_bit(CONNECTED, &ar->flag))
1471 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1472 return 0;
1473}
1474
Kalle Valoabcb3442011-07-22 08:26:20 +03001475#ifdef CONFIG_PM
1476static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1477 struct cfg80211_wowlan *wow)
1478{
1479 struct ath6kl *ar = wiphy_priv(wiphy);
1480
1481 return ath6kl_hif_suspend(ar);
1482}
1483#endif
1484
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001485static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1486 struct ieee80211_channel *chan,
1487 enum nl80211_channel_type channel_type)
1488{
1489 struct ath6kl *ar = ath6kl_priv(dev);
1490
1491 if (!ath6kl_cfg80211_ready(ar))
1492 return -EIO;
1493
1494 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1495 __func__, chan->center_freq, chan->hw_value);
1496 ar->next_chan = chan->center_freq;
1497
1498 return 0;
1499}
1500
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001501static bool ath6kl_is_p2p_ie(const u8 *pos)
1502{
1503 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1504 pos[2] == 0x50 && pos[3] == 0x6f &&
1505 pos[4] == 0x9a && pos[5] == 0x09;
1506}
1507
1508static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1509 size_t ies_len)
1510{
1511 const u8 *pos;
1512 u8 *buf = NULL;
1513 size_t len = 0;
1514 int ret;
1515
1516 /*
1517 * Filter out P2P IE(s) since they will be included depending on
1518 * the Probe Request frame in ath6kl_send_go_probe_resp().
1519 */
1520
1521 if (ies && ies_len) {
1522 buf = kmalloc(ies_len, GFP_KERNEL);
1523 if (buf == NULL)
1524 return -ENOMEM;
1525 pos = ies;
1526 while (pos + 1 < ies + ies_len) {
1527 if (pos + 2 + pos[1] > ies + ies_len)
1528 break;
1529 if (!ath6kl_is_p2p_ie(pos)) {
1530 memcpy(buf + len, pos, 2 + pos[1]);
1531 len += 2 + pos[1];
1532 }
1533 pos += 2 + pos[1];
1534 }
1535 }
1536
1537 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1538 buf, len);
1539 kfree(buf);
1540 return ret;
1541}
1542
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001543static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1544 struct beacon_parameters *info, bool add)
1545{
1546 struct ath6kl *ar = ath6kl_priv(dev);
1547 struct ieee80211_mgmt *mgmt;
1548 u8 *ies;
1549 int ies_len;
1550 struct wmi_connect_cmd p;
1551 int res;
1552 int i;
1553
1554 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1555
1556 if (!ath6kl_cfg80211_ready(ar))
1557 return -EIO;
1558
1559 if (ar->next_mode != AP_NETWORK)
1560 return -EOPNOTSUPP;
1561
1562 if (info->beacon_ies) {
1563 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1564 info->beacon_ies,
1565 info->beacon_ies_len);
1566 if (res)
1567 return res;
1568 }
1569 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001570 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1571 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001572 if (res)
1573 return res;
1574 }
1575 if (info->assocresp_ies) {
1576 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1577 info->assocresp_ies,
1578 info->assocresp_ies_len);
1579 if (res)
1580 return res;
1581 }
1582
1583 if (!add)
1584 return 0;
1585
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001586 ar->ap_mode_bkey.valid = false;
1587
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001588 /* TODO:
1589 * info->interval
1590 * info->dtim_period
1591 */
1592
1593 if (info->head == NULL)
1594 return -EINVAL;
1595 mgmt = (struct ieee80211_mgmt *) info->head;
1596 ies = mgmt->u.beacon.variable;
1597 if (ies > info->head + info->head_len)
1598 return -EINVAL;
1599 ies_len = info->head + info->head_len - ies;
1600
1601 if (info->ssid == NULL)
1602 return -EINVAL;
1603 memcpy(ar->ssid, info->ssid, info->ssid_len);
1604 ar->ssid_len = info->ssid_len;
1605 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1606 return -EOPNOTSUPP; /* TODO */
1607
1608 ar->dot11_auth_mode = OPEN_AUTH;
1609
1610 memset(&p, 0, sizeof(p));
1611
1612 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1613 switch (info->crypto.akm_suites[i]) {
1614 case WLAN_AKM_SUITE_8021X:
1615 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1616 p.auth_mode |= WPA_AUTH;
1617 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1618 p.auth_mode |= WPA2_AUTH;
1619 break;
1620 case WLAN_AKM_SUITE_PSK:
1621 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1622 p.auth_mode |= WPA_PSK_AUTH;
1623 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1624 p.auth_mode |= WPA2_PSK_AUTH;
1625 break;
1626 }
1627 }
1628 if (p.auth_mode == 0)
1629 p.auth_mode = NONE_AUTH;
1630 ar->auth_mode = p.auth_mode;
1631
1632 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1633 switch (info->crypto.ciphers_pairwise[i]) {
1634 case WLAN_CIPHER_SUITE_WEP40:
1635 case WLAN_CIPHER_SUITE_WEP104:
1636 p.prwise_crypto_type |= WEP_CRYPT;
1637 break;
1638 case WLAN_CIPHER_SUITE_TKIP:
1639 p.prwise_crypto_type |= TKIP_CRYPT;
1640 break;
1641 case WLAN_CIPHER_SUITE_CCMP:
1642 p.prwise_crypto_type |= AES_CRYPT;
1643 break;
1644 }
1645 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001646 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001647 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001648 ath6kl_set_cipher(ar, 0, true);
1649 } else if (info->crypto.n_ciphers_pairwise == 1)
1650 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001651
1652 switch (info->crypto.cipher_group) {
1653 case WLAN_CIPHER_SUITE_WEP40:
1654 case WLAN_CIPHER_SUITE_WEP104:
1655 p.grp_crypto_type = WEP_CRYPT;
1656 break;
1657 case WLAN_CIPHER_SUITE_TKIP:
1658 p.grp_crypto_type = TKIP_CRYPT;
1659 break;
1660 case WLAN_CIPHER_SUITE_CCMP:
1661 p.grp_crypto_type = AES_CRYPT;
1662 break;
1663 default:
1664 p.grp_crypto_type = NONE_CRYPT;
1665 break;
1666 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001667 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001668
1669 p.nw_type = AP_NETWORK;
1670 ar->nw_type = ar->next_mode;
1671
1672 p.ssid_len = ar->ssid_len;
1673 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1674 p.dot11_auth_mode = ar->dot11_auth_mode;
1675 p.ch = cpu_to_le16(ar->next_chan);
1676
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001677 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1678 if (res < 0)
1679 return res;
1680
1681 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001682}
1683
1684static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1685 struct beacon_parameters *info)
1686{
1687 return ath6kl_ap_beacon(wiphy, dev, info, true);
1688}
1689
1690static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1691 struct beacon_parameters *info)
1692{
1693 return ath6kl_ap_beacon(wiphy, dev, info, false);
1694}
1695
1696static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1697{
1698 struct ath6kl *ar = ath6kl_priv(dev);
1699
1700 if (ar->nw_type != AP_NETWORK)
1701 return -EOPNOTSUPP;
1702 if (!test_bit(CONNECTED, &ar->flag))
1703 return -ENOTCONN;
1704
1705 ath6kl_wmi_disconnect_cmd(ar->wmi);
1706 clear_bit(CONNECTED, &ar->flag);
1707
1708 return 0;
1709}
1710
Jouni Malinen23875132011-08-30 21:57:53 +03001711static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1712 u8 *mac, struct station_parameters *params)
1713{
1714 struct ath6kl *ar = ath6kl_priv(dev);
1715
1716 if (ar->nw_type != AP_NETWORK)
1717 return -EOPNOTSUPP;
1718
1719 /* Use this only for authorizing/unauthorizing a station */
1720 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1721 return -EOPNOTSUPP;
1722
1723 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1724 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1725 mac, 0);
1726 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1727 0);
1728}
1729
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001730static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1731 struct net_device *dev,
1732 struct ieee80211_channel *chan,
1733 enum nl80211_channel_type channel_type,
1734 unsigned int duration,
1735 u64 *cookie)
1736{
1737 struct ath6kl *ar = ath6kl_priv(dev);
1738
1739 /* TODO: if already pending or ongoing remain-on-channel,
1740 * return -EBUSY */
1741 *cookie = 1; /* only a single pending request is supported */
1742
1743 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1744 duration);
1745}
1746
1747static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1748 struct net_device *dev,
1749 u64 cookie)
1750{
1751 struct ath6kl *ar = ath6kl_priv(dev);
1752
1753 if (cookie != 1)
1754 return -ENOENT;
1755
1756 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1757}
1758
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001759static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1760 size_t len, unsigned int freq)
1761{
1762 const u8 *pos;
1763 u8 *p2p;
1764 int p2p_len;
1765 int ret;
1766 const struct ieee80211_mgmt *mgmt;
1767
1768 mgmt = (const struct ieee80211_mgmt *) buf;
1769
1770 /* Include P2P IE(s) from the frame generated in user space. */
1771
1772 p2p = kmalloc(len, GFP_KERNEL);
1773 if (p2p == NULL)
1774 return -ENOMEM;
1775 p2p_len = 0;
1776
1777 pos = mgmt->u.probe_resp.variable;
1778 while (pos + 1 < buf + len) {
1779 if (pos + 2 + pos[1] > buf + len)
1780 break;
1781 if (ath6kl_is_p2p_ie(pos)) {
1782 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1783 p2p_len += 2 + pos[1];
1784 }
1785 pos += 2 + pos[1];
1786 }
1787
1788 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1789 p2p, p2p_len);
1790 kfree(p2p);
1791 return ret;
1792}
1793
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001794static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1795 struct ieee80211_channel *chan, bool offchan,
1796 enum nl80211_channel_type channel_type,
1797 bool channel_type_valid, unsigned int wait,
1798 const u8 *buf, size_t len, u64 *cookie)
1799{
1800 struct ath6kl *ar = ath6kl_priv(dev);
1801 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001802 const struct ieee80211_mgmt *mgmt;
1803
1804 mgmt = (const struct ieee80211_mgmt *) buf;
1805 if (buf + len >= mgmt->u.probe_resp.variable &&
1806 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1807 ieee80211_is_probe_resp(mgmt->frame_control)) {
1808 /*
1809 * Send Probe Response frame in AP mode using a separate WMI
1810 * command to allow the target to fill in the generic IEs.
1811 */
1812 *cookie = 0; /* TX status not supported */
1813 return ath6kl_send_go_probe_resp(ar, buf, len,
1814 chan->center_freq);
1815 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001816
1817 id = ar->send_action_id++;
1818 if (id == 0) {
1819 /*
1820 * 0 is a reserved value in the WMI command and shall not be
1821 * used for the command.
1822 */
1823 id = ar->send_action_id++;
1824 }
1825
1826 *cookie = id;
1827 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1828 buf, len);
1829}
1830
Jouni Malinenae32c302011-08-30 21:58:01 +03001831static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1832 struct net_device *dev,
1833 u16 frame_type, bool reg)
1834{
1835 struct ath6kl *ar = ath6kl_priv(dev);
1836
1837 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1838 __func__, frame_type, reg);
1839 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1840 /*
1841 * Note: This notification callback is not allowed to sleep, so
1842 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1843 * hardcode target to report Probe Request frames all the time.
1844 */
1845 ar->probe_req_report = reg;
1846 }
1847}
1848
Jouni Malinenf80574a2011-08-30 21:58:04 +03001849static const struct ieee80211_txrx_stypes
1850ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1851 [NL80211_IFTYPE_STATION] = {
1852 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1853 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1854 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1855 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1856 },
1857 [NL80211_IFTYPE_P2P_CLIENT] = {
1858 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1859 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1860 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1861 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1862 },
1863 [NL80211_IFTYPE_P2P_GO] = {
1864 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1865 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1866 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1867 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1868 },
1869};
1870
Kalle Valobdcd8172011-07-18 00:22:30 +03001871static struct cfg80211_ops ath6kl_cfg80211_ops = {
1872 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1873 .scan = ath6kl_cfg80211_scan,
1874 .connect = ath6kl_cfg80211_connect,
1875 .disconnect = ath6kl_cfg80211_disconnect,
1876 .add_key = ath6kl_cfg80211_add_key,
1877 .get_key = ath6kl_cfg80211_get_key,
1878 .del_key = ath6kl_cfg80211_del_key,
1879 .set_default_key = ath6kl_cfg80211_set_default_key,
1880 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1881 .set_tx_power = ath6kl_cfg80211_set_txpower,
1882 .get_tx_power = ath6kl_cfg80211_get_txpower,
1883 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1884 .join_ibss = ath6kl_cfg80211_join_ibss,
1885 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1886 .get_station = ath6kl_get_station,
1887 .set_pmksa = ath6kl_set_pmksa,
1888 .del_pmksa = ath6kl_del_pmksa,
1889 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001890 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001891#ifdef CONFIG_PM
1892 .suspend = ar6k_cfg80211_suspend,
1893#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001894 .set_channel = ath6kl_set_channel,
1895 .add_beacon = ath6kl_add_beacon,
1896 .set_beacon = ath6kl_set_beacon,
1897 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001898 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001899 .remain_on_channel = ath6kl_remain_on_channel,
1900 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001901 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001902 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001903};
1904
1905struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1906{
1907 int ret = 0;
1908 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001909 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001910
1911 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1912 if (!wdev) {
1913 ath6kl_err("couldn't allocate wireless device\n");
1914 return NULL;
1915 }
1916
1917 /* create a new wiphy for use with cfg80211 */
1918 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1919 if (!wdev->wiphy) {
1920 ath6kl_err("couldn't allocate wiphy device\n");
1921 kfree(wdev);
1922 return NULL;
1923 }
1924
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001925 ar = wiphy_priv(wdev->wiphy);
1926 ar->p2p = !!ath6kl_p2p;
1927
Jouni Malinenf80574a2011-08-30 21:58:04 +03001928 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1929
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001930 wdev->wiphy->max_remain_on_channel_duration = 5000;
1931
Kalle Valobdcd8172011-07-18 00:22:30 +03001932 /* set device pointer for wiphy */
1933 set_wiphy_dev(wdev->wiphy, dev);
1934
1935 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001936 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001937 if (ar->p2p) {
1938 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1939 BIT(NL80211_IFTYPE_P2P_CLIENT);
1940 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001941 /* max num of ssids that can be probed during scanning */
1942 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001943 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001944 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1945 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1946 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1947
1948 wdev->wiphy->cipher_suites = cipher_suites;
1949 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1950
1951 ret = wiphy_register(wdev->wiphy);
1952 if (ret < 0) {
1953 ath6kl_err("couldn't register wiphy device\n");
1954 wiphy_free(wdev->wiphy);
1955 kfree(wdev);
1956 return NULL;
1957 }
1958
1959 return wdev;
1960}
1961
1962void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1963{
1964 struct wireless_dev *wdev = ar->wdev;
1965
1966 if (ar->scan_req) {
1967 cfg80211_scan_done(ar->scan_req, true);
1968 ar->scan_req = NULL;
1969 }
1970
1971 if (!wdev)
1972 return;
1973
1974 wiphy_unregister(wdev->wiphy);
1975 wiphy_free(wdev->wiphy);
1976 kfree(wdev);
1977}