blob: c3540bbfcac638386f6fbf1f41ed77870cdee613 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
24
25module_param(ath6kl_p2p, uint, 0644);
26
Kalle Valobdcd8172011-07-18 00:22:30 +030027#define RATETAB_ENT(_rate, _rateid, _flags) { \
28 .bitrate = (_rate), \
29 .flags = (_flags), \
30 .hw_value = (_rateid), \
31}
32
33#define CHAN2G(_channel, _freq, _flags) { \
34 .band = IEEE80211_BAND_2GHZ, \
35 .hw_value = (_channel), \
36 .center_freq = (_freq), \
37 .flags = (_flags), \
38 .max_antenna_gain = 0, \
39 .max_power = 30, \
40}
41
42#define CHAN5G(_channel, _flags) { \
43 .band = IEEE80211_BAND_5GHZ, \
44 .hw_value = (_channel), \
45 .center_freq = 5000 + (5 * (_channel)), \
46 .flags = (_flags), \
47 .max_antenna_gain = 0, \
48 .max_power = 30, \
49}
50
51static struct ieee80211_rate ath6kl_rates[] = {
52 RATETAB_ENT(10, 0x1, 0),
53 RATETAB_ENT(20, 0x2, 0),
54 RATETAB_ENT(55, 0x4, 0),
55 RATETAB_ENT(110, 0x8, 0),
56 RATETAB_ENT(60, 0x10, 0),
57 RATETAB_ENT(90, 0x20, 0),
58 RATETAB_ENT(120, 0x40, 0),
59 RATETAB_ENT(180, 0x80, 0),
60 RATETAB_ENT(240, 0x100, 0),
61 RATETAB_ENT(360, 0x200, 0),
62 RATETAB_ENT(480, 0x400, 0),
63 RATETAB_ENT(540, 0x800, 0),
64};
65
66#define ath6kl_a_rates (ath6kl_rates + 4)
67#define ath6kl_a_rates_size 8
68#define ath6kl_g_rates (ath6kl_rates + 0)
69#define ath6kl_g_rates_size 12
70
71static struct ieee80211_channel ath6kl_2ghz_channels[] = {
72 CHAN2G(1, 2412, 0),
73 CHAN2G(2, 2417, 0),
74 CHAN2G(3, 2422, 0),
75 CHAN2G(4, 2427, 0),
76 CHAN2G(5, 2432, 0),
77 CHAN2G(6, 2437, 0),
78 CHAN2G(7, 2442, 0),
79 CHAN2G(8, 2447, 0),
80 CHAN2G(9, 2452, 0),
81 CHAN2G(10, 2457, 0),
82 CHAN2G(11, 2462, 0),
83 CHAN2G(12, 2467, 0),
84 CHAN2G(13, 2472, 0),
85 CHAN2G(14, 2484, 0),
86};
87
88static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
89 CHAN5G(34, 0), CHAN5G(36, 0),
90 CHAN5G(38, 0), CHAN5G(40, 0),
91 CHAN5G(42, 0), CHAN5G(44, 0),
92 CHAN5G(46, 0), CHAN5G(48, 0),
93 CHAN5G(52, 0), CHAN5G(56, 0),
94 CHAN5G(60, 0), CHAN5G(64, 0),
95 CHAN5G(100, 0), CHAN5G(104, 0),
96 CHAN5G(108, 0), CHAN5G(112, 0),
97 CHAN5G(116, 0), CHAN5G(120, 0),
98 CHAN5G(124, 0), CHAN5G(128, 0),
99 CHAN5G(132, 0), CHAN5G(136, 0),
100 CHAN5G(140, 0), CHAN5G(149, 0),
101 CHAN5G(153, 0), CHAN5G(157, 0),
102 CHAN5G(161, 0), CHAN5G(165, 0),
103 CHAN5G(184, 0), CHAN5G(188, 0),
104 CHAN5G(192, 0), CHAN5G(196, 0),
105 CHAN5G(200, 0), CHAN5G(204, 0),
106 CHAN5G(208, 0), CHAN5G(212, 0),
107 CHAN5G(216, 0),
108};
109
110static struct ieee80211_supported_band ath6kl_band_2ghz = {
111 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
112 .channels = ath6kl_2ghz_channels,
113 .n_bitrates = ath6kl_g_rates_size,
114 .bitrates = ath6kl_g_rates,
115};
116
117static struct ieee80211_supported_band ath6kl_band_5ghz = {
118 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
119 .channels = ath6kl_5ghz_a_channels,
120 .n_bitrates = ath6kl_a_rates_size,
121 .bitrates = ath6kl_a_rates,
122};
123
124static int ath6kl_set_wpa_version(struct ath6kl *ar,
125 enum nl80211_wpa_versions wpa_version)
126{
127 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
128
129 if (!wpa_version) {
130 ar->auth_mode = NONE_AUTH;
131 } else if (wpa_version & NL80211_WPA_VERSION_2) {
132 ar->auth_mode = WPA2_AUTH;
133 } else if (wpa_version & NL80211_WPA_VERSION_1) {
134 ar->auth_mode = WPA_AUTH;
135 } else {
136 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
137 return -ENOTSUPP;
138 }
139
140 return 0;
141}
142
143static int ath6kl_set_auth_type(struct ath6kl *ar,
144 enum nl80211_auth_type auth_type)
145{
146
147 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
148
149 switch (auth_type) {
150 case NL80211_AUTHTYPE_OPEN_SYSTEM:
151 ar->dot11_auth_mode = OPEN_AUTH;
152 break;
153 case NL80211_AUTHTYPE_SHARED_KEY:
154 ar->dot11_auth_mode = SHARED_AUTH;
155 break;
156 case NL80211_AUTHTYPE_NETWORK_EAP:
157 ar->dot11_auth_mode = LEAP_AUTH;
158 break;
159
160 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530161 ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300162 break;
163
164 default:
165 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
166 return -ENOTSUPP;
167 }
168
169 return 0;
170}
171
172static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
173{
174 u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
Edward Lu38acde32011-08-30 21:58:06 +0300175 u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
176 &ar->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300177
178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
179 __func__, cipher, ucast);
180
181 switch (cipher) {
182 case 0:
183 /* our own hack to use value 0 as no crypto used */
184 *ar_cipher = NONE_CRYPT;
185 *ar_cipher_len = 0;
186 break;
187 case WLAN_CIPHER_SUITE_WEP40:
188 *ar_cipher = WEP_CRYPT;
189 *ar_cipher_len = 5;
190 break;
191 case WLAN_CIPHER_SUITE_WEP104:
192 *ar_cipher = WEP_CRYPT;
193 *ar_cipher_len = 13;
194 break;
195 case WLAN_CIPHER_SUITE_TKIP:
196 *ar_cipher = TKIP_CRYPT;
197 *ar_cipher_len = 0;
198 break;
199 case WLAN_CIPHER_SUITE_CCMP:
200 *ar_cipher = AES_CRYPT;
201 *ar_cipher_len = 0;
202 break;
203 default:
204 ath6kl_err("cipher 0x%x not supported\n", cipher);
205 return -ENOTSUPP;
206 }
207
208 return 0;
209}
210
211static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
212{
213 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
214
215 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
216 if (ar->auth_mode == WPA_AUTH)
217 ar->auth_mode = WPA_PSK_AUTH;
218 else if (ar->auth_mode == WPA2_AUTH)
219 ar->auth_mode = WPA2_PSK_AUTH;
220 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
221 ar->auth_mode = NONE_AUTH;
222 }
223}
224
225static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
226{
227 if (!test_bit(WMI_READY, &ar->flag)) {
228 ath6kl_err("wmi is not ready\n");
229 return false;
230 }
231
Raja Mani575b5f32011-07-19 19:27:33 +0530232 if (!test_bit(WLAN_ENABLED, &ar->flag)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300233 ath6kl_err("wlan disabled\n");
234 return false;
235 }
236
237 return true;
238}
239
240static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
241 struct cfg80211_connect_params *sme)
242{
243 struct ath6kl *ar = ath6kl_priv(dev);
244 int status;
245
246 ar->sme_state = SME_CONNECTING;
247
248 if (!ath6kl_cfg80211_ready(ar))
249 return -EIO;
250
251 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
252 ath6kl_err("destroy in progress\n");
253 return -EBUSY;
254 }
255
256 if (test_bit(SKIP_SCAN, &ar->flag) &&
257 ((sme->channel && sme->channel->center_freq == 0) ||
258 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
259 ath6kl_err("SkipScan: channel or bssid invalid\n");
260 return -EINVAL;
261 }
262
263 if (down_interruptible(&ar->sem)) {
264 ath6kl_err("busy, couldn't get access\n");
265 return -ERESTARTSYS;
266 }
267
268 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
269 ath6kl_err("busy, destroy in progress\n");
270 up(&ar->sem);
271 return -EBUSY;
272 }
273
274 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
275 /*
276 * sleep until the command queue drains
277 */
278 wait_event_interruptible_timeout(ar->event_wq,
279 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
280 WMI_TIMEOUT);
281 if (signal_pending(current)) {
282 ath6kl_err("cmd queue drain timeout\n");
283 up(&ar->sem);
284 return -EINTR;
285 }
286 }
287
288 if (test_bit(CONNECTED, &ar->flag) &&
289 ar->ssid_len == sme->ssid_len &&
290 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
291 ar->reconnect_flag = true;
292 status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
293 ar->ch_hint);
294
295 up(&ar->sem);
296 if (status) {
297 ath6kl_err("wmi_reconnect_cmd failed\n");
298 return -EIO;
299 }
300 return 0;
301 } else if (ar->ssid_len == sme->ssid_len &&
302 !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
303 ath6kl_disconnect(ar);
304 }
305
306 memset(ar->ssid, 0, sizeof(ar->ssid));
307 ar->ssid_len = sme->ssid_len;
308 memcpy(ar->ssid, sme->ssid, sme->ssid_len);
309
310 if (sme->channel)
311 ar->ch_hint = sme->channel->center_freq;
312
313 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
314 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
315 memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
316
317 ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
318
319 status = ath6kl_set_auth_type(ar, sme->auth_type);
320 if (status) {
321 up(&ar->sem);
322 return status;
323 }
324
325 if (sme->crypto.n_ciphers_pairwise)
326 ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
327 else
328 ath6kl_set_cipher(ar, 0, true);
329
330 ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
331
332 if (sme->crypto.n_akm_suites)
333 ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
334
335 if ((sme->key_len) &&
336 (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
337 struct ath6kl_key *key = NULL;
338
339 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
340 sme->key_idx > WMI_MAX_KEY_INDEX) {
341 ath6kl_err("key index %d out of bounds\n",
342 sme->key_idx);
343 up(&ar->sem);
344 return -ENOENT;
345 }
346
347 key = &ar->keys[sme->key_idx];
348 key->key_len = sme->key_len;
349 memcpy(key->key, sme->key, key->key_len);
350 key->cipher = ar->prwise_crypto;
351 ar->def_txkey_index = sme->key_idx;
352
353 ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
354 ar->prwise_crypto,
355 GROUP_USAGE | TX_USAGE,
356 key->key_len,
357 NULL,
358 key->key, KEY_OP_INIT_VAL, NULL,
359 NO_SYNC_WMIFLAG);
360 }
361
362 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300363 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300364 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
365 ath6kl_err("couldn't set bss filtering\n");
366 up(&ar->sem);
367 return -EIO;
368 }
369 }
370
371 ar->nw_type = ar->next_mode;
372
373 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
374 "%s: connect called with authmode %d dot11 auth %d"
375 " PW crypto %d PW crypto len %d GRP crypto %d"
376 " GRP crypto len %d channel hint %u\n",
377 __func__,
378 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
379 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +0300380 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300381
382 ar->reconnect_flag = 0;
383 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
384 ar->dot11_auth_mode, ar->auth_mode,
385 ar->prwise_crypto,
386 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +0300387 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +0300388 ar->ssid_len, ar->ssid,
389 ar->req_bssid, ar->ch_hint,
390 ar->connect_ctrl_flags);
391
392 up(&ar->sem);
393
394 if (status == -EINVAL) {
395 memset(ar->ssid, 0, sizeof(ar->ssid));
396 ar->ssid_len = 0;
397 ath6kl_err("invalid request\n");
398 return -ENOENT;
399 } else if (status) {
400 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
401 return -EIO;
402 }
403
404 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
405 ((ar->auth_mode == WPA_PSK_AUTH)
406 || (ar->auth_mode == WPA2_PSK_AUTH))) {
407 mod_timer(&ar->disconnect_timer,
408 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
409 }
410
411 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
412 set_bit(CONNECT_PEND, &ar->flag);
413
414 return 0;
415}
416
Jouni Malinen01cac472011-09-19 19:14:59 +0300417static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
418 struct ieee80211_channel *chan,
419 const u8 *beacon_ie, size_t beacon_ie_len)
420{
421 struct cfg80211_bss *bss;
422 u8 *ie;
423
424 bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid,
425 ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
426 WLAN_CAPABILITY_ESS);
427 if (bss == NULL) {
428 /*
429 * Since cfg80211 may not yet know about the BSS,
430 * generate a partial entry until the first BSS info
431 * event becomes available.
432 *
433 * Prepend SSID element since it is not included in the Beacon
434 * IEs from the target.
435 */
436 ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
437 if (ie == NULL)
438 return -ENOMEM;
439 ie[0] = WLAN_EID_SSID;
440 ie[1] = ar->ssid_len;
441 memcpy(ie + 2, ar->ssid, ar->ssid_len);
442 memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
443 bss = cfg80211_inform_bss(ar->wdev->wiphy, chan,
444 bssid, 0, WLAN_CAPABILITY_ESS, 100,
445 ie, 2 + ar->ssid_len + beacon_ie_len,
446 0, GFP_KERNEL);
447 if (bss)
448 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
449 "%pM prior to indicating connect/roamed "
450 "event\n", bssid);
451 kfree(ie);
452 } else
453 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
454 "entry\n");
455
456 if (bss == NULL)
457 return -ENOMEM;
458
459 cfg80211_put_bss(bss);
460
461 return 0;
462}
463
Kalle Valobdcd8172011-07-18 00:22:30 +0300464void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
465 u8 *bssid, u16 listen_intvl,
466 u16 beacon_intvl,
467 enum network_type nw_type,
468 u8 beacon_ie_len, u8 assoc_req_len,
469 u8 assoc_resp_len, u8 *assoc_info)
470{
Jouni Malinen01cac472011-09-19 19:14:59 +0300471 struct ieee80211_channel *chan;
Kalle Valobdcd8172011-07-18 00:22:30 +0300472
473 /* capinfo + listen interval */
474 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
475
476 /* capinfo + status code + associd */
477 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
478
479 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
480 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
481 assoc_resp_ie_offset;
482
483 assoc_req_len -= assoc_req_ie_offset;
484 assoc_resp_len -= assoc_resp_ie_offset;
485
Jouni Malinen32c10872011-09-19 19:15:07 +0300486 /*
487 * Store Beacon interval here; DTIM period will be available only once
488 * a Beacon frame from the AP is seen.
489 */
490 ar->assoc_bss_beacon_int = beacon_intvl;
491 clear_bit(DTIM_PERIOD_AVAIL, &ar->flag);
492
Kalle Valobdcd8172011-07-18 00:22:30 +0300493 if (nw_type & ADHOC_NETWORK) {
494 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
495 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
496 "%s: ath6k not in ibss mode\n", __func__);
497 return;
498 }
499 }
500
501 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300502 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
503 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300504 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
505 "%s: ath6k not in station mode\n", __func__);
506 return;
507 }
508 }
509
Jouni Malinen01cac472011-09-19 19:14:59 +0300510 chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300511
Kalle Valobdcd8172011-07-18 00:22:30 +0300512
513 if (nw_type & ADHOC_NETWORK) {
514 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
515 return;
516 }
517
Jouni Malinen01cac472011-09-19 19:14:59 +0300518 if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
519 beacon_ie_len) < 0) {
520 ath6kl_err("could not add cfg80211 bss entry for "
521 "connect/roamed notification\n");
522 return;
523 }
524
Raja Mani9aa60352011-08-04 19:26:29 +0530525 if (ar->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300526 /* inform connect result to cfg80211 */
Raja Mani9aa60352011-08-04 19:26:29 +0530527 ar->sme_state = SME_CONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300528 cfg80211_connect_result(ar->net_dev, bssid,
529 assoc_req_ie, assoc_req_len,
530 assoc_resp_ie, assoc_resp_len,
531 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Raja Mani9aa60352011-08-04 19:26:29 +0530532 } else if (ar->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300533 /* inform roam event to cfg80211 */
Jouni Malinen01cac472011-09-19 19:14:59 +0300534 cfg80211_roamed(ar->net_dev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300535 assoc_req_ie, assoc_req_len,
536 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
537 }
538}
539
540static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
541 struct net_device *dev, u16 reason_code)
542{
543 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
544
545 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
546 reason_code);
547
548 if (!ath6kl_cfg80211_ready(ar))
549 return -EIO;
550
551 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
552 ath6kl_err("busy, destroy in progress\n");
553 return -EBUSY;
554 }
555
556 if (down_interruptible(&ar->sem)) {
557 ath6kl_err("busy, couldn't get access\n");
558 return -ERESTARTSYS;
559 }
560
561 ar->reconnect_flag = 0;
562 ath6kl_disconnect(ar);
563 memset(ar->ssid, 0, sizeof(ar->ssid));
564 ar->ssid_len = 0;
565
566 if (!test_bit(SKIP_SCAN, &ar->flag))
567 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
568
569 up(&ar->sem);
570
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530571 ar->sme_state = SME_DISCONNECTED;
572
Kalle Valobdcd8172011-07-18 00:22:30 +0300573 return 0;
574}
575
576void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
577 u8 *bssid, u8 assoc_resp_len,
578 u8 *assoc_info, u16 proto_reason)
579{
Kalle Valobdcd8172011-07-18 00:22:30 +0300580 if (ar->scan_req) {
581 cfg80211_scan_done(ar->scan_req, true);
582 ar->scan_req = NULL;
583 }
584
585 if (ar->nw_type & ADHOC_NETWORK) {
586 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
587 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
588 "%s: ath6k not in ibss mode\n", __func__);
589 return;
590 }
591 memset(bssid, 0, ETH_ALEN);
592 cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
593 return;
594 }
595
596 if (ar->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300597 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
598 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300599 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
600 "%s: ath6k not in station mode\n", __func__);
601 return;
602 }
603 }
604
605 if (!test_bit(CONNECT_PEND, &ar->flag)) {
606 if (reason != DISCONNECT_CMD)
607 ath6kl_wmi_disconnect_cmd(ar->wmi);
608
609 return;
610 }
611
612 if (reason == NO_NETWORK_AVAIL) {
613 /* connect cmd failed */
614 ath6kl_wmi_disconnect_cmd(ar->wmi);
615 return;
616 }
617
618 if (reason != DISCONNECT_CMD)
619 return;
620
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530621 clear_bit(CONNECT_PEND, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300622
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530623 if (ar->sme_state == SME_CONNECTING) {
624 cfg80211_connect_result(ar->net_dev,
625 bssid, NULL, 0,
626 NULL, 0,
627 WLAN_STATUS_UNSPECIFIED_FAILURE,
628 GFP_KERNEL);
629 } else if (ar->sme_state == SME_CONNECTED) {
630 cfg80211_disconnected(ar->net_dev, reason,
631 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300632 }
633
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530634 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300635}
636
Kalle Valobdcd8172011-07-18 00:22:30 +0300637static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
638 struct cfg80211_scan_request *request)
639{
640 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300641 s8 n_channels = 0;
642 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300643 int ret = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300644
645 if (!ath6kl_cfg80211_ready(ar))
646 return -EIO;
647
648 if (!ar->usr_bss_filter) {
Jouni Malinen551185c2011-09-19 19:15:06 +0300649 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300650 ret = ath6kl_wmi_bssfilter_cmd(
651 ar->wmi,
652 (test_bit(CONNECTED, &ar->flag) ?
653 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
654 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300655 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300656 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300657 }
658 }
659
660 if (request->n_ssids && request->ssids[0].ssid_len) {
661 u8 i;
662
663 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
664 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
665
666 for (i = 0; i < request->n_ssids; i++)
667 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
668 SPECIFIC_SSID_FLAG,
669 request->ssids[i].ssid_len,
670 request->ssids[i].ssid);
671 }
672
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300673 if (request->ie) {
674 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
675 request->ie, request->ie_len);
676 if (ret) {
677 ath6kl_err("failed to set Probe Request appie for "
678 "scan");
679 return ret;
680 }
681 }
682
Jouni Malinen11869be2011-09-02 20:07:06 +0300683 /*
684 * Scan only the requested channels if the request specifies a set of
685 * channels. If the list is longer than the target supports, do not
686 * configure the list and instead, scan all available channels.
687 */
688 if (request->n_channels > 0 &&
689 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300690 u8 i;
691
Jouni Malinen11869be2011-09-02 20:07:06 +0300692 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300693
694 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
695 if (channels == NULL) {
696 ath6kl_warn("failed to set scan channels, "
697 "scan all channels");
698 n_channels = 0;
699 }
700
701 for (i = 0; i < n_channels; i++)
702 channels[i] = request->channels[i]->center_freq;
703 }
704
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300705 ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
706 false, 0, 0, n_channels, channels);
707 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300708 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300709 else
710 ar->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300711
Edward Lu1276c9e2011-08-30 21:58:00 +0300712 kfree(channels);
713
Kalle Valobdcd8172011-07-18 00:22:30 +0300714 return ret;
715}
716
717void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
718{
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300719 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300720
721 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
722
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300723 if (!ar->scan_req)
724 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300725
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300726 if ((status == -ECANCELED) || (status == -EBUSY)) {
727 cfg80211_scan_done(ar->scan_req, true);
728 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300729 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300730
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300731 cfg80211_scan_done(ar->scan_req, false);
732
733 if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
734 for (i = 0; i < ar->scan_req->n_ssids; i++) {
735 ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
736 DISABLE_SSID_FLAG,
737 0, NULL);
738 }
739 }
740
741out:
742 ar->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300743}
744
745static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
746 u8 key_index, bool pairwise,
747 const u8 *mac_addr,
748 struct key_params *params)
749{
750 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
751 struct ath6kl_key *key = NULL;
752 u8 key_usage;
753 u8 key_type;
754 int status = 0;
755
756 if (!ath6kl_cfg80211_ready(ar))
757 return -EIO;
758
759 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
760 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
761 "%s: key index %d out of bounds\n", __func__,
762 key_index);
763 return -ENOENT;
764 }
765
766 key = &ar->keys[key_index];
767 memset(key, 0, sizeof(struct ath6kl_key));
768
769 if (pairwise)
770 key_usage = PAIRWISE_USAGE;
771 else
772 key_usage = GROUP_USAGE;
773
774 if (params) {
775 if (params->key_len > WLAN_MAX_KEY_LEN ||
776 params->seq_len > sizeof(key->seq))
777 return -EINVAL;
778
779 key->key_len = params->key_len;
780 memcpy(key->key, params->key, key->key_len);
781 key->seq_len = params->seq_len;
782 memcpy(key->seq, params->seq, key->seq_len);
783 key->cipher = params->cipher;
784 }
785
786 switch (key->cipher) {
787 case WLAN_CIPHER_SUITE_WEP40:
788 case WLAN_CIPHER_SUITE_WEP104:
789 key_type = WEP_CRYPT;
790 break;
791
792 case WLAN_CIPHER_SUITE_TKIP:
793 key_type = TKIP_CRYPT;
794 break;
795
796 case WLAN_CIPHER_SUITE_CCMP:
797 key_type = AES_CRYPT;
798 break;
799
800 default:
801 return -ENOTSUPP;
802 }
803
804 if (((ar->auth_mode == WPA_PSK_AUTH)
805 || (ar->auth_mode == WPA2_PSK_AUTH))
806 && (key_usage & GROUP_USAGE))
807 del_timer(&ar->disconnect_timer);
808
809 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
810 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
811 __func__, key_index, key->key_len, key_type,
812 key_usage, key->seq_len);
813
814 ar->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300815
816 if (ar->nw_type == AP_NETWORK && !pairwise &&
817 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
818 ar->ap_mode_bkey.valid = true;
819 ar->ap_mode_bkey.key_index = key_index;
820 ar->ap_mode_bkey.key_type = key_type;
821 ar->ap_mode_bkey.key_len = key->key_len;
822 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
823 if (!test_bit(CONNECTED, &ar->flag)) {
824 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
825 "key configuration until AP mode has been "
826 "started\n");
827 /*
828 * The key will be set in ath6kl_connect_ap_mode() once
829 * the connected event is received from the target.
830 */
831 return 0;
832 }
833 }
834
Jouni Malinen151411e2011-09-15 15:10:16 +0300835 if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
836 !test_bit(CONNECTED, &ar->flag)) {
837 /*
838 * Store the key locally so that it can be re-configured after
839 * the AP mode has properly started
840 * (ath6kl_install_statioc_wep_keys).
841 */
842 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
843 "until AP mode has been started\n");
844 ar->wep_key_list[key_index].key_len = key->key_len;
845 memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
846 return 0;
847 }
848
Kalle Valobdcd8172011-07-18 00:22:30 +0300849 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
850 key_type, key_usage, key->key_len,
851 key->seq, key->key, KEY_OP_INIT_VAL,
852 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
853
854 if (status)
855 return -EIO;
856
857 return 0;
858}
859
860static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
861 u8 key_index, bool pairwise,
862 const u8 *mac_addr)
863{
864 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
865
866 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
867
868 if (!ath6kl_cfg80211_ready(ar))
869 return -EIO;
870
871 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
872 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
873 "%s: key index %d out of bounds\n", __func__,
874 key_index);
875 return -ENOENT;
876 }
877
878 if (!ar->keys[key_index].key_len) {
879 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
880 "%s: index %d is empty\n", __func__, key_index);
881 return 0;
882 }
883
884 ar->keys[key_index].key_len = 0;
885
886 return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
887}
888
889static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
890 u8 key_index, bool pairwise,
891 const u8 *mac_addr, void *cookie,
892 void (*callback) (void *cookie,
893 struct key_params *))
894{
895 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
896 struct ath6kl_key *key = NULL;
897 struct key_params params;
898
899 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
900
901 if (!ath6kl_cfg80211_ready(ar))
902 return -EIO;
903
904 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
905 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
906 "%s: key index %d out of bounds\n", __func__,
907 key_index);
908 return -ENOENT;
909 }
910
911 key = &ar->keys[key_index];
912 memset(&params, 0, sizeof(params));
913 params.cipher = key->cipher;
914 params.key_len = key->key_len;
915 params.seq_len = key->seq_len;
916 params.seq = key->seq;
917 params.key = key->key;
918
919 callback(cookie, &params);
920
921 return key->key_len ? 0 : -ENOENT;
922}
923
924static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
925 struct net_device *ndev,
926 u8 key_index, bool unicast,
927 bool multicast)
928{
929 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
930 struct ath6kl_key *key = NULL;
931 int status = 0;
932 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +0300933 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +0300934
935 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
936
937 if (!ath6kl_cfg80211_ready(ar))
938 return -EIO;
939
940 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
941 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
942 "%s: key index %d out of bounds\n",
943 __func__, key_index);
944 return -ENOENT;
945 }
946
947 if (!ar->keys[key_index].key_len) {
948 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
949 __func__, key_index);
950 return -EINVAL;
951 }
952
953 ar->def_txkey_index = key_index;
954 key = &ar->keys[ar->def_txkey_index];
955 key_usage = GROUP_USAGE;
956 if (ar->prwise_crypto == WEP_CRYPT)
957 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +0300958 if (unicast)
959 key_type = ar->prwise_crypto;
960 if (multicast)
961 key_type = ar->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +0300962
Jouni Malinen151411e2011-09-15 15:10:16 +0300963 if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300964 return 0; /* Delay until AP mode has been started */
965
Kalle Valobdcd8172011-07-18 00:22:30 +0300966 status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +0300967 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +0300968 key->key_len, key->seq, key->key,
969 KEY_OP_INIT_VAL, NULL,
970 SYNC_BOTH_WMIFLAG);
971 if (status)
972 return -EIO;
973
974 return 0;
975}
976
977void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
978 bool ismcast)
979{
980 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
981 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
982
983 cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
984 (ismcast ? NL80211_KEYTYPE_GROUP :
985 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
986 GFP_KERNEL);
987}
988
989static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
990{
991 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
992 int ret;
993
994 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
995 changed);
996
997 if (!ath6kl_cfg80211_ready(ar))
998 return -EIO;
999
1000 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1001 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1002 if (ret != 0) {
1003 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1004 return -EIO;
1005 }
1006 }
1007
1008 return 0;
1009}
1010
1011/*
1012 * The type nl80211_tx_power_setting replaces the following
1013 * data type from 2.6.36 onwards
1014*/
1015static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1016 enum nl80211_tx_power_setting type,
1017 int dbm)
1018{
1019 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1020 u8 ath6kl_dbm;
1021
1022 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1023 type, dbm);
1024
1025 if (!ath6kl_cfg80211_ready(ar))
1026 return -EIO;
1027
1028 switch (type) {
1029 case NL80211_TX_POWER_AUTOMATIC:
1030 return 0;
1031 case NL80211_TX_POWER_LIMITED:
1032 ar->tx_pwr = ath6kl_dbm = dbm;
1033 break;
1034 default:
1035 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1036 __func__, type);
1037 return -EOPNOTSUPP;
1038 }
1039
1040 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1041
1042 return 0;
1043}
1044
1045static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1046{
1047 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1048
1049 if (!ath6kl_cfg80211_ready(ar))
1050 return -EIO;
1051
1052 if (test_bit(CONNECTED, &ar->flag)) {
1053 ar->tx_pwr = 0;
1054
1055 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1056 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1057 return -EIO;
1058 }
1059
1060 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1061 5 * HZ);
1062
1063 if (signal_pending(current)) {
1064 ath6kl_err("target did not respond\n");
1065 return -EINTR;
1066 }
1067 }
1068
1069 *dbm = ar->tx_pwr;
1070 return 0;
1071}
1072
1073static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1074 struct net_device *dev,
1075 bool pmgmt, int timeout)
1076{
1077 struct ath6kl *ar = ath6kl_priv(dev);
1078 struct wmi_power_mode_cmd mode;
1079
1080 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1081 __func__, pmgmt, timeout);
1082
1083 if (!ath6kl_cfg80211_ready(ar))
1084 return -EIO;
1085
1086 if (pmgmt) {
1087 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1088 mode.pwr_mode = REC_POWER;
1089 } else {
1090 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1091 mode.pwr_mode = MAX_PERF_POWER;
1092 }
1093
1094 if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
1095 ath6kl_err("wmi_powermode_cmd failed\n");
1096 return -EIO;
1097 }
1098
1099 return 0;
1100}
1101
1102static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1103 struct net_device *ndev,
1104 enum nl80211_iftype type, u32 *flags,
1105 struct vif_params *params)
1106{
1107 struct ath6kl *ar = ath6kl_priv(ndev);
1108 struct wireless_dev *wdev = ar->wdev;
1109
1110 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1111
1112 if (!ath6kl_cfg80211_ready(ar))
1113 return -EIO;
1114
1115 switch (type) {
1116 case NL80211_IFTYPE_STATION:
1117 ar->next_mode = INFRA_NETWORK;
1118 break;
1119 case NL80211_IFTYPE_ADHOC:
1120 ar->next_mode = ADHOC_NETWORK;
1121 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001122 case NL80211_IFTYPE_AP:
1123 ar->next_mode = AP_NETWORK;
1124 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001125 case NL80211_IFTYPE_P2P_CLIENT:
1126 ar->next_mode = INFRA_NETWORK;
1127 break;
1128 case NL80211_IFTYPE_P2P_GO:
1129 ar->next_mode = AP_NETWORK;
1130 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001131 default:
1132 ath6kl_err("invalid interface type %u\n", type);
1133 return -EOPNOTSUPP;
1134 }
1135
1136 wdev->iftype = type;
1137
1138 return 0;
1139}
1140
1141static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1142 struct net_device *dev,
1143 struct cfg80211_ibss_params *ibss_param)
1144{
1145 struct ath6kl *ar = ath6kl_priv(dev);
1146 int status;
1147
1148 if (!ath6kl_cfg80211_ready(ar))
1149 return -EIO;
1150
1151 ar->ssid_len = ibss_param->ssid_len;
1152 memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
1153
1154 if (ibss_param->channel)
1155 ar->ch_hint = ibss_param->channel->center_freq;
1156
1157 if (ibss_param->channel_fixed) {
1158 /*
1159 * TODO: channel_fixed: The channel should be fixed, do not
1160 * search for IBSSs to join on other channels. Target
1161 * firmware does not support this feature, needs to be
1162 * updated.
1163 */
1164 return -EOPNOTSUPP;
1165 }
1166
1167 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
1168 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
1169 memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
1170
1171 ath6kl_set_wpa_version(ar, 0);
1172
1173 status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
1174 if (status)
1175 return status;
1176
1177 if (ibss_param->privacy) {
1178 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
1179 ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
1180 } else {
1181 ath6kl_set_cipher(ar, 0, true);
1182 ath6kl_set_cipher(ar, 0, false);
1183 }
1184
1185 ar->nw_type = ar->next_mode;
1186
1187 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1188 "%s: connect called with authmode %d dot11 auth %d"
1189 " PW crypto %d PW crypto len %d GRP crypto %d"
1190 " GRP crypto len %d channel hint %u\n",
1191 __func__,
1192 ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
1193 ar->prwise_crypto_len, ar->grp_crypto,
Edward Lu38acde32011-08-30 21:58:06 +03001194 ar->grp_crypto_len, ar->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001195
1196 status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
1197 ar->dot11_auth_mode, ar->auth_mode,
1198 ar->prwise_crypto,
1199 ar->prwise_crypto_len,
Edward Lu38acde32011-08-30 21:58:06 +03001200 ar->grp_crypto, ar->grp_crypto_len,
Kalle Valobdcd8172011-07-18 00:22:30 +03001201 ar->ssid_len, ar->ssid,
1202 ar->req_bssid, ar->ch_hint,
1203 ar->connect_ctrl_flags);
1204 set_bit(CONNECT_PEND, &ar->flag);
1205
1206 return 0;
1207}
1208
1209static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1210 struct net_device *dev)
1211{
1212 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
1213
1214 if (!ath6kl_cfg80211_ready(ar))
1215 return -EIO;
1216
1217 ath6kl_disconnect(ar);
1218 memset(ar->ssid, 0, sizeof(ar->ssid));
1219 ar->ssid_len = 0;
1220
1221 return 0;
1222}
1223
1224static const u32 cipher_suites[] = {
1225 WLAN_CIPHER_SUITE_WEP40,
1226 WLAN_CIPHER_SUITE_WEP104,
1227 WLAN_CIPHER_SUITE_TKIP,
1228 WLAN_CIPHER_SUITE_CCMP,
1229};
1230
1231static bool is_rate_legacy(s32 rate)
1232{
1233 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1234 6000, 9000, 12000, 18000, 24000,
1235 36000, 48000, 54000
1236 };
1237 u8 i;
1238
1239 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1240 if (rate == legacy[i])
1241 return true;
1242
1243 return false;
1244}
1245
1246static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1247{
1248 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1249 52000, 58500, 65000, 72200
1250 };
1251 u8 i;
1252
1253 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1254 if (rate == ht20[i]) {
1255 if (i == ARRAY_SIZE(ht20) - 1)
1256 /* last rate uses sgi */
1257 *sgi = true;
1258 else
1259 *sgi = false;
1260
1261 *mcs = i;
1262 return true;
1263 }
1264 }
1265 return false;
1266}
1267
1268static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1269{
1270 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1271 81000, 108000, 121500, 135000,
1272 150000
1273 };
1274 u8 i;
1275
1276 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1277 if (rate == ht40[i]) {
1278 if (i == ARRAY_SIZE(ht40) - 1)
1279 /* last rate uses sgi */
1280 *sgi = true;
1281 else
1282 *sgi = false;
1283
1284 *mcs = i;
1285 return true;
1286 }
1287 }
1288
1289 return false;
1290}
1291
1292static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1293 u8 *mac, struct station_info *sinfo)
1294{
1295 struct ath6kl *ar = ath6kl_priv(dev);
1296 long left;
1297 bool sgi;
1298 s32 rate;
1299 int ret;
1300 u8 mcs;
1301
1302 if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
1303 return -ENOENT;
1304
1305 if (down_interruptible(&ar->sem))
1306 return -EBUSY;
1307
1308 set_bit(STATS_UPDATE_PEND, &ar->flag);
1309
1310 ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
1311
1312 if (ret != 0) {
1313 up(&ar->sem);
1314 return -EIO;
1315 }
1316
1317 left = wait_event_interruptible_timeout(ar->event_wq,
1318 !test_bit(STATS_UPDATE_PEND,
1319 &ar->flag),
1320 WMI_TIMEOUT);
1321
1322 up(&ar->sem);
1323
1324 if (left == 0)
1325 return -ETIMEDOUT;
1326 else if (left < 0)
1327 return left;
1328
1329 if (ar->target_stats.rx_byte) {
1330 sinfo->rx_bytes = ar->target_stats.rx_byte;
1331 sinfo->filled |= STATION_INFO_RX_BYTES;
1332 sinfo->rx_packets = ar->target_stats.rx_pkt;
1333 sinfo->filled |= STATION_INFO_RX_PACKETS;
1334 }
1335
1336 if (ar->target_stats.tx_byte) {
1337 sinfo->tx_bytes = ar->target_stats.tx_byte;
1338 sinfo->filled |= STATION_INFO_TX_BYTES;
1339 sinfo->tx_packets = ar->target_stats.tx_pkt;
1340 sinfo->filled |= STATION_INFO_TX_PACKETS;
1341 }
1342
1343 sinfo->signal = ar->target_stats.cs_rssi;
1344 sinfo->filled |= STATION_INFO_SIGNAL;
1345
1346 rate = ar->target_stats.tx_ucast_rate;
1347
1348 if (is_rate_legacy(rate)) {
1349 sinfo->txrate.legacy = rate / 100;
1350 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1351 if (sgi) {
1352 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1353 sinfo->txrate.mcs = mcs - 1;
1354 } else {
1355 sinfo->txrate.mcs = mcs;
1356 }
1357
1358 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1359 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1360 if (sgi) {
1361 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1362 sinfo->txrate.mcs = mcs - 1;
1363 } else {
1364 sinfo->txrate.mcs = mcs;
1365 }
1366
1367 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1368 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1369 } else {
1370 ath6kl_warn("invalid rate: %d\n", rate);
1371 return 0;
1372 }
1373
1374 sinfo->filled |= STATION_INFO_TX_BITRATE;
1375
Jouni Malinen32c10872011-09-19 19:15:07 +03001376 if (test_bit(CONNECTED, &ar->flag) &&
1377 test_bit(DTIM_PERIOD_AVAIL, &ar->flag) &&
1378 ar->nw_type == INFRA_NETWORK) {
1379 sinfo->filled |= STATION_INFO_BSS_PARAM;
1380 sinfo->bss_param.flags = 0;
1381 sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
1382 sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
1383 }
1384
Kalle Valobdcd8172011-07-18 00:22:30 +03001385 return 0;
1386}
1387
1388static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1389 struct cfg80211_pmksa *pmksa)
1390{
1391 struct ath6kl *ar = ath6kl_priv(netdev);
1392 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1393 pmksa->pmkid, true);
1394}
1395
1396static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1397 struct cfg80211_pmksa *pmksa)
1398{
1399 struct ath6kl *ar = ath6kl_priv(netdev);
1400 return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
1401 pmksa->pmkid, false);
1402}
1403
1404static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1405{
1406 struct ath6kl *ar = ath6kl_priv(netdev);
1407 if (test_bit(CONNECTED, &ar->flag))
1408 return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
1409 return 0;
1410}
1411
Kalle Valoabcb3442011-07-22 08:26:20 +03001412#ifdef CONFIG_PM
1413static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1414 struct cfg80211_wowlan *wow)
1415{
1416 struct ath6kl *ar = wiphy_priv(wiphy);
1417
1418 return ath6kl_hif_suspend(ar);
1419}
1420#endif
1421
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001422static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1423 struct ieee80211_channel *chan,
1424 enum nl80211_channel_type channel_type)
1425{
1426 struct ath6kl *ar = ath6kl_priv(dev);
1427
1428 if (!ath6kl_cfg80211_ready(ar))
1429 return -EIO;
1430
1431 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1432 __func__, chan->center_freq, chan->hw_value);
1433 ar->next_chan = chan->center_freq;
1434
1435 return 0;
1436}
1437
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001438static bool ath6kl_is_p2p_ie(const u8 *pos)
1439{
1440 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1441 pos[2] == 0x50 && pos[3] == 0x6f &&
1442 pos[4] == 0x9a && pos[5] == 0x09;
1443}
1444
1445static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
1446 size_t ies_len)
1447{
1448 const u8 *pos;
1449 u8 *buf = NULL;
1450 size_t len = 0;
1451 int ret;
1452
1453 /*
1454 * Filter out P2P IE(s) since they will be included depending on
1455 * the Probe Request frame in ath6kl_send_go_probe_resp().
1456 */
1457
1458 if (ies && ies_len) {
1459 buf = kmalloc(ies_len, GFP_KERNEL);
1460 if (buf == NULL)
1461 return -ENOMEM;
1462 pos = ies;
1463 while (pos + 1 < ies + ies_len) {
1464 if (pos + 2 + pos[1] > ies + ies_len)
1465 break;
1466 if (!ath6kl_is_p2p_ie(pos)) {
1467 memcpy(buf + len, pos, 2 + pos[1]);
1468 len += 2 + pos[1];
1469 }
1470 pos += 2 + pos[1];
1471 }
1472 }
1473
1474 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
1475 buf, len);
1476 kfree(buf);
1477 return ret;
1478}
1479
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001480static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1481 struct beacon_parameters *info, bool add)
1482{
1483 struct ath6kl *ar = ath6kl_priv(dev);
1484 struct ieee80211_mgmt *mgmt;
1485 u8 *ies;
1486 int ies_len;
1487 struct wmi_connect_cmd p;
1488 int res;
1489 int i;
1490
1491 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1492
1493 if (!ath6kl_cfg80211_ready(ar))
1494 return -EIO;
1495
1496 if (ar->next_mode != AP_NETWORK)
1497 return -EOPNOTSUPP;
1498
1499 if (info->beacon_ies) {
1500 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
1501 info->beacon_ies,
1502 info->beacon_ies_len);
1503 if (res)
1504 return res;
1505 }
1506 if (info->proberesp_ies) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001507 res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
1508 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001509 if (res)
1510 return res;
1511 }
1512 if (info->assocresp_ies) {
1513 res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
1514 info->assocresp_ies,
1515 info->assocresp_ies_len);
1516 if (res)
1517 return res;
1518 }
1519
1520 if (!add)
1521 return 0;
1522
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001523 ar->ap_mode_bkey.valid = false;
1524
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001525 /* TODO:
1526 * info->interval
1527 * info->dtim_period
1528 */
1529
1530 if (info->head == NULL)
1531 return -EINVAL;
1532 mgmt = (struct ieee80211_mgmt *) info->head;
1533 ies = mgmt->u.beacon.variable;
1534 if (ies > info->head + info->head_len)
1535 return -EINVAL;
1536 ies_len = info->head + info->head_len - ies;
1537
1538 if (info->ssid == NULL)
1539 return -EINVAL;
1540 memcpy(ar->ssid, info->ssid, info->ssid_len);
1541 ar->ssid_len = info->ssid_len;
1542 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1543 return -EOPNOTSUPP; /* TODO */
1544
1545 ar->dot11_auth_mode = OPEN_AUTH;
1546
1547 memset(&p, 0, sizeof(p));
1548
1549 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1550 switch (info->crypto.akm_suites[i]) {
1551 case WLAN_AKM_SUITE_8021X:
1552 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1553 p.auth_mode |= WPA_AUTH;
1554 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1555 p.auth_mode |= WPA2_AUTH;
1556 break;
1557 case WLAN_AKM_SUITE_PSK:
1558 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1559 p.auth_mode |= WPA_PSK_AUTH;
1560 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1561 p.auth_mode |= WPA2_PSK_AUTH;
1562 break;
1563 }
1564 }
1565 if (p.auth_mode == 0)
1566 p.auth_mode = NONE_AUTH;
1567 ar->auth_mode = p.auth_mode;
1568
1569 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1570 switch (info->crypto.ciphers_pairwise[i]) {
1571 case WLAN_CIPHER_SUITE_WEP40:
1572 case WLAN_CIPHER_SUITE_WEP104:
1573 p.prwise_crypto_type |= WEP_CRYPT;
1574 break;
1575 case WLAN_CIPHER_SUITE_TKIP:
1576 p.prwise_crypto_type |= TKIP_CRYPT;
1577 break;
1578 case WLAN_CIPHER_SUITE_CCMP:
1579 p.prwise_crypto_type |= AES_CRYPT;
1580 break;
1581 }
1582 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001583 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001584 p.prwise_crypto_type = NONE_CRYPT;
Edward Lu229ed6b2011-08-30 21:58:07 +03001585 ath6kl_set_cipher(ar, 0, true);
1586 } else if (info->crypto.n_ciphers_pairwise == 1)
1587 ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001588
1589 switch (info->crypto.cipher_group) {
1590 case WLAN_CIPHER_SUITE_WEP40:
1591 case WLAN_CIPHER_SUITE_WEP104:
1592 p.grp_crypto_type = WEP_CRYPT;
1593 break;
1594 case WLAN_CIPHER_SUITE_TKIP:
1595 p.grp_crypto_type = TKIP_CRYPT;
1596 break;
1597 case WLAN_CIPHER_SUITE_CCMP:
1598 p.grp_crypto_type = AES_CRYPT;
1599 break;
1600 default:
1601 p.grp_crypto_type = NONE_CRYPT;
1602 break;
1603 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001604 ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001605
1606 p.nw_type = AP_NETWORK;
1607 ar->nw_type = ar->next_mode;
1608
1609 p.ssid_len = ar->ssid_len;
1610 memcpy(p.ssid, ar->ssid, ar->ssid_len);
1611 p.dot11_auth_mode = ar->dot11_auth_mode;
1612 p.ch = cpu_to_le16(ar->next_chan);
1613
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001614 res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
1615 if (res < 0)
1616 return res;
1617
1618 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001619}
1620
1621static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1622 struct beacon_parameters *info)
1623{
1624 return ath6kl_ap_beacon(wiphy, dev, info, true);
1625}
1626
1627static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1628 struct beacon_parameters *info)
1629{
1630 return ath6kl_ap_beacon(wiphy, dev, info, false);
1631}
1632
1633static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1634{
1635 struct ath6kl *ar = ath6kl_priv(dev);
1636
1637 if (ar->nw_type != AP_NETWORK)
1638 return -EOPNOTSUPP;
1639 if (!test_bit(CONNECTED, &ar->flag))
1640 return -ENOTCONN;
1641
1642 ath6kl_wmi_disconnect_cmd(ar->wmi);
1643 clear_bit(CONNECTED, &ar->flag);
1644
1645 return 0;
1646}
1647
Jouni Malinen23875132011-08-30 21:57:53 +03001648static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1649 u8 *mac, struct station_parameters *params)
1650{
1651 struct ath6kl *ar = ath6kl_priv(dev);
1652
1653 if (ar->nw_type != AP_NETWORK)
1654 return -EOPNOTSUPP;
1655
1656 /* Use this only for authorizing/unauthorizing a station */
1657 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1658 return -EOPNOTSUPP;
1659
1660 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1661 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
1662 mac, 0);
1663 return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
1664 0);
1665}
1666
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001667static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1668 struct net_device *dev,
1669 struct ieee80211_channel *chan,
1670 enum nl80211_channel_type channel_type,
1671 unsigned int duration,
1672 u64 *cookie)
1673{
1674 struct ath6kl *ar = ath6kl_priv(dev);
1675
1676 /* TODO: if already pending or ongoing remain-on-channel,
1677 * return -EBUSY */
1678 *cookie = 1; /* only a single pending request is supported */
1679
1680 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
1681 duration);
1682}
1683
1684static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1685 struct net_device *dev,
1686 u64 cookie)
1687{
1688 struct ath6kl *ar = ath6kl_priv(dev);
1689
1690 if (cookie != 1)
1691 return -ENOENT;
1692
1693 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
1694}
1695
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001696static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
1697 size_t len, unsigned int freq)
1698{
1699 const u8 *pos;
1700 u8 *p2p;
1701 int p2p_len;
1702 int ret;
1703 const struct ieee80211_mgmt *mgmt;
1704
1705 mgmt = (const struct ieee80211_mgmt *) buf;
1706
1707 /* Include P2P IE(s) from the frame generated in user space. */
1708
1709 p2p = kmalloc(len, GFP_KERNEL);
1710 if (p2p == NULL)
1711 return -ENOMEM;
1712 p2p_len = 0;
1713
1714 pos = mgmt->u.probe_resp.variable;
1715 while (pos + 1 < buf + len) {
1716 if (pos + 2 + pos[1] > buf + len)
1717 break;
1718 if (ath6kl_is_p2p_ie(pos)) {
1719 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1720 p2p_len += 2 + pos[1];
1721 }
1722 pos += 2 + pos[1];
1723 }
1724
1725 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
1726 p2p, p2p_len);
1727 kfree(p2p);
1728 return ret;
1729}
1730
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001731static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1732 struct ieee80211_channel *chan, bool offchan,
1733 enum nl80211_channel_type channel_type,
1734 bool channel_type_valid, unsigned int wait,
1735 const u8 *buf, size_t len, u64 *cookie)
1736{
1737 struct ath6kl *ar = ath6kl_priv(dev);
1738 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001739 const struct ieee80211_mgmt *mgmt;
1740
1741 mgmt = (const struct ieee80211_mgmt *) buf;
1742 if (buf + len >= mgmt->u.probe_resp.variable &&
1743 ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
1744 ieee80211_is_probe_resp(mgmt->frame_control)) {
1745 /*
1746 * Send Probe Response frame in AP mode using a separate WMI
1747 * command to allow the target to fill in the generic IEs.
1748 */
1749 *cookie = 0; /* TX status not supported */
1750 return ath6kl_send_go_probe_resp(ar, buf, len,
1751 chan->center_freq);
1752 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001753
1754 id = ar->send_action_id++;
1755 if (id == 0) {
1756 /*
1757 * 0 is a reserved value in the WMI command and shall not be
1758 * used for the command.
1759 */
1760 id = ar->send_action_id++;
1761 }
1762
1763 *cookie = id;
1764 return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
1765 buf, len);
1766}
1767
Jouni Malinenae32c302011-08-30 21:58:01 +03001768static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1769 struct net_device *dev,
1770 u16 frame_type, bool reg)
1771{
1772 struct ath6kl *ar = ath6kl_priv(dev);
1773
1774 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1775 __func__, frame_type, reg);
1776 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1777 /*
1778 * Note: This notification callback is not allowed to sleep, so
1779 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1780 * hardcode target to report Probe Request frames all the time.
1781 */
1782 ar->probe_req_report = reg;
1783 }
1784}
1785
Jouni Malinenf80574a2011-08-30 21:58:04 +03001786static const struct ieee80211_txrx_stypes
1787ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1788 [NL80211_IFTYPE_STATION] = {
1789 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1790 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1791 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1792 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1793 },
1794 [NL80211_IFTYPE_P2P_CLIENT] = {
1795 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1796 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1797 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1798 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1799 },
1800 [NL80211_IFTYPE_P2P_GO] = {
1801 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1802 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1803 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1804 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1805 },
1806};
1807
Kalle Valobdcd8172011-07-18 00:22:30 +03001808static struct cfg80211_ops ath6kl_cfg80211_ops = {
1809 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1810 .scan = ath6kl_cfg80211_scan,
1811 .connect = ath6kl_cfg80211_connect,
1812 .disconnect = ath6kl_cfg80211_disconnect,
1813 .add_key = ath6kl_cfg80211_add_key,
1814 .get_key = ath6kl_cfg80211_get_key,
1815 .del_key = ath6kl_cfg80211_del_key,
1816 .set_default_key = ath6kl_cfg80211_set_default_key,
1817 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1818 .set_tx_power = ath6kl_cfg80211_set_txpower,
1819 .get_tx_power = ath6kl_cfg80211_get_txpower,
1820 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1821 .join_ibss = ath6kl_cfg80211_join_ibss,
1822 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1823 .get_station = ath6kl_get_station,
1824 .set_pmksa = ath6kl_set_pmksa,
1825 .del_pmksa = ath6kl_del_pmksa,
1826 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001827 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001828#ifdef CONFIG_PM
1829 .suspend = ar6k_cfg80211_suspend,
1830#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001831 .set_channel = ath6kl_set_channel,
1832 .add_beacon = ath6kl_add_beacon,
1833 .set_beacon = ath6kl_set_beacon,
1834 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001835 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001836 .remain_on_channel = ath6kl_remain_on_channel,
1837 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001838 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001839 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001840};
1841
1842struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
1843{
1844 int ret = 0;
1845 struct wireless_dev *wdev;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001846 struct ath6kl *ar;
Kalle Valobdcd8172011-07-18 00:22:30 +03001847
1848 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1849 if (!wdev) {
1850 ath6kl_err("couldn't allocate wireless device\n");
1851 return NULL;
1852 }
1853
1854 /* create a new wiphy for use with cfg80211 */
1855 wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
1856 if (!wdev->wiphy) {
1857 ath6kl_err("couldn't allocate wiphy device\n");
1858 kfree(wdev);
1859 return NULL;
1860 }
1861
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001862 ar = wiphy_priv(wdev->wiphy);
1863 ar->p2p = !!ath6kl_p2p;
1864
Jouni Malinenf80574a2011-08-30 21:58:04 +03001865 wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
1866
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001867 wdev->wiphy->max_remain_on_channel_duration = 5000;
1868
Kalle Valobdcd8172011-07-18 00:22:30 +03001869 /* set device pointer for wiphy */
1870 set_wiphy_dev(wdev->wiphy, dev);
1871
1872 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001873 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001874 if (ar->p2p) {
1875 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
1876 BIT(NL80211_IFTYPE_P2P_CLIENT);
1877 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001878 /* max num of ssids that can be probed during scanning */
1879 wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001880 wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Kalle Valobdcd8172011-07-18 00:22:30 +03001881 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
1882 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
1883 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1884
1885 wdev->wiphy->cipher_suites = cipher_suites;
1886 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1887
1888 ret = wiphy_register(wdev->wiphy);
1889 if (ret < 0) {
1890 ath6kl_err("couldn't register wiphy device\n");
1891 wiphy_free(wdev->wiphy);
1892 kfree(wdev);
1893 return NULL;
1894 }
1895
1896 return wdev;
1897}
1898
1899void ath6kl_cfg80211_deinit(struct ath6kl *ar)
1900{
1901 struct wireless_dev *wdev = ar->wdev;
1902
1903 if (ar->scan_req) {
1904 cfg80211_scan_done(ar->scan_req, true);
1905 ar->scan_req = NULL;
1906 }
1907
1908 if (!wdev)
1909 return;
1910
1911 wiphy_unregister(wdev->wiphy);
1912 wiphy_free(wdev->wiphy);
1913 kfree(wdev);
1914}