blob: abe3af3c61889a50d074a084fcb1b999a651f397 [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
Jouni Malinen837cb972011-10-11 17:31:57 +0300124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
125
Kalle Valo10509f92011-12-13 14:52:07 +0200126/* returns true if scheduled scan was stopped */
127static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
128{
129 struct ath6kl *ar = vif->ar;
130
131 if (ar->state != ATH6KL_STATE_SCHED_SCAN)
132 return false;
133
134 del_timer_sync(&vif->sched_scan_timer);
135
136 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
137 ATH6KL_HOST_MODE_AWAKE);
138
139 ar->state = ATH6KL_STATE_ON;
140
141 return true;
142}
143
144static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
145{
146 struct ath6kl *ar = vif->ar;
147 bool stopped;
148
149 stopped = __ath6kl_cfg80211_sscan_stop(vif);
150
151 if (!stopped)
152 return;
153
154 cfg80211_sched_scan_stopped(ar->wiphy);
155}
156
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530157static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300158 enum nl80211_wpa_versions wpa_version)
159{
160 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
161
162 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530163 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300164 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530165 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300166 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530167 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300168 } else {
169 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
170 return -ENOTSUPP;
171 }
172
173 return 0;
174}
175
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530176static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300177 enum nl80211_auth_type auth_type)
178{
Kalle Valobdcd8172011-07-18 00:22:30 +0300179 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
180
181 switch (auth_type) {
182 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530183 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300184 break;
185 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530186 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300187 break;
188 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530189 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300190 break;
191
192 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530193 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300194 break;
195
196 default:
197 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
198 return -ENOTSUPP;
199 }
200
201 return 0;
202}
203
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530204static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300205{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530206 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
207 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
208 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300209
210 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
211 __func__, cipher, ucast);
212
213 switch (cipher) {
214 case 0:
215 /* our own hack to use value 0 as no crypto used */
216 *ar_cipher = NONE_CRYPT;
217 *ar_cipher_len = 0;
218 break;
219 case WLAN_CIPHER_SUITE_WEP40:
220 *ar_cipher = WEP_CRYPT;
221 *ar_cipher_len = 5;
222 break;
223 case WLAN_CIPHER_SUITE_WEP104:
224 *ar_cipher = WEP_CRYPT;
225 *ar_cipher_len = 13;
226 break;
227 case WLAN_CIPHER_SUITE_TKIP:
228 *ar_cipher = TKIP_CRYPT;
229 *ar_cipher_len = 0;
230 break;
231 case WLAN_CIPHER_SUITE_CCMP:
232 *ar_cipher = AES_CRYPT;
233 *ar_cipher_len = 0;
234 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200235 case WLAN_CIPHER_SUITE_SMS4:
236 *ar_cipher = WAPI_CRYPT;
237 *ar_cipher_len = 0;
238 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300239 default:
240 ath6kl_err("cipher 0x%x not supported\n", cipher);
241 return -ENOTSUPP;
242 }
243
244 return 0;
245}
246
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530247static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300248{
249 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
250
251 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530252 if (vif->auth_mode == WPA_AUTH)
253 vif->auth_mode = WPA_PSK_AUTH;
254 else if (vif->auth_mode == WPA2_AUTH)
255 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300256 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530257 if (vif->auth_mode == WPA_AUTH)
258 vif->auth_mode = WPA_AUTH_CCKM;
259 else if (vif->auth_mode == WPA2_AUTH)
260 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300261 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530262 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300263 }
264}
265
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530266static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300267{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530268 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530269
Kalle Valobdcd8172011-07-18 00:22:30 +0300270 if (!test_bit(WMI_READY, &ar->flag)) {
271 ath6kl_err("wmi is not ready\n");
272 return false;
273 }
274
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530275 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300276 ath6kl_err("wlan disabled\n");
277 return false;
278 }
279
280 return true;
281}
282
Kevin Fang6981ffd2011-10-07 08:51:19 +0800283static bool ath6kl_is_wpa_ie(const u8 *pos)
284{
285 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
286 pos[2] == 0x00 && pos[3] == 0x50 &&
287 pos[4] == 0xf2 && pos[5] == 0x01;
288}
289
290static bool ath6kl_is_rsn_ie(const u8 *pos)
291{
292 return pos[0] == WLAN_EID_RSN;
293}
294
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700295static bool ath6kl_is_wps_ie(const u8 *pos)
296{
297 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
298 pos[1] >= 4 &&
299 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
300 pos[5] == 0x04);
301}
302
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530303static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
304 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800305{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530306 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800307 const u8 *pos;
308 u8 *buf = NULL;
309 size_t len = 0;
310 int ret;
311
312 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700313 * Clear previously set flag
314 */
315
316 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
317
318 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800319 * Filter out RSN/WPA IE(s)
320 */
321
322 if (ies && ies_len) {
323 buf = kmalloc(ies_len, GFP_KERNEL);
324 if (buf == NULL)
325 return -ENOMEM;
326 pos = ies;
327
328 while (pos + 1 < ies + ies_len) {
329 if (pos + 2 + pos[1] > ies + ies_len)
330 break;
331 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
332 memcpy(buf + len, pos, 2 + pos[1]);
333 len += 2 + pos[1];
334 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700335
336 if (ath6kl_is_wps_ie(pos))
337 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
338
Kevin Fang6981ffd2011-10-07 08:51:19 +0800339 pos += 2 + pos[1];
340 }
341 }
342
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530343 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
344 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800345 kfree(buf);
346 return ret;
347}
348
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530349static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
350{
351 switch (type) {
352 case NL80211_IFTYPE_STATION:
353 *nw_type = INFRA_NETWORK;
354 break;
355 case NL80211_IFTYPE_ADHOC:
356 *nw_type = ADHOC_NETWORK;
357 break;
358 case NL80211_IFTYPE_AP:
359 *nw_type = AP_NETWORK;
360 break;
361 case NL80211_IFTYPE_P2P_CLIENT:
362 *nw_type = INFRA_NETWORK;
363 break;
364 case NL80211_IFTYPE_P2P_GO:
365 *nw_type = AP_NETWORK;
366 break;
367 default:
368 ath6kl_err("invalid interface type %u\n", type);
369 return -ENOTSUPP;
370 }
371
372 return 0;
373}
374
375static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
376 u8 *if_idx, u8 *nw_type)
377{
378 int i;
379
380 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
381 return false;
382
383 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
384 ar->num_vif))
385 return false;
386
387 if (type == NL80211_IFTYPE_STATION ||
388 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200389 for (i = 0; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530390 if ((ar->avail_idx_map >> i) & BIT(0)) {
391 *if_idx = i;
392 return true;
393 }
394 }
395 }
396
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530397 if (type == NL80211_IFTYPE_P2P_CLIENT ||
398 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200399 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530400 if ((ar->avail_idx_map >> i) & BIT(0)) {
401 *if_idx = i;
402 return true;
403 }
404 }
405 }
406
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530407 return false;
408}
409
Kalle Valobdcd8172011-07-18 00:22:30 +0300410static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
411 struct cfg80211_connect_params *sme)
412{
413 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530414 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300415 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800416 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Kalle Valobdcd8172011-07-18 00:22:30 +0300417
Kalle Valo10509f92011-12-13 14:52:07 +0200418 ath6kl_cfg80211_sscan_disable(vif);
419
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530420 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300421
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530422 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300423 return -EIO;
424
425 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
426 ath6kl_err("destroy in progress\n");
427 return -EBUSY;
428 }
429
430 if (test_bit(SKIP_SCAN, &ar->flag) &&
431 ((sme->channel && sme->channel->center_freq == 0) ||
432 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
433 ath6kl_err("SkipScan: channel or bssid invalid\n");
434 return -EINVAL;
435 }
436
437 if (down_interruptible(&ar->sem)) {
438 ath6kl_err("busy, couldn't get access\n");
439 return -ERESTARTSYS;
440 }
441
442 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
443 ath6kl_err("busy, destroy in progress\n");
444 up(&ar->sem);
445 return -EBUSY;
446 }
447
448 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
449 /*
450 * sleep until the command queue drains
451 */
452 wait_event_interruptible_timeout(ar->event_wq,
453 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
454 WMI_TIMEOUT);
455 if (signal_pending(current)) {
456 ath6kl_err("cmd queue drain timeout\n");
457 up(&ar->sem);
458 return -EINTR;
459 }
460 }
461
Kevin Fang6981ffd2011-10-07 08:51:19 +0800462 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530463 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Dan Carpenter743b4512011-11-18 17:09:32 +0300464 if (status) {
465 up(&ar->sem);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800466 return status;
Dan Carpenter743b4512011-11-18 17:09:32 +0300467 }
Raja Mani542c5192011-11-15 14:14:56 +0530468 } else
469 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800470
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530471 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530472 vif->ssid_len == sme->ssid_len &&
473 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530474 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530475 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
476 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530477 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300478
479 up(&ar->sem);
480 if (status) {
481 ath6kl_err("wmi_reconnect_cmd failed\n");
482 return -EIO;
483 }
484 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530485 } else if (vif->ssid_len == sme->ssid_len &&
486 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530487 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300488 }
489
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530490 memset(vif->ssid, 0, sizeof(vif->ssid));
491 vif->ssid_len = sme->ssid_len;
492 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300493
494 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530495 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300496
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530497 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300498 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530499 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300500
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530501 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300502
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530503 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300504 if (status) {
505 up(&ar->sem);
506 return status;
507 }
508
509 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530510 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300511 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530512 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300513
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530514 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300515
516 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530517 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300518
519 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530520 (vif->auth_mode == NONE_AUTH) &&
521 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300522 struct ath6kl_key *key = NULL;
523
524 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
525 sme->key_idx > WMI_MAX_KEY_INDEX) {
526 ath6kl_err("key index %d out of bounds\n",
527 sme->key_idx);
528 up(&ar->sem);
529 return -ENOENT;
530 }
531
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530532 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300533 key->key_len = sme->key_len;
534 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530535 key->cipher = vif->prwise_crypto;
536 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300537
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530538 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530539 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300540 GROUP_USAGE | TX_USAGE,
541 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200542 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300543 key->key, KEY_OP_INIT_VAL, NULL,
544 NO_SYNC_WMIFLAG);
545 }
546
547 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530548 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530549 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
550 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300551 ath6kl_err("couldn't set bss filtering\n");
552 up(&ar->sem);
553 return -EIO;
554 }
555 }
556
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530557 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300558
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800559 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
560 nw_subtype = SUBTYPE_P2PCLIENT;
561
Kalle Valobdcd8172011-07-18 00:22:30 +0300562 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
563 "%s: connect called with authmode %d dot11 auth %d"
564 " PW crypto %d PW crypto len %d GRP crypto %d"
565 " GRP crypto len %d channel hint %u\n",
566 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530567 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
568 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530569 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300570
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530571 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530572 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530573 vif->dot11_auth_mode, vif->auth_mode,
574 vif->prwise_crypto,
575 vif->prwise_crypto_len,
576 vif->grp_crypto, vif->grp_crypto_len,
577 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530578 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800579 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300580
581 up(&ar->sem);
582
583 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 memset(vif->ssid, 0, sizeof(vif->ssid));
585 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300586 ath6kl_err("invalid request\n");
587 return -ENOENT;
588 } else if (status) {
589 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
590 return -EIO;
591 }
592
593 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530594 ((vif->auth_mode == WPA_PSK_AUTH)
595 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530596 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300597 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
598 }
599
600 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530601 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300602
603 return 0;
604}
605
Raja Mani4eab6f42011-11-09 17:02:23 +0530606static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
607 enum network_type nw_type,
608 const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300609 struct ieee80211_channel *chan,
610 const u8 *beacon_ie, size_t beacon_ie_len)
611{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530612 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300613 struct cfg80211_bss *bss;
Raja Mani4eab6f42011-11-09 17:02:23 +0530614 u16 cap_mask, cap_val;
Jouni Malinen01cac472011-09-19 19:14:59 +0300615 u8 *ie;
616
Raja Mani4eab6f42011-11-09 17:02:23 +0530617 if (nw_type & ADHOC_NETWORK) {
618 cap_mask = WLAN_CAPABILITY_IBSS;
619 cap_val = WLAN_CAPABILITY_IBSS;
620 } else {
621 cap_mask = WLAN_CAPABILITY_ESS;
622 cap_val = WLAN_CAPABILITY_ESS;
623 }
624
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530625 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530626 vif->ssid, vif->ssid_len,
627 cap_mask, cap_val);
Jouni Malinen01cac472011-09-19 19:14:59 +0300628 if (bss == NULL) {
629 /*
630 * Since cfg80211 may not yet know about the BSS,
631 * generate a partial entry until the first BSS info
632 * event becomes available.
633 *
634 * Prepend SSID element since it is not included in the Beacon
635 * IEs from the target.
636 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530637 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300638 if (ie == NULL)
639 return -ENOMEM;
640 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530641 ie[1] = vif->ssid_len;
642 memcpy(ie + 2, vif->ssid, vif->ssid_len);
643 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530644 bss = cfg80211_inform_bss(ar->wiphy, chan,
Raja Mani4eab6f42011-11-09 17:02:23 +0530645 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530646 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300647 0, GFP_KERNEL);
648 if (bss)
Raja Mani4eab6f42011-11-09 17:02:23 +0530649 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
650 "cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300651 kfree(ie);
652 } else
653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
654 "entry\n");
655
656 if (bss == NULL)
657 return -ENOMEM;
658
659 cfg80211_put_bss(bss);
660
661 return 0;
662}
663
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530664void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300665 u8 *bssid, u16 listen_intvl,
666 u16 beacon_intvl,
667 enum network_type nw_type,
668 u8 beacon_ie_len, u8 assoc_req_len,
669 u8 assoc_resp_len, u8 *assoc_info)
670{
Jouni Malinen01cac472011-09-19 19:14:59 +0300671 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530672 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300673
674 /* capinfo + listen interval */
675 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
676
677 /* capinfo + status code + associd */
678 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
679
680 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
681 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
682 assoc_resp_ie_offset;
683
684 assoc_req_len -= assoc_req_ie_offset;
685 assoc_resp_len -= assoc_resp_ie_offset;
686
Jouni Malinen32c10872011-09-19 19:15:07 +0300687 /*
688 * Store Beacon interval here; DTIM period will be available only once
689 * a Beacon frame from the AP is seen.
690 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530691 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530692 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300693
Kalle Valobdcd8172011-07-18 00:22:30 +0300694 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530695 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300696 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
697 "%s: ath6k not in ibss mode\n", __func__);
698 return;
699 }
700 }
701
702 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530703 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
704 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300705 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
706 "%s: ath6k not in station mode\n", __func__);
707 return;
708 }
709 }
710
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530711 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300712
Raja Mani4eab6f42011-11-09 17:02:23 +0530713 if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
714 beacon_ie_len) < 0) {
715 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300716 return;
717 }
718
Raja Mani4eab6f42011-11-09 17:02:23 +0530719 if (nw_type & ADHOC_NETWORK) {
720 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
721 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
722 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300723 return;
724 }
725
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530726 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530728 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530729 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300730 assoc_req_ie, assoc_req_len,
731 assoc_resp_ie, assoc_resp_len,
732 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530733 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300734 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530735 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300736 assoc_req_ie, assoc_req_len,
737 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
738 }
739}
740
741static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
742 struct net_device *dev, u16 reason_code)
743{
Kalle Valod6d5c062011-11-25 13:17:37 +0200744 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530745 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300746
747 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
748 reason_code);
749
Kalle Valo10509f92011-12-13 14:52:07 +0200750 ath6kl_cfg80211_sscan_disable(vif);
751
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530752 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300753 return -EIO;
754
755 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
756 ath6kl_err("busy, destroy in progress\n");
757 return -EBUSY;
758 }
759
760 if (down_interruptible(&ar->sem)) {
761 ath6kl_err("busy, couldn't get access\n");
762 return -ERESTARTSYS;
763 }
764
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530765 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530766 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530767 memset(vif->ssid, 0, sizeof(vif->ssid));
768 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300769
770 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530771 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300772
773 up(&ar->sem);
774
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530775 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530776
Kalle Valobdcd8172011-07-18 00:22:30 +0300777 return 0;
778}
779
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530780void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300781 u8 *bssid, u8 assoc_resp_len,
782 u8 *assoc_info, u16 proto_reason)
783{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530784 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530785
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530786 if (vif->scan_req) {
787 cfg80211_scan_done(vif->scan_req, true);
788 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300789 }
790
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530791 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530792 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300793 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
794 "%s: ath6k not in ibss mode\n", __func__);
795 return;
796 }
797 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530798 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300799 return;
800 }
801
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530802 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530803 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
804 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300805 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
806 "%s: ath6k not in station mode\n", __func__);
807 return;
808 }
809 }
810
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530811 /*
812 * Send a disconnect command to target when a disconnect event is
813 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
814 * request from host) to make the firmware stop trying to connect even
815 * after giving disconnect event. There will be one more disconnect
816 * event for this disconnect command with reason code DISCONNECT_CMD
817 * which will be notified to cfg80211.
818 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300819
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530820 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530821 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300822 return;
823 }
824
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530825 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300826
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530827 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530828 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530829 bssid, NULL, 0,
830 NULL, 0,
831 WLAN_STATUS_UNSPECIFIED_FAILURE,
832 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530833 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530834 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530835 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300836 }
837
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530838 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300839}
840
Kalle Valobdcd8172011-07-18 00:22:30 +0300841static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
842 struct cfg80211_scan_request *request)
843{
Kalle Valod6d5c062011-11-25 13:17:37 +0200844 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530845 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300846 s8 n_channels = 0;
847 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300848 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530849 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300850
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530851 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300852 return -EIO;
853
Kalle Valo10509f92011-12-13 14:52:07 +0200854 ath6kl_cfg80211_sscan_disable(vif);
855
Kalle Valobdcd8172011-07-18 00:22:30 +0300856 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530857 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300858 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530859 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530860 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300861 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
862 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300863 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300864 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300865 }
866 }
867
868 if (request->n_ssids && request->ssids[0].ssid_len) {
869 u8 i;
870
871 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
872 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
873
874 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530875 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
876 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300877 request->ssids[i].ssid_len,
878 request->ssids[i].ssid);
879 }
880
Kalle Valo10509f92011-12-13 14:52:07 +0200881 /*
882 * FIXME: we should clear the IE in fw if it's not set so just
883 * remove the check altogether
884 */
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300885 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530886 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
887 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300888 request->ie, request->ie_len);
889 if (ret) {
890 ath6kl_err("failed to set Probe Request appie for "
891 "scan");
892 return ret;
893 }
894 }
895
Jouni Malinen11869be2011-09-02 20:07:06 +0300896 /*
897 * Scan only the requested channels if the request specifies a set of
898 * channels. If the list is longer than the target supports, do not
899 * configure the list and instead, scan all available channels.
900 */
901 if (request->n_channels > 0 &&
902 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300903 u8 i;
904
Jouni Malinen11869be2011-09-02 20:07:06 +0300905 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300906
907 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
908 if (channels == NULL) {
909 ath6kl_warn("failed to set scan channels, "
910 "scan all channels");
911 n_channels = 0;
912 }
913
914 for (i = 0; i < n_channels; i++)
915 channels[i] = request->channels[i]->center_freq;
916 }
917
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530918 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530919 force_fg_scan = 1;
920
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800921 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
922 ar->fw_capabilities)) {
923 /*
924 * If capable of doing P2P mgmt operations using
925 * station interface, send additional information like
926 * supported rates to advertise and xmit rates for
927 * probe requests
928 */
929 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
930 WMI_LONG_SCAN, force_fg_scan,
931 false, 0, 0, n_channels,
932 channels, request->no_cck,
933 request->rates);
934 } else {
935 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
936 WMI_LONG_SCAN, force_fg_scan,
937 false, 0, 0, n_channels,
938 channels);
939 }
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300940 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300941 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300942 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530943 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300944
Edward Lu1276c9e2011-08-30 21:58:00 +0300945 kfree(channels);
946
Kalle Valobdcd8172011-07-18 00:22:30 +0300947 return ret;
948}
949
Kalle Valo1c17d312011-11-01 08:43:56 +0200950void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300951{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530952 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300953 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300954
Kalle Valo1c17d312011-11-01 08:43:56 +0200955 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
956 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300957
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530958 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300959 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300960
Kalle Valo1c17d312011-11-01 08:43:56 +0200961 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300962 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300963
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530964 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
965 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530966 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
967 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300968 0, NULL);
969 }
970 }
971
972out:
Kalle Valocb938212011-10-27 18:47:46 +0300973 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530974 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300975}
976
977static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
978 u8 key_index, bool pairwise,
979 const u8 *mac_addr,
980 struct key_params *params)
981{
Kalle Valod6d5c062011-11-25 13:17:37 +0200982 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530983 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300984 struct ath6kl_key *key = NULL;
985 u8 key_usage;
986 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300987
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530988 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300989 return -EIO;
990
Jouni Malinen837cb972011-10-11 17:31:57 +0300991 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
992 if (params->key_len != WMI_KRK_LEN)
993 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530994 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
995 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300996 }
997
Kalle Valobdcd8172011-07-18 00:22:30 +0300998 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
999 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1000 "%s: key index %d out of bounds\n", __func__,
1001 key_index);
1002 return -ENOENT;
1003 }
1004
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301005 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001006 memset(key, 0, sizeof(struct ath6kl_key));
1007
1008 if (pairwise)
1009 key_usage = PAIRWISE_USAGE;
1010 else
1011 key_usage = GROUP_USAGE;
1012
1013 if (params) {
Dai Shuibing5e070212011-11-03 11:39:37 +02001014 int seq_len = params->seq_len;
1015 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1016 seq_len > ATH6KL_KEY_SEQ_LEN) {
1017 /* Only first half of the WPI PN is configured */
1018 seq_len = ATH6KL_KEY_SEQ_LEN;
1019 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001020 if (params->key_len > WLAN_MAX_KEY_LEN ||
Dai Shuibing5e070212011-11-03 11:39:37 +02001021 seq_len > sizeof(key->seq))
Kalle Valobdcd8172011-07-18 00:22:30 +03001022 return -EINVAL;
1023
1024 key->key_len = params->key_len;
1025 memcpy(key->key, params->key, key->key_len);
Dai Shuibing5e070212011-11-03 11:39:37 +02001026 key->seq_len = seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +03001027 memcpy(key->seq, params->seq, key->seq_len);
1028 key->cipher = params->cipher;
1029 }
1030
1031 switch (key->cipher) {
1032 case WLAN_CIPHER_SUITE_WEP40:
1033 case WLAN_CIPHER_SUITE_WEP104:
1034 key_type = WEP_CRYPT;
1035 break;
1036
1037 case WLAN_CIPHER_SUITE_TKIP:
1038 key_type = TKIP_CRYPT;
1039 break;
1040
1041 case WLAN_CIPHER_SUITE_CCMP:
1042 key_type = AES_CRYPT;
1043 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001044 case WLAN_CIPHER_SUITE_SMS4:
1045 key_type = WAPI_CRYPT;
1046 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001047
1048 default:
1049 return -ENOTSUPP;
1050 }
1051
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301052 if (((vif->auth_mode == WPA_PSK_AUTH)
1053 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +03001054 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301055 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001056
1057 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1058 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1059 __func__, key_index, key->key_len, key_type,
1060 key_usage, key->seq_len);
1061
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301062 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001063 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
1064 key_type == WAPI_CRYPT) && params) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001065 ar->ap_mode_bkey.valid = true;
1066 ar->ap_mode_bkey.key_index = key_index;
1067 ar->ap_mode_bkey.key_type = key_type;
1068 ar->ap_mode_bkey.key_len = key->key_len;
1069 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301070 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001071 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1072 "key configuration until AP mode has been "
1073 "started\n");
1074 /*
1075 * The key will be set in ath6kl_connect_ap_mode() once
1076 * the connected event is received from the target.
1077 */
1078 return 0;
1079 }
1080 }
1081
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301082 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301083 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001084 /*
1085 * Store the key locally so that it can be re-configured after
1086 * the AP mode has properly started
1087 * (ath6kl_install_statioc_wep_keys).
1088 */
1089 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1090 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301091 vif->wep_key_list[key_index].key_len = key->key_len;
1092 memcpy(vif->wep_key_list[key_index].key, key->key,
1093 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001094 return 0;
1095 }
1096
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301097 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001098 key_type, key_usage, key->key_len,
1099 key->seq, key->seq_len, key->key,
1100 KEY_OP_INIT_VAL,
1101 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001102}
1103
1104static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1105 u8 key_index, bool pairwise,
1106 const u8 *mac_addr)
1107{
Kalle Valod6d5c062011-11-25 13:17:37 +02001108 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301109 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001110
1111 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1112
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301113 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001114 return -EIO;
1115
1116 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1117 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1118 "%s: key index %d out of bounds\n", __func__,
1119 key_index);
1120 return -ENOENT;
1121 }
1122
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301123 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001124 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1125 "%s: index %d is empty\n", __func__, key_index);
1126 return 0;
1127 }
1128
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301129 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001130
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301131 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001132}
1133
1134static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1135 u8 key_index, bool pairwise,
1136 const u8 *mac_addr, void *cookie,
1137 void (*callback) (void *cookie,
1138 struct key_params *))
1139{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301140 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001141 struct ath6kl_key *key = NULL;
1142 struct key_params params;
1143
1144 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1145
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301146 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001147 return -EIO;
1148
1149 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1150 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1151 "%s: key index %d out of bounds\n", __func__,
1152 key_index);
1153 return -ENOENT;
1154 }
1155
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301156 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001157 memset(&params, 0, sizeof(params));
1158 params.cipher = key->cipher;
1159 params.key_len = key->key_len;
1160 params.seq_len = key->seq_len;
1161 params.seq = key->seq;
1162 params.key = key->key;
1163
1164 callback(cookie, &params);
1165
1166 return key->key_len ? 0 : -ENOENT;
1167}
1168
1169static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1170 struct net_device *ndev,
1171 u8 key_index, bool unicast,
1172 bool multicast)
1173{
Kalle Valod6d5c062011-11-25 13:17:37 +02001174 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301175 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001176 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001177 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001178 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001179
1180 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1181
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301182 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001183 return -EIO;
1184
1185 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1186 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1187 "%s: key index %d out of bounds\n",
1188 __func__, key_index);
1189 return -ENOENT;
1190 }
1191
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301192 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001193 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1194 __func__, key_index);
1195 return -EINVAL;
1196 }
1197
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301198 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301199 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001200 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301201 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001202 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001203 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301204 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001205 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301206 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001207
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301208 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001209 return 0; /* Delay until AP mode has been started */
1210
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001211 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1212 vif->def_txkey_index,
1213 key_type, key_usage,
1214 key->key_len, key->seq, key->seq_len,
1215 key->key,
1216 KEY_OP_INIT_VAL, NULL,
1217 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001218}
1219
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301220void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001221 bool ismcast)
1222{
1223 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1224 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1225
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301226 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001227 (ismcast ? NL80211_KEYTYPE_GROUP :
1228 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1229 GFP_KERNEL);
1230}
1231
1232static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1233{
1234 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301235 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001236 int ret;
1237
1238 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1239 changed);
1240
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301241 vif = ath6kl_vif_first(ar);
1242 if (!vif)
1243 return -EIO;
1244
1245 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001246 return -EIO;
1247
1248 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1249 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1250 if (ret != 0) {
1251 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1252 return -EIO;
1253 }
1254 }
1255
1256 return 0;
1257}
1258
1259/*
1260 * The type nl80211_tx_power_setting replaces the following
1261 * data type from 2.6.36 onwards
1262*/
1263static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1264 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001265 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001266{
1267 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301268 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001269 u8 ath6kl_dbm;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001270 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001271
1272 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1273 type, dbm);
1274
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301275 vif = ath6kl_vif_first(ar);
1276 if (!vif)
1277 return -EIO;
1278
1279 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001280 return -EIO;
1281
1282 switch (type) {
1283 case NL80211_TX_POWER_AUTOMATIC:
1284 return 0;
1285 case NL80211_TX_POWER_LIMITED:
1286 ar->tx_pwr = ath6kl_dbm = dbm;
1287 break;
1288 default:
1289 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1290 __func__, type);
1291 return -EOPNOTSUPP;
1292 }
1293
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301294 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001295
1296 return 0;
1297}
1298
1299static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1300{
1301 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301302 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001303
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301304 vif = ath6kl_vif_first(ar);
1305 if (!vif)
1306 return -EIO;
1307
1308 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001309 return -EIO;
1310
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301311 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001312 ar->tx_pwr = 0;
1313
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301314 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001315 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1316 return -EIO;
1317 }
1318
1319 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1320 5 * HZ);
1321
1322 if (signal_pending(current)) {
1323 ath6kl_err("target did not respond\n");
1324 return -EINTR;
1325 }
1326 }
1327
1328 *dbm = ar->tx_pwr;
1329 return 0;
1330}
1331
1332static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1333 struct net_device *dev,
1334 bool pmgmt, int timeout)
1335{
1336 struct ath6kl *ar = ath6kl_priv(dev);
1337 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301338 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001339
1340 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1341 __func__, pmgmt, timeout);
1342
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301343 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001344 return -EIO;
1345
1346 if (pmgmt) {
1347 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1348 mode.pwr_mode = REC_POWER;
1349 } else {
1350 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1351 mode.pwr_mode = MAX_PERF_POWER;
1352 }
1353
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301354 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1355 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001356 ath6kl_err("wmi_powermode_cmd failed\n");
1357 return -EIO;
1358 }
1359
1360 return 0;
1361}
1362
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301363static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1364 char *name,
1365 enum nl80211_iftype type,
1366 u32 *flags,
1367 struct vif_params *params)
1368{
1369 struct ath6kl *ar = wiphy_priv(wiphy);
1370 struct net_device *ndev;
1371 u8 if_idx, nw_type;
1372
Kalle Valo71f96ee2011-11-14 19:31:30 +02001373 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301374 ath6kl_err("Reached maximum number of supported vif\n");
1375 return ERR_PTR(-EINVAL);
1376 }
1377
1378 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1379 ath6kl_err("Not a supported interface type\n");
1380 return ERR_PTR(-EINVAL);
1381 }
1382
1383 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1384 if (!ndev)
1385 return ERR_PTR(-ENOMEM);
1386
1387 ar->num_vif++;
1388
1389 return ndev;
1390}
1391
1392static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1393 struct net_device *ndev)
1394{
1395 struct ath6kl *ar = wiphy_priv(wiphy);
1396 struct ath6kl_vif *vif = netdev_priv(ndev);
1397
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301398 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301399 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301400 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301401
1402 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1403
1404 ath6kl_deinit_if_data(vif);
1405
1406 return 0;
1407}
1408
Kalle Valobdcd8172011-07-18 00:22:30 +03001409static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1410 struct net_device *ndev,
1411 enum nl80211_iftype type, u32 *flags,
1412 struct vif_params *params)
1413{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301414 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001415
1416 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1417
Kalle Valobdcd8172011-07-18 00:22:30 +03001418 switch (type) {
1419 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301420 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001421 break;
1422 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301423 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001424 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001425 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301426 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001427 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001428 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301429 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001430 break;
1431 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301432 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001433 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001434 default:
1435 ath6kl_err("invalid interface type %u\n", type);
1436 return -EOPNOTSUPP;
1437 }
1438
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301439 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001440
1441 return 0;
1442}
1443
1444static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1445 struct net_device *dev,
1446 struct cfg80211_ibss_params *ibss_param)
1447{
1448 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301449 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001450 int status;
1451
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301452 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001453 return -EIO;
1454
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301455 vif->ssid_len = ibss_param->ssid_len;
1456 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001457
1458 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301459 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001460
1461 if (ibss_param->channel_fixed) {
1462 /*
1463 * TODO: channel_fixed: The channel should be fixed, do not
1464 * search for IBSSs to join on other channels. Target
1465 * firmware does not support this feature, needs to be
1466 * updated.
1467 */
1468 return -EOPNOTSUPP;
1469 }
1470
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301471 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001472 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301473 memcpy(vif->req_bssid, ibss_param->bssid,
1474 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001475
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301476 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001477
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301478 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001479 if (status)
1480 return status;
1481
1482 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301483 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1484 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001485 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301486 ath6kl_set_cipher(vif, 0, true);
1487 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001488 }
1489
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301490 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001491
1492 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1493 "%s: connect called with authmode %d dot11 auth %d"
1494 " PW crypto %d PW crypto len %d GRP crypto %d"
1495 " GRP crypto len %d channel hint %u\n",
1496 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301497 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1498 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301499 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001500
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301501 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301502 vif->dot11_auth_mode, vif->auth_mode,
1503 vif->prwise_crypto,
1504 vif->prwise_crypto_len,
1505 vif->grp_crypto, vif->grp_crypto_len,
1506 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301507 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001508 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301509 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001510
1511 return 0;
1512}
1513
1514static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1515 struct net_device *dev)
1516{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301517 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301519 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001520 return -EIO;
1521
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301522 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301523 memset(vif->ssid, 0, sizeof(vif->ssid));
1524 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001525
1526 return 0;
1527}
1528
1529static const u32 cipher_suites[] = {
1530 WLAN_CIPHER_SUITE_WEP40,
1531 WLAN_CIPHER_SUITE_WEP104,
1532 WLAN_CIPHER_SUITE_TKIP,
1533 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001534 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001535 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001536};
1537
1538static bool is_rate_legacy(s32 rate)
1539{
1540 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1541 6000, 9000, 12000, 18000, 24000,
1542 36000, 48000, 54000
1543 };
1544 u8 i;
1545
1546 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1547 if (rate == legacy[i])
1548 return true;
1549
1550 return false;
1551}
1552
1553static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1554{
1555 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1556 52000, 58500, 65000, 72200
1557 };
1558 u8 i;
1559
1560 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1561 if (rate == ht20[i]) {
1562 if (i == ARRAY_SIZE(ht20) - 1)
1563 /* last rate uses sgi */
1564 *sgi = true;
1565 else
1566 *sgi = false;
1567
1568 *mcs = i;
1569 return true;
1570 }
1571 }
1572 return false;
1573}
1574
1575static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1576{
1577 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1578 81000, 108000, 121500, 135000,
1579 150000
1580 };
1581 u8 i;
1582
1583 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1584 if (rate == ht40[i]) {
1585 if (i == ARRAY_SIZE(ht40) - 1)
1586 /* last rate uses sgi */
1587 *sgi = true;
1588 else
1589 *sgi = false;
1590
1591 *mcs = i;
1592 return true;
1593 }
1594 }
1595
1596 return false;
1597}
1598
1599static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1600 u8 *mac, struct station_info *sinfo)
1601{
1602 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301603 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001604 long left;
1605 bool sgi;
1606 s32 rate;
1607 int ret;
1608 u8 mcs;
1609
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301610 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001611 return -ENOENT;
1612
1613 if (down_interruptible(&ar->sem))
1614 return -EBUSY;
1615
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301616 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001617
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301618 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001619
1620 if (ret != 0) {
1621 up(&ar->sem);
1622 return -EIO;
1623 }
1624
1625 left = wait_event_interruptible_timeout(ar->event_wq,
1626 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301627 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001628 WMI_TIMEOUT);
1629
1630 up(&ar->sem);
1631
1632 if (left == 0)
1633 return -ETIMEDOUT;
1634 else if (left < 0)
1635 return left;
1636
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301637 if (vif->target_stats.rx_byte) {
1638 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001639 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301640 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001641 sinfo->filled |= STATION_INFO_RX_PACKETS;
1642 }
1643
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301644 if (vif->target_stats.tx_byte) {
1645 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001646 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301647 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001648 sinfo->filled |= STATION_INFO_TX_PACKETS;
1649 }
1650
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301651 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001652 sinfo->filled |= STATION_INFO_SIGNAL;
1653
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301654 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001655
1656 if (is_rate_legacy(rate)) {
1657 sinfo->txrate.legacy = rate / 100;
1658 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1659 if (sgi) {
1660 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1661 sinfo->txrate.mcs = mcs - 1;
1662 } else {
1663 sinfo->txrate.mcs = mcs;
1664 }
1665
1666 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1667 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1668 if (sgi) {
1669 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1670 sinfo->txrate.mcs = mcs - 1;
1671 } else {
1672 sinfo->txrate.mcs = mcs;
1673 }
1674
1675 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1676 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1677 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001678 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1679 "invalid rate from stats: %d\n", rate);
1680 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001681 return 0;
1682 }
1683
1684 sinfo->filled |= STATION_INFO_TX_BITRATE;
1685
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301686 if (test_bit(CONNECTED, &vif->flags) &&
1687 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301688 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001689 sinfo->filled |= STATION_INFO_BSS_PARAM;
1690 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301691 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1692 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001693 }
1694
Kalle Valobdcd8172011-07-18 00:22:30 +03001695 return 0;
1696}
1697
1698static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1699 struct cfg80211_pmksa *pmksa)
1700{
1701 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301702 struct ath6kl_vif *vif = netdev_priv(netdev);
1703
1704 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001705 pmksa->pmkid, true);
1706}
1707
1708static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1709 struct cfg80211_pmksa *pmksa)
1710{
1711 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301712 struct ath6kl_vif *vif = netdev_priv(netdev);
1713
1714 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001715 pmksa->pmkid, false);
1716}
1717
1718static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1719{
1720 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301721 struct ath6kl_vif *vif = netdev_priv(netdev);
1722
1723 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301724 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1725 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001726 return 0;
1727}
1728
Raja Mani6cb3c712011-11-07 22:52:45 +02001729static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1730{
1731 struct ath6kl_vif *vif;
1732 int ret, pos, left;
1733 u32 filter = 0;
1734 u16 i;
1735 u8 mask[WOW_MASK_SIZE];
1736
1737 vif = ath6kl_vif_first(ar);
1738 if (!vif)
1739 return -EIO;
1740
1741 if (!ath6kl_cfg80211_ready(vif))
1742 return -EIO;
1743
1744 if (!test_bit(CONNECTED, &vif->flags))
1745 return -EINVAL;
1746
1747 /* Clear existing WOW patterns */
1748 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1749 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1750 WOW_LIST_ID, i);
1751 /* Configure new WOW patterns */
1752 for (i = 0; i < wow->n_patterns; i++) {
1753
1754 /*
1755 * Convert given nl80211 specific mask value to equivalent
1756 * driver specific mask value and send it to the chip along
1757 * with patterns. For example, If the mask value defined in
1758 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1759 * then equivalent driver specific mask value is
1760 * "0xFF 0x00 0xFF 0x00".
1761 */
1762 memset(&mask, 0, sizeof(mask));
1763 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1764 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1765 mask[pos] = 0xFF;
1766 }
1767 /*
1768 * Note: Pattern's offset is not passed as part of wowlan
1769 * parameter from CFG layer. So it's always passed as ZERO
1770 * to the firmware. It means, given WOW patterns are always
1771 * matched from the first byte of received pkt in the firmware.
1772 */
1773 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1774 vif->fw_vif_idx, WOW_LIST_ID,
1775 wow->patterns[i].pattern_len,
1776 0 /* pattern offset */,
1777 wow->patterns[i].pattern, mask);
1778 if (ret)
1779 return ret;
1780 }
1781
1782 if (wow->disconnect)
1783 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1784
1785 if (wow->magic_pkt)
1786 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1787
1788 if (wow->gtk_rekey_failure)
1789 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1790
1791 if (wow->eap_identity_req)
1792 filter |= WOW_FILTER_OPTION_EAP_REQ;
1793
1794 if (wow->four_way_handshake)
1795 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1796
1797 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1798 ATH6KL_WOW_MODE_ENABLE,
1799 filter,
1800 WOW_HOST_REQ_DELAY);
1801 if (ret)
1802 return ret;
1803
1804 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1805 ATH6KL_HOST_MODE_ASLEEP);
1806 if (ret)
1807 return ret;
1808
1809 if (ar->tx_pending[ar->ctrl_ep]) {
1810 left = wait_event_interruptible_timeout(ar->event_wq,
1811 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1812 if (left == 0) {
1813 ath6kl_warn("clear wmi ctrl data timeout\n");
1814 ret = -ETIMEDOUT;
1815 } else if (left < 0) {
1816 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1817 ret = left;
1818 }
1819 }
1820
1821 return ret;
1822}
1823
1824static int ath6kl_wow_resume(struct ath6kl *ar)
1825{
1826 struct ath6kl_vif *vif;
1827 int ret;
1828
1829 vif = ath6kl_vif_first(ar);
1830 if (!vif)
1831 return -EIO;
1832
1833 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1834 ATH6KL_HOST_MODE_AWAKE);
1835 return ret;
1836}
1837
Kalle Valo52d81a62011-11-01 08:44:21 +02001838int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001839 enum ath6kl_cfg_suspend_mode mode,
1840 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001841{
1842 int ret;
1843
Kalle Valo52d81a62011-11-01 08:44:21 +02001844 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001845 case ATH6KL_CFG_SUSPEND_WOW:
1846
1847 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1848
1849 /* Flush all non control pkts in TX path */
1850 ath6kl_tx_data_cleanup(ar);
1851
1852 ret = ath6kl_wow_suspend(ar, wow);
1853 if (ret) {
1854 ath6kl_err("wow suspend failed: %d\n", ret);
1855 return ret;
1856 }
1857 ar->state = ATH6KL_STATE_WOW;
1858 break;
1859
Kalle Valo52d81a62011-11-01 08:44:21 +02001860 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001861
Kalle Valo7125f012011-12-13 14:51:37 +02001862 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001863
Kalle Valo52d81a62011-11-01 08:44:21 +02001864 /* save the current power mode before enabling power save */
1865 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1866
1867 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1868 if (ret) {
1869 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1870 ret);
1871 }
1872
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001873 ar->state = ATH6KL_STATE_DEEPSLEEP;
1874
Kalle Valo52d81a62011-11-01 08:44:21 +02001875 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001876
1877 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001878
Kalle Valo7125f012011-12-13 14:51:37 +02001879 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001880
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001881 if (ar->state == ATH6KL_STATE_OFF) {
1882 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1883 "suspend hw off, no action for cutpower\n");
1884 break;
1885 }
1886
1887 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1888
1889 ret = ath6kl_init_hw_stop(ar);
1890 if (ret) {
1891 ath6kl_warn("failed to stop hw during suspend: %d\n",
1892 ret);
1893 }
1894
1895 ar->state = ATH6KL_STATE_CUTPOWER;
1896
1897 break;
1898
Kalle Valo10509f92011-12-13 14:52:07 +02001899 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
1900 /*
1901 * Nothing needed for schedule scan, firmware is already in
1902 * wow mode and sleeping most of the time.
1903 */
1904 break;
1905
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001906 default:
1907 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001908 }
1909
1910 return 0;
1911}
1912
1913int ath6kl_cfg80211_resume(struct ath6kl *ar)
1914{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001915 int ret;
1916
1917 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001918 case ATH6KL_STATE_WOW:
1919 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1920
1921 ret = ath6kl_wow_resume(ar);
1922 if (ret) {
1923 ath6kl_warn("wow mode resume failed: %d\n", ret);
1924 return ret;
1925 }
1926
1927 ar->state = ATH6KL_STATE_ON;
1928 break;
1929
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001930 case ATH6KL_STATE_DEEPSLEEP:
1931 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1932 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1933 ar->wmi->saved_pwr_mode);
1934 if (ret) {
1935 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1936 ret);
1937 }
1938 }
1939
1940 ar->state = ATH6KL_STATE_ON;
1941
1942 break;
1943
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001944 case ATH6KL_STATE_CUTPOWER:
1945 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1946
1947 ret = ath6kl_init_hw_start(ar);
1948 if (ret) {
1949 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1950 return ret;
1951 }
Raja Manid7c44e02011-11-07 22:52:46 +02001952 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001953
Kalle Valo10509f92011-12-13 14:52:07 +02001954 case ATH6KL_STATE_SCHED_SCAN:
1955 break;
1956
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001957 default:
1958 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001959 }
1960
1961 return 0;
1962}
1963
Kalle Valoabcb3442011-07-22 08:26:20 +03001964#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001965
1966/* hif layer decides what suspend mode to use */
1967static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001968 struct cfg80211_wowlan *wow)
1969{
1970 struct ath6kl *ar = wiphy_priv(wiphy);
1971
Raja Mani0f60e9f2011-11-07 22:52:45 +02001972 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001973}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001974
Kalle Valo52d81a62011-11-01 08:44:21 +02001975static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001976{
1977 struct ath6kl *ar = wiphy_priv(wiphy);
1978
1979 return ath6kl_hif_resume(ar);
1980}
Raja Mania918fb32011-11-07 22:52:46 +02001981
1982/*
1983 * FIXME: WOW suspend mode is selected if the host sdio controller supports
1984 * both sdio irq wake up and keep power. The target pulls sdio data line to
1985 * wake up the host when WOW pattern matches. This causes sdio irq handler
1986 * is being called in the host side which internally hits ath6kl's RX path.
1987 *
1988 * Since sdio interrupt is not disabled, RX path executes even before
1989 * the host executes the actual resume operation from PM module.
1990 *
1991 * In the current scenario, WOW resume should happen before start processing
1992 * any data from the target. So It's required to perform WOW resume in RX path.
1993 * Ideally we should perform WOW resume only in the actual platform
1994 * resume path. This area needs bit rework to avoid WOW resume in RX path.
1995 *
1996 * ath6kl_check_wow_status() is called from ath6kl_rx().
1997 */
1998void ath6kl_check_wow_status(struct ath6kl *ar)
1999{
2000 if (ar->state == ATH6KL_STATE_WOW)
2001 ath6kl_cfg80211_resume(ar);
2002}
2003
2004#else
2005
2006void ath6kl_check_wow_status(struct ath6kl *ar)
2007{
2008}
Kalle Valoabcb3442011-07-22 08:26:20 +03002009#endif
2010
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002011static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
2012 struct ieee80211_channel *chan,
2013 enum nl80211_channel_type channel_type)
2014{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302015 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002016
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302017 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002018 return -EIO;
2019
2020 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
2021 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302022 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002023
2024 return 0;
2025}
2026
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002027static bool ath6kl_is_p2p_ie(const u8 *pos)
2028{
2029 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2030 pos[2] == 0x50 && pos[3] == 0x6f &&
2031 pos[4] == 0x9a && pos[5] == 0x09;
2032}
2033
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302034static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2035 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002036{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302037 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002038 const u8 *pos;
2039 u8 *buf = NULL;
2040 size_t len = 0;
2041 int ret;
2042
2043 /*
2044 * Filter out P2P IE(s) since they will be included depending on
2045 * the Probe Request frame in ath6kl_send_go_probe_resp().
2046 */
2047
2048 if (ies && ies_len) {
2049 buf = kmalloc(ies_len, GFP_KERNEL);
2050 if (buf == NULL)
2051 return -ENOMEM;
2052 pos = ies;
2053 while (pos + 1 < ies + ies_len) {
2054 if (pos + 2 + pos[1] > ies + ies_len)
2055 break;
2056 if (!ath6kl_is_p2p_ie(pos)) {
2057 memcpy(buf + len, pos, 2 + pos[1]);
2058 len += 2 + pos[1];
2059 }
2060 pos += 2 + pos[1];
2061 }
2062 }
2063
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302064 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2065 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002066 kfree(buf);
2067 return ret;
2068}
2069
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002070static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2071 struct beacon_parameters *info, bool add)
2072{
2073 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302074 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002075 struct ieee80211_mgmt *mgmt;
2076 u8 *ies;
2077 int ies_len;
2078 struct wmi_connect_cmd p;
2079 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302080 int i, ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002081
2082 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2083
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302084 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002085 return -EIO;
2086
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302087 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002088 return -EOPNOTSUPP;
2089
2090 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302091 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2092 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002093 info->beacon_ies,
2094 info->beacon_ies_len);
2095 if (res)
2096 return res;
2097 }
2098 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302099 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002100 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002101 if (res)
2102 return res;
2103 }
2104 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302105 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2106 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002107 info->assocresp_ies,
2108 info->assocresp_ies_len);
2109 if (res)
2110 return res;
2111 }
2112
2113 if (!add)
2114 return 0;
2115
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002116 ar->ap_mode_bkey.valid = false;
2117
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002118 /* TODO:
2119 * info->interval
2120 * info->dtim_period
2121 */
2122
2123 if (info->head == NULL)
2124 return -EINVAL;
2125 mgmt = (struct ieee80211_mgmt *) info->head;
2126 ies = mgmt->u.beacon.variable;
2127 if (ies > info->head + info->head_len)
2128 return -EINVAL;
2129 ies_len = info->head + info->head_len - ies;
2130
2131 if (info->ssid == NULL)
2132 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302133 memcpy(vif->ssid, info->ssid, info->ssid_len);
2134 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002135 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2136 return -EOPNOTSUPP; /* TODO */
2137
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302138 ret = ath6kl_set_auth_type(vif, info->auth_type);
2139 if (ret)
2140 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002141
2142 memset(&p, 0, sizeof(p));
2143
2144 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2145 switch (info->crypto.akm_suites[i]) {
2146 case WLAN_AKM_SUITE_8021X:
2147 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2148 p.auth_mode |= WPA_AUTH;
2149 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2150 p.auth_mode |= WPA2_AUTH;
2151 break;
2152 case WLAN_AKM_SUITE_PSK:
2153 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2154 p.auth_mode |= WPA_PSK_AUTH;
2155 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2156 p.auth_mode |= WPA2_PSK_AUTH;
2157 break;
2158 }
2159 }
2160 if (p.auth_mode == 0)
2161 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302162 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002163
2164 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2165 switch (info->crypto.ciphers_pairwise[i]) {
2166 case WLAN_CIPHER_SUITE_WEP40:
2167 case WLAN_CIPHER_SUITE_WEP104:
2168 p.prwise_crypto_type |= WEP_CRYPT;
2169 break;
2170 case WLAN_CIPHER_SUITE_TKIP:
2171 p.prwise_crypto_type |= TKIP_CRYPT;
2172 break;
2173 case WLAN_CIPHER_SUITE_CCMP:
2174 p.prwise_crypto_type |= AES_CRYPT;
2175 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002176 case WLAN_CIPHER_SUITE_SMS4:
2177 p.prwise_crypto_type |= WAPI_CRYPT;
2178 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002179 }
2180 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002181 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002182 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302183 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002184 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302185 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002186
2187 switch (info->crypto.cipher_group) {
2188 case WLAN_CIPHER_SUITE_WEP40:
2189 case WLAN_CIPHER_SUITE_WEP104:
2190 p.grp_crypto_type = WEP_CRYPT;
2191 break;
2192 case WLAN_CIPHER_SUITE_TKIP:
2193 p.grp_crypto_type = TKIP_CRYPT;
2194 break;
2195 case WLAN_CIPHER_SUITE_CCMP:
2196 p.grp_crypto_type = AES_CRYPT;
2197 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002198 case WLAN_CIPHER_SUITE_SMS4:
2199 p.grp_crypto_type = WAPI_CRYPT;
2200 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002201 default:
2202 p.grp_crypto_type = NONE_CRYPT;
2203 break;
2204 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302205 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002206
2207 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302208 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002209
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302210 p.ssid_len = vif->ssid_len;
2211 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2212 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302213 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002214
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002215 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2216 p.nw_subtype = SUBTYPE_P2PGO;
2217 } else {
2218 /*
2219 * Due to firmware limitation, it is not possible to
2220 * do P2P mgmt operations in AP mode
2221 */
2222 p.nw_subtype = SUBTYPE_NONE;
2223 }
2224
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302225 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002226 if (res < 0)
2227 return res;
2228
2229 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002230}
2231
2232static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2233 struct beacon_parameters *info)
2234{
2235 return ath6kl_ap_beacon(wiphy, dev, info, true);
2236}
2237
2238static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2239 struct beacon_parameters *info)
2240{
2241 return ath6kl_ap_beacon(wiphy, dev, info, false);
2242}
2243
2244static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2245{
2246 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302247 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002248
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302249 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002250 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302251 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002252 return -ENOTCONN;
2253
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302254 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302255 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002256
2257 return 0;
2258}
2259
Jouni Malinen23875132011-08-30 21:57:53 +03002260static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2261 u8 *mac, struct station_parameters *params)
2262{
2263 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302264 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002265
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302266 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002267 return -EOPNOTSUPP;
2268
2269 /* Use this only for authorizing/unauthorizing a station */
2270 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2271 return -EOPNOTSUPP;
2272
2273 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302274 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2275 WMI_AP_MLME_AUTHORIZE, mac, 0);
2276 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2277 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002278}
2279
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002280static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2281 struct net_device *dev,
2282 struct ieee80211_channel *chan,
2283 enum nl80211_channel_type channel_type,
2284 unsigned int duration,
2285 u64 *cookie)
2286{
2287 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302288 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002289 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002290
2291 /* TODO: if already pending or ongoing remain-on-channel,
2292 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002293 id = ++vif->last_roc_id;
2294 if (id == 0) {
2295 /* Do not use 0 as the cookie value */
2296 id = ++vif->last_roc_id;
2297 }
2298 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002299
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302300 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2301 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002302}
2303
2304static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2305 struct net_device *dev,
2306 u64 cookie)
2307{
2308 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302309 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002310
Jouni Malinen10522612011-10-27 16:00:13 +03002311 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002312 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002313 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002314
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302315 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002316}
2317
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302318static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2319 const u8 *buf, size_t len,
2320 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002321{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302322 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002323 const u8 *pos;
2324 u8 *p2p;
2325 int p2p_len;
2326 int ret;
2327 const struct ieee80211_mgmt *mgmt;
2328
2329 mgmt = (const struct ieee80211_mgmt *) buf;
2330
2331 /* Include P2P IE(s) from the frame generated in user space. */
2332
2333 p2p = kmalloc(len, GFP_KERNEL);
2334 if (p2p == NULL)
2335 return -ENOMEM;
2336 p2p_len = 0;
2337
2338 pos = mgmt->u.probe_resp.variable;
2339 while (pos + 1 < buf + len) {
2340 if (pos + 2 + pos[1] > buf + len)
2341 break;
2342 if (ath6kl_is_p2p_ie(pos)) {
2343 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2344 p2p_len += 2 + pos[1];
2345 }
2346 pos += 2 + pos[1];
2347 }
2348
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302349 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2350 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002351 kfree(p2p);
2352 return ret;
2353}
2354
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002355static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2356 struct ieee80211_channel *chan, bool offchan,
2357 enum nl80211_channel_type channel_type,
2358 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002359 const u8 *buf, size_t len, bool no_cck,
2360 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002361{
2362 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302363 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002364 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002365 const struct ieee80211_mgmt *mgmt;
2366
2367 mgmt = (const struct ieee80211_mgmt *) buf;
2368 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302369 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002370 ieee80211_is_probe_resp(mgmt->frame_control)) {
2371 /*
2372 * Send Probe Response frame in AP mode using a separate WMI
2373 * command to allow the target to fill in the generic IEs.
2374 */
2375 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302376 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002377 chan->center_freq);
2378 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002379
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302380 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002381 if (id == 0) {
2382 /*
2383 * 0 is a reserved value in the WMI command and shall not be
2384 * used for the command.
2385 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302386 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002387 }
2388
2389 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002390
2391 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
2392 ar->fw_capabilities)) {
2393 /*
2394 * If capable of doing P2P mgmt operations using
2395 * station interface, send additional information like
2396 * supported rates to advertise and xmit rates for
2397 * probe requests
2398 */
2399 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
2400 chan->center_freq, wait,
2401 buf, len, no_cck);
2402 } else {
2403 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2404 chan->center_freq, wait,
2405 buf, len);
2406 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002407}
2408
Jouni Malinenae32c302011-08-30 21:58:01 +03002409static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2410 struct net_device *dev,
2411 u16 frame_type, bool reg)
2412{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302413 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002414
2415 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2416 __func__, frame_type, reg);
2417 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2418 /*
2419 * Note: This notification callback is not allowed to sleep, so
2420 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2421 * hardcode target to report Probe Request frames all the time.
2422 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302423 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002424 }
2425}
2426
Kalle Valo10509f92011-12-13 14:52:07 +02002427static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2428 struct net_device *dev,
2429 struct cfg80211_sched_scan_request *request)
2430{
2431 struct ath6kl *ar = ath6kl_priv(dev);
2432 struct ath6kl_vif *vif = netdev_priv(dev);
2433 u16 interval;
2434 int ret;
2435 u8 i;
2436
2437 if (ar->state != ATH6KL_STATE_ON)
2438 return -EIO;
2439
2440 if (vif->sme_state != SME_DISCONNECTED)
2441 return -EBUSY;
2442
2443 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2444 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2445 i, DISABLE_SSID_FLAG,
2446 0, NULL);
2447 }
2448
2449 /* fw uses seconds, also make sure that it's >0 */
2450 interval = max_t(u16, 1, request->interval / 1000);
2451
2452 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2453 interval, interval,
2454 10, 0, 0, 0, 3, 0, 0, 0);
2455
2456 if (request->n_ssids && request->ssids[0].ssid_len) {
2457 for (i = 0; i < request->n_ssids; i++) {
2458 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2459 i, SPECIFIC_SSID_FLAG,
2460 request->ssids[i].ssid_len,
2461 request->ssids[i].ssid);
2462 }
2463 }
2464
2465 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2466 ATH6KL_WOW_MODE_ENABLE,
2467 WOW_FILTER_SSID,
2468 WOW_HOST_REQ_DELAY);
2469 if (ret) {
2470 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
2471 return ret;
2472 }
2473
2474 /* this also clears IE in fw if it's not set */
2475 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2476 WMI_FRAME_PROBE_REQ,
2477 request->ie, request->ie_len);
2478 if (ret) {
2479 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
2480 ret);
2481 return ret;
2482 }
2483
2484 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2485 ATH6KL_HOST_MODE_ASLEEP);
2486 if (ret) {
2487 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
2488 ret);
2489 return ret;
2490 }
2491
2492 ar->state = ATH6KL_STATE_SCHED_SCAN;
2493
2494 return ret;
2495}
2496
2497static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
2498 struct net_device *dev)
2499{
2500 struct ath6kl_vif *vif = netdev_priv(dev);
2501 bool stopped;
2502
2503 stopped = __ath6kl_cfg80211_sscan_stop(vif);
2504
2505 if (!stopped)
2506 return -EIO;
2507
2508 return 0;
2509}
2510
Jouni Malinenf80574a2011-08-30 21:58:04 +03002511static const struct ieee80211_txrx_stypes
2512ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2513 [NL80211_IFTYPE_STATION] = {
2514 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2515 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2516 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2517 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2518 },
2519 [NL80211_IFTYPE_P2P_CLIENT] = {
2520 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2521 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2522 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2523 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2524 },
2525 [NL80211_IFTYPE_P2P_GO] = {
2526 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2527 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2528 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2529 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2530 },
2531};
2532
Kalle Valobdcd8172011-07-18 00:22:30 +03002533static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302534 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2535 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002536 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2537 .scan = ath6kl_cfg80211_scan,
2538 .connect = ath6kl_cfg80211_connect,
2539 .disconnect = ath6kl_cfg80211_disconnect,
2540 .add_key = ath6kl_cfg80211_add_key,
2541 .get_key = ath6kl_cfg80211_get_key,
2542 .del_key = ath6kl_cfg80211_del_key,
2543 .set_default_key = ath6kl_cfg80211_set_default_key,
2544 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2545 .set_tx_power = ath6kl_cfg80211_set_txpower,
2546 .get_tx_power = ath6kl_cfg80211_get_txpower,
2547 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2548 .join_ibss = ath6kl_cfg80211_join_ibss,
2549 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2550 .get_station = ath6kl_get_station,
2551 .set_pmksa = ath6kl_set_pmksa,
2552 .del_pmksa = ath6kl_del_pmksa,
2553 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002554 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002555#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002556 .suspend = __ath6kl_cfg80211_suspend,
2557 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002558#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002559 .set_channel = ath6kl_set_channel,
2560 .add_beacon = ath6kl_add_beacon,
2561 .set_beacon = ath6kl_set_beacon,
2562 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002563 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002564 .remain_on_channel = ath6kl_remain_on_channel,
2565 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002566 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002567 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valo10509f92011-12-13 14:52:07 +02002568 .sched_scan_start = ath6kl_cfg80211_sscan_start,
2569 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Kalle Valobdcd8172011-07-18 00:22:30 +03002570};
2571
Kalle Valo7125f012011-12-13 14:51:37 +02002572void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02002573{
Kalle Valo10509f92011-12-13 14:52:07 +02002574 ath6kl_cfg80211_sscan_disable(vif);
2575
Kalle Valoec4b7f62011-11-01 08:44:04 +02002576 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02002577 case SME_DISCONNECTED:
2578 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02002579 case SME_CONNECTING:
2580 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2581 NULL, 0,
2582 WLAN_STATUS_UNSPECIFIED_FAILURE,
2583 GFP_KERNEL);
2584 break;
2585 case SME_CONNECTED:
Kalle Valoec4b7f62011-11-01 08:44:04 +02002586 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2587 break;
2588 }
2589
2590 if (test_bit(CONNECTED, &vif->flags) ||
2591 test_bit(CONNECT_PEND, &vif->flags))
Kalle Valo7125f012011-12-13 14:51:37 +02002592 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002593
2594 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002595 clear_bit(CONNECTED, &vif->flags);
2596 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002597
2598 /* disable scanning */
Kalle Valo7125f012011-12-13 14:51:37 +02002599 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
2600 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
2601 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02002602
2603 ath6kl_cfg80211_scan_complete_event(vif, true);
2604}
2605
Kalle Valo7125f012011-12-13 14:51:37 +02002606void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
2607{
2608 struct ath6kl_vif *vif;
2609
2610 vif = ath6kl_vif_first(ar);
2611 if (!vif) {
2612 /* save the current power mode before enabling power save */
2613 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2614
2615 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2616 ath6kl_warn("ath6kl_deep_sleep_enable: "
2617 "wmi_powermode_cmd failed\n");
2618 return;
2619 }
2620
2621 /*
2622 * FIXME: we should take ar->list_lock to protect changes in the
2623 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
2624 * sleeps.
2625 */
2626 list_for_each_entry(vif, &ar->vif_list, list)
2627 ath6kl_cfg80211_stop(vif);
2628}
2629
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302630struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002631{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002632 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302633 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302634 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002635
2636 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302637 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302638
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302639 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002640 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002641 return NULL;
2642 }
2643
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302644 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan774439a2011-11-18 10:05:26 +05302645 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302646 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302647 ar->dev = dev;
2648
Kalle Valo71f96ee2011-11-14 19:31:30 +02002649 ar->vif_max = 1;
2650
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302651 ar->max_norm_iface = 1;
2652
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302653 spin_lock_init(&ar->lock);
2654 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302655 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302656
2657 init_waitqueue_head(&ar->event_wq);
2658 sema_init(&ar->sem, 1);
2659
2660 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302661 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302662
2663 clear_bit(WMI_ENABLED, &ar->flag);
2664 clear_bit(SKIP_SCAN, &ar->flag);
2665 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2666
2667 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2668 ar->listen_intvl_b = 0;
2669 ar->tx_pwr = 0;
2670
2671 ar->intra_bss = 1;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302672 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2673
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002674 ar->state = ATH6KL_STATE_OFF;
2675
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302676 memset((u8 *)ar->sta_list, 0,
2677 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2678
2679 /* Init the PS queues */
2680 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2681 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2682 skb_queue_head_init(&ar->sta_list[ctr].psq);
2683 }
2684
2685 skb_queue_head_init(&ar->mcastpsq);
2686
2687 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2688
2689 return ar;
2690}
2691
2692int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2693{
2694 struct wiphy *wiphy = ar->wiphy;
2695 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002696
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302697 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002698
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302699 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002700
Kalle Valobdcd8172011-07-18 00:22:30 +03002701 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302702 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002703
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302704 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302705 BIT(NL80211_IFTYPE_ADHOC) |
2706 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002707 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302708 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302709 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002710 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302711
Kalle Valobdcd8172011-07-18 00:22:30 +03002712 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302713 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2714 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2715 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2716 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2717 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002718
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302719 wiphy->cipher_suites = cipher_suites;
2720 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002721
Raja Manieae9e062011-11-07 22:52:46 +02002722 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2723 WIPHY_WOWLAN_DISCONNECT |
2724 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2725 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2726 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2727 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2728 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2729 wiphy->wowlan.pattern_min_len = 1;
2730 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2731
Kalle Valo10509f92011-12-13 14:52:07 +02002732 wiphy->max_sched_scan_ssids = 10;
2733
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302734 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002735 if (ret < 0) {
2736 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302737 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002738 }
2739
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302740 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002741}
2742
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302743static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002744{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302745 vif->aggr_cntxt = aggr_init(vif->ndev);
2746 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302747 ath6kl_err("failed to initialize aggr\n");
2748 return -ENOMEM;
2749 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002750
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302751 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302752 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02002753 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
2754 (unsigned long) vif);
2755
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302756 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302757 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302758
2759 return 0;
2760}
2761
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302762void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302763{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302764 struct ath6kl *ar = vif->ar;
2765
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302766 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302767
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302768 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2769
2770 if (vif->nw_type == ADHOC_NETWORK)
2771 ar->ibss_if_active = false;
2772
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302773 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302774
2775 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302776}
2777
2778struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302779 enum nl80211_iftype type, u8 fw_vif_idx,
2780 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302781{
2782 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302783 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302784
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302785 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302786 if (!ndev)
2787 return NULL;
2788
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302789 vif = netdev_priv(ndev);
2790 ndev->ieee80211_ptr = &vif->wdev;
2791 vif->wdev.wiphy = ar->wiphy;
2792 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302793 vif->ndev = ndev;
2794 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2795 vif->wdev.netdev = ndev;
2796 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302797 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302798 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302799
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302800 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2801 if (fw_vif_idx != 0)
2802 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2803 0x2;
2804
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302805 init_netdev(ndev);
2806
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302807 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302808
2809 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302810 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302811 goto err;
2812
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302813 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302814 goto err;
2815
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302816 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302817 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302818 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302819 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302820 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302821
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302822 if (type == NL80211_IFTYPE_ADHOC)
2823 ar->ibss_if_active = true;
2824
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302825 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302826 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302827 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302828
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302829 return ndev;
2830
2831err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302832 aggr_module_destroy(vif->aggr_cntxt);
2833 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302834 return NULL;
2835}
2836
2837void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2838{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302839 wiphy_unregister(ar->wiphy);
2840 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002841}