blob: 7ff9806de50b8213b9e1852a0eb5da0717fea4e3 [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
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040017#include <linux/moduleparam.h>
Raja Manic08631c2011-12-16 14:24:24 +053018#include <linux/inetdevice.h>
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040019
Kalle Valobdcd8172011-07-18 00:22:30 +030020#include "core.h"
21#include "cfg80211.h"
22#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030023#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030024#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030025
26#define RATETAB_ENT(_rate, _rateid, _flags) { \
27 .bitrate = (_rate), \
28 .flags = (_flags), \
29 .hw_value = (_rateid), \
30}
31
32#define CHAN2G(_channel, _freq, _flags) { \
33 .band = IEEE80211_BAND_2GHZ, \
34 .hw_value = (_channel), \
35 .center_freq = (_freq), \
36 .flags = (_flags), \
37 .max_antenna_gain = 0, \
38 .max_power = 30, \
39}
40
41#define CHAN5G(_channel, _flags) { \
42 .band = IEEE80211_BAND_5GHZ, \
43 .hw_value = (_channel), \
44 .center_freq = 5000 + (5 * (_channel)), \
45 .flags = (_flags), \
46 .max_antenna_gain = 0, \
47 .max_power = 30, \
48}
49
50static struct ieee80211_rate ath6kl_rates[] = {
51 RATETAB_ENT(10, 0x1, 0),
52 RATETAB_ENT(20, 0x2, 0),
53 RATETAB_ENT(55, 0x4, 0),
54 RATETAB_ENT(110, 0x8, 0),
55 RATETAB_ENT(60, 0x10, 0),
56 RATETAB_ENT(90, 0x20, 0),
57 RATETAB_ENT(120, 0x40, 0),
58 RATETAB_ENT(180, 0x80, 0),
59 RATETAB_ENT(240, 0x100, 0),
60 RATETAB_ENT(360, 0x200, 0),
61 RATETAB_ENT(480, 0x400, 0),
62 RATETAB_ENT(540, 0x800, 0),
63};
64
65#define ath6kl_a_rates (ath6kl_rates + 4)
66#define ath6kl_a_rates_size 8
67#define ath6kl_g_rates (ath6kl_rates + 0)
68#define ath6kl_g_rates_size 12
69
70static struct ieee80211_channel ath6kl_2ghz_channels[] = {
71 CHAN2G(1, 2412, 0),
72 CHAN2G(2, 2417, 0),
73 CHAN2G(3, 2422, 0),
74 CHAN2G(4, 2427, 0),
75 CHAN2G(5, 2432, 0),
76 CHAN2G(6, 2437, 0),
77 CHAN2G(7, 2442, 0),
78 CHAN2G(8, 2447, 0),
79 CHAN2G(9, 2452, 0),
80 CHAN2G(10, 2457, 0),
81 CHAN2G(11, 2462, 0),
82 CHAN2G(12, 2467, 0),
83 CHAN2G(13, 2472, 0),
84 CHAN2G(14, 2484, 0),
85};
86
87static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
88 CHAN5G(34, 0), CHAN5G(36, 0),
89 CHAN5G(38, 0), CHAN5G(40, 0),
90 CHAN5G(42, 0), CHAN5G(44, 0),
91 CHAN5G(46, 0), CHAN5G(48, 0),
92 CHAN5G(52, 0), CHAN5G(56, 0),
93 CHAN5G(60, 0), CHAN5G(64, 0),
94 CHAN5G(100, 0), CHAN5G(104, 0),
95 CHAN5G(108, 0), CHAN5G(112, 0),
96 CHAN5G(116, 0), CHAN5G(120, 0),
97 CHAN5G(124, 0), CHAN5G(128, 0),
98 CHAN5G(132, 0), CHAN5G(136, 0),
99 CHAN5G(140, 0), CHAN5G(149, 0),
100 CHAN5G(153, 0), CHAN5G(157, 0),
101 CHAN5G(161, 0), CHAN5G(165, 0),
102 CHAN5G(184, 0), CHAN5G(188, 0),
103 CHAN5G(192, 0), CHAN5G(196, 0),
104 CHAN5G(200, 0), CHAN5G(204, 0),
105 CHAN5G(208, 0), CHAN5G(212, 0),
106 CHAN5G(216, 0),
107};
108
109static struct ieee80211_supported_band ath6kl_band_2ghz = {
110 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
111 .channels = ath6kl_2ghz_channels,
112 .n_bitrates = ath6kl_g_rates_size,
113 .bitrates = ath6kl_g_rates,
114};
115
116static struct ieee80211_supported_band ath6kl_band_5ghz = {
117 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
118 .channels = ath6kl_5ghz_a_channels,
119 .n_bitrates = ath6kl_a_rates_size,
120 .bitrates = ath6kl_a_rates,
121};
122
Jouni Malinen837cb972011-10-11 17:31:57 +0300123#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
124
Kalle Valo10509f92011-12-13 14:52:07 +0200125/* returns true if scheduled scan was stopped */
126static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
127{
128 struct ath6kl *ar = vif->ar;
129
130 if (ar->state != ATH6KL_STATE_SCHED_SCAN)
131 return false;
132
133 del_timer_sync(&vif->sched_scan_timer);
134
135 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
136 ATH6KL_HOST_MODE_AWAKE);
137
138 ar->state = ATH6KL_STATE_ON;
139
140 return true;
141}
142
143static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
144{
145 struct ath6kl *ar = vif->ar;
146 bool stopped;
147
148 stopped = __ath6kl_cfg80211_sscan_stop(vif);
149
150 if (!stopped)
151 return;
152
153 cfg80211_sched_scan_stopped(ar->wiphy);
154}
155
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530156static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300157 enum nl80211_wpa_versions wpa_version)
158{
159 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
160
161 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530162 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300163 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530164 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530166 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300167 } else {
168 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
169 return -ENOTSUPP;
170 }
171
172 return 0;
173}
174
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530175static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300176 enum nl80211_auth_type auth_type)
177{
Kalle Valobdcd8172011-07-18 00:22:30 +0300178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
179
180 switch (auth_type) {
181 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530182 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300183 break;
184 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530185 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300186 break;
187 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530188 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300189 break;
190
191 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530192 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300193 break;
194
195 default:
196 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
197 return -ENOTSUPP;
198 }
199
200 return 0;
201}
202
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530203static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300204{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530205 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
206 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
207 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300208
209 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
210 __func__, cipher, ucast);
211
212 switch (cipher) {
213 case 0:
214 /* our own hack to use value 0 as no crypto used */
215 *ar_cipher = NONE_CRYPT;
216 *ar_cipher_len = 0;
217 break;
218 case WLAN_CIPHER_SUITE_WEP40:
219 *ar_cipher = WEP_CRYPT;
220 *ar_cipher_len = 5;
221 break;
222 case WLAN_CIPHER_SUITE_WEP104:
223 *ar_cipher = WEP_CRYPT;
224 *ar_cipher_len = 13;
225 break;
226 case WLAN_CIPHER_SUITE_TKIP:
227 *ar_cipher = TKIP_CRYPT;
228 *ar_cipher_len = 0;
229 break;
230 case WLAN_CIPHER_SUITE_CCMP:
231 *ar_cipher = AES_CRYPT;
232 *ar_cipher_len = 0;
233 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200234 case WLAN_CIPHER_SUITE_SMS4:
235 *ar_cipher = WAPI_CRYPT;
236 *ar_cipher_len = 0;
237 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300238 default:
239 ath6kl_err("cipher 0x%x not supported\n", cipher);
240 return -ENOTSUPP;
241 }
242
243 return 0;
244}
245
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530246static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300247{
248 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
249
250 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530251 if (vif->auth_mode == WPA_AUTH)
252 vif->auth_mode = WPA_PSK_AUTH;
253 else if (vif->auth_mode == WPA2_AUTH)
254 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300255 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530256 if (vif->auth_mode == WPA_AUTH)
257 vif->auth_mode = WPA_AUTH_CCKM;
258 else if (vif->auth_mode == WPA2_AUTH)
259 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300260 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530261 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300262 }
263}
264
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530265static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300266{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530267 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530268
Kalle Valobdcd8172011-07-18 00:22:30 +0300269 if (!test_bit(WMI_READY, &ar->flag)) {
270 ath6kl_err("wmi is not ready\n");
271 return false;
272 }
273
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530274 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300275 ath6kl_err("wlan disabled\n");
276 return false;
277 }
278
279 return true;
280}
281
Kevin Fang6981ffd2011-10-07 08:51:19 +0800282static bool ath6kl_is_wpa_ie(const u8 *pos)
283{
284 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
285 pos[2] == 0x00 && pos[3] == 0x50 &&
286 pos[4] == 0xf2 && pos[5] == 0x01;
287}
288
289static bool ath6kl_is_rsn_ie(const u8 *pos)
290{
291 return pos[0] == WLAN_EID_RSN;
292}
293
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700294static bool ath6kl_is_wps_ie(const u8 *pos)
295{
296 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
297 pos[1] >= 4 &&
298 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
299 pos[5] == 0x04);
300}
301
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530302static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
303 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800304{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530305 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800306 const u8 *pos;
307 u8 *buf = NULL;
308 size_t len = 0;
309 int ret;
310
311 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700312 * Clear previously set flag
313 */
314
315 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
316
317 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800318 * Filter out RSN/WPA IE(s)
319 */
320
321 if (ies && ies_len) {
322 buf = kmalloc(ies_len, GFP_KERNEL);
323 if (buf == NULL)
324 return -ENOMEM;
325 pos = ies;
326
327 while (pos + 1 < ies + ies_len) {
328 if (pos + 2 + pos[1] > ies + ies_len)
329 break;
330 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
331 memcpy(buf + len, pos, 2 + pos[1]);
332 len += 2 + pos[1];
333 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700334
335 if (ath6kl_is_wps_ie(pos))
336 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
337
Kevin Fang6981ffd2011-10-07 08:51:19 +0800338 pos += 2 + pos[1];
339 }
340 }
341
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530342 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
343 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800344 kfree(buf);
345 return ret;
346}
347
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530348static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
349{
350 switch (type) {
351 case NL80211_IFTYPE_STATION:
352 *nw_type = INFRA_NETWORK;
353 break;
354 case NL80211_IFTYPE_ADHOC:
355 *nw_type = ADHOC_NETWORK;
356 break;
357 case NL80211_IFTYPE_AP:
358 *nw_type = AP_NETWORK;
359 break;
360 case NL80211_IFTYPE_P2P_CLIENT:
361 *nw_type = INFRA_NETWORK;
362 break;
363 case NL80211_IFTYPE_P2P_GO:
364 *nw_type = AP_NETWORK;
365 break;
366 default:
367 ath6kl_err("invalid interface type %u\n", type);
368 return -ENOTSUPP;
369 }
370
371 return 0;
372}
373
374static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
375 u8 *if_idx, u8 *nw_type)
376{
377 int i;
378
379 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
380 return false;
381
382 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
383 ar->num_vif))
384 return false;
385
386 if (type == NL80211_IFTYPE_STATION ||
387 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200388 for (i = 0; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530389 if ((ar->avail_idx_map >> i) & BIT(0)) {
390 *if_idx = i;
391 return true;
392 }
393 }
394 }
395
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530396 if (type == NL80211_IFTYPE_P2P_CLIENT ||
397 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200398 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530399 if ((ar->avail_idx_map >> i) & BIT(0)) {
400 *if_idx = i;
401 return true;
402 }
403 }
404 }
405
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530406 return false;
407}
408
Kalle Valobdcd8172011-07-18 00:22:30 +0300409static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
410 struct cfg80211_connect_params *sme)
411{
412 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530413 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300414 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800415 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Kalle Valobdcd8172011-07-18 00:22:30 +0300416
Kalle Valo10509f92011-12-13 14:52:07 +0200417 ath6kl_cfg80211_sscan_disable(vif);
418
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530419 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300420
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530421 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300422 return -EIO;
423
424 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
425 ath6kl_err("destroy in progress\n");
426 return -EBUSY;
427 }
428
429 if (test_bit(SKIP_SCAN, &ar->flag) &&
430 ((sme->channel && sme->channel->center_freq == 0) ||
431 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
432 ath6kl_err("SkipScan: channel or bssid invalid\n");
433 return -EINVAL;
434 }
435
436 if (down_interruptible(&ar->sem)) {
437 ath6kl_err("busy, couldn't get access\n");
438 return -ERESTARTSYS;
439 }
440
441 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
442 ath6kl_err("busy, destroy in progress\n");
443 up(&ar->sem);
444 return -EBUSY;
445 }
446
447 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
448 /*
449 * sleep until the command queue drains
450 */
451 wait_event_interruptible_timeout(ar->event_wq,
452 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
453 WMI_TIMEOUT);
454 if (signal_pending(current)) {
455 ath6kl_err("cmd queue drain timeout\n");
456 up(&ar->sem);
457 return -EINTR;
458 }
459 }
460
Jouni Malinen6e786cb2011-12-15 14:16:00 +0200461 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
462 if (status) {
463 up(&ar->sem);
464 return status;
465 }
466
467 if (sme->ie == NULL || sme->ie_len == 0)
Raja Mani542c5192011-11-15 14:14:56 +0530468 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800469
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530470 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530471 vif->ssid_len == sme->ssid_len &&
472 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530473 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530474 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
475 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530476 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300477
478 up(&ar->sem);
479 if (status) {
480 ath6kl_err("wmi_reconnect_cmd failed\n");
481 return -EIO;
482 }
483 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530484 } else if (vif->ssid_len == sme->ssid_len &&
485 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530486 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300487 }
488
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530489 memset(vif->ssid, 0, sizeof(vif->ssid));
490 vif->ssid_len = sme->ssid_len;
491 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300492
493 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530494 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300495
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530496 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300497 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530498 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300499
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530500 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300501
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530502 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300503 if (status) {
504 up(&ar->sem);
505 return status;
506 }
507
508 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530509 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300510 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530511 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300512
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530513 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300514
515 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530516 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300517
518 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530519 (vif->auth_mode == NONE_AUTH) &&
520 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300521 struct ath6kl_key *key = NULL;
522
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530523 if (sme->key_idx > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300524 ath6kl_err("key index %d out of bounds\n",
525 sme->key_idx);
526 up(&ar->sem);
527 return -ENOENT;
528 }
529
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530530 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300531 key->key_len = sme->key_len;
532 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530533 key->cipher = vif->prwise_crypto;
534 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300535
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530536 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530537 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300538 GROUP_USAGE | TX_USAGE,
539 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200540 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300541 key->key, KEY_OP_INIT_VAL, NULL,
542 NO_SYNC_WMIFLAG);
543 }
544
545 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530546 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530547 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
548 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300549 ath6kl_err("couldn't set bss filtering\n");
550 up(&ar->sem);
551 return -EIO;
552 }
553 }
554
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530555 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300556
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800557 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
558 nw_subtype = SUBTYPE_P2PCLIENT;
559
Kalle Valobdcd8172011-07-18 00:22:30 +0300560 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
561 "%s: connect called with authmode %d dot11 auth %d"
562 " PW crypto %d PW crypto len %d GRP crypto %d"
563 " GRP crypto len %d channel hint %u\n",
564 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530565 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
566 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530567 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300568
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530569 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530570 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530571 vif->dot11_auth_mode, vif->auth_mode,
572 vif->prwise_crypto,
573 vif->prwise_crypto_len,
574 vif->grp_crypto, vif->grp_crypto_len,
575 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530576 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800577 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300578
579 up(&ar->sem);
580
581 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530582 memset(vif->ssid, 0, sizeof(vif->ssid));
583 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300584 ath6kl_err("invalid request\n");
585 return -ENOENT;
586 } else if (status) {
587 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
588 return -EIO;
589 }
590
591 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530592 ((vif->auth_mode == WPA_PSK_AUTH)
593 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530594 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300595 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
596 }
597
598 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530599 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300600
601 return 0;
602}
603
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530604static struct cfg80211_bss *
605ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
606 enum network_type nw_type,
607 const u8 *bssid,
608 struct ieee80211_channel *chan,
609 const u8 *beacon_ie,
610 size_t beacon_ie_len)
Jouni Malinen01cac472011-09-19 19:14:59 +0300611{
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)
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530639 return NULL;
Jouni Malinen01cac472011-09-19 19:14:59 +0300640 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
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
Jouni Malinen01cac472011-09-19 19:14:59 +0300654
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530655 return bss;
Jouni Malinen01cac472011-09-19 19:14:59 +0300656}
657
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530658void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300659 u8 *bssid, u16 listen_intvl,
660 u16 beacon_intvl,
661 enum network_type nw_type,
662 u8 beacon_ie_len, u8 assoc_req_len,
663 u8 assoc_resp_len, u8 *assoc_info)
664{
Jouni Malinen01cac472011-09-19 19:14:59 +0300665 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530666 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530667 struct cfg80211_bss *bss;
Kalle Valobdcd8172011-07-18 00:22:30 +0300668
669 /* capinfo + listen interval */
670 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
671
672 /* capinfo + status code + associd */
673 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
674
675 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
676 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
677 assoc_resp_ie_offset;
678
679 assoc_req_len -= assoc_req_ie_offset;
680 assoc_resp_len -= assoc_resp_ie_offset;
681
Jouni Malinen32c10872011-09-19 19:15:07 +0300682 /*
683 * Store Beacon interval here; DTIM period will be available only once
684 * a Beacon frame from the AP is seen.
685 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530686 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530687 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300688
Kalle Valobdcd8172011-07-18 00:22:30 +0300689 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530690 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300691 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
692 "%s: ath6k not in ibss mode\n", __func__);
693 return;
694 }
695 }
696
697 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530698 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
699 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300700 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
701 "%s: ath6k not in station mode\n", __func__);
702 return;
703 }
704 }
705
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530706 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300707
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530708 bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
709 assoc_info, beacon_ie_len);
710 if (!bss) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530711 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300712 return;
713 }
714
Raja Mani4eab6f42011-11-09 17:02:23 +0530715 if (nw_type & ADHOC_NETWORK) {
716 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
717 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
718 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530719 cfg80211_put_bss(bss);
Jouni Malinen01cac472011-09-19 19:14:59 +0300720 return;
721 }
722
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530723 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300724 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530725 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 assoc_req_ie, assoc_req_len,
728 assoc_resp_ie, assoc_resp_len,
729 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530730 cfg80211_put_bss(bss);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530731 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300732 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530733 cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
734 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300735 }
736}
737
738static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
739 struct net_device *dev, u16 reason_code)
740{
Kalle Valod6d5c062011-11-25 13:17:37 +0200741 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530742 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300743
744 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
745 reason_code);
746
Kalle Valo10509f92011-12-13 14:52:07 +0200747 ath6kl_cfg80211_sscan_disable(vif);
748
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530749 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300750 return -EIO;
751
752 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
753 ath6kl_err("busy, destroy in progress\n");
754 return -EBUSY;
755 }
756
757 if (down_interruptible(&ar->sem)) {
758 ath6kl_err("busy, couldn't get access\n");
759 return -ERESTARTSYS;
760 }
761
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530762 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530763 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530764 memset(vif->ssid, 0, sizeof(vif->ssid));
765 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300766
767 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530768 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300769
770 up(&ar->sem);
771
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530772 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530773
Kalle Valobdcd8172011-07-18 00:22:30 +0300774 return 0;
775}
776
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530777void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300778 u8 *bssid, u8 assoc_resp_len,
779 u8 *assoc_info, u16 proto_reason)
780{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530781 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530782
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530783 if (vif->scan_req) {
784 cfg80211_scan_done(vif->scan_req, true);
785 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300786 }
787
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530788 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530789 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300790 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
791 "%s: ath6k not in ibss mode\n", __func__);
792 return;
793 }
794 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530795 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300796 return;
797 }
798
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530799 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530800 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
801 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300802 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
803 "%s: ath6k not in station mode\n", __func__);
804 return;
805 }
806 }
807
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530808 /*
809 * Send a disconnect command to target when a disconnect event is
810 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
811 * request from host) to make the firmware stop trying to connect even
812 * after giving disconnect event. There will be one more disconnect
813 * event for this disconnect command with reason code DISCONNECT_CMD
814 * which will be notified to cfg80211.
815 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300816
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530817 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530818 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300819 return;
820 }
821
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530822 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300823
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530824 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530825 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530826 bssid, NULL, 0,
827 NULL, 0,
828 WLAN_STATUS_UNSPECIFIED_FAILURE,
829 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530830 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530831 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530832 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300833 }
834
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530835 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300836}
837
Kalle Valobdcd8172011-07-18 00:22:30 +0300838static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
839 struct cfg80211_scan_request *request)
840{
Kalle Valod6d5c062011-11-25 13:17:37 +0200841 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530842 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300843 s8 n_channels = 0;
844 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300845 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530846 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300847
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530848 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300849 return -EIO;
850
Kalle Valo10509f92011-12-13 14:52:07 +0200851 ath6kl_cfg80211_sscan_disable(vif);
852
Kalle Valobdcd8172011-07-18 00:22:30 +0300853 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530854 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300855 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530856 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530857 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300858 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
859 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300860 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300861 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300862 }
863 }
864
865 if (request->n_ssids && request->ssids[0].ssid_len) {
866 u8 i;
867
868 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
869 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
870
871 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530872 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
873 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300874 request->ssids[i].ssid_len,
875 request->ssids[i].ssid);
876 }
877
Kalle Valo10509f92011-12-13 14:52:07 +0200878 /*
879 * FIXME: we should clear the IE in fw if it's not set so just
880 * remove the check altogether
881 */
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300882 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530883 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
884 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300885 request->ie, request->ie_len);
886 if (ret) {
887 ath6kl_err("failed to set Probe Request appie for "
888 "scan");
889 return ret;
890 }
891 }
892
Jouni Malinen11869be2011-09-02 20:07:06 +0300893 /*
894 * Scan only the requested channels if the request specifies a set of
895 * channels. If the list is longer than the target supports, do not
896 * configure the list and instead, scan all available channels.
897 */
898 if (request->n_channels > 0 &&
899 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300900 u8 i;
901
Jouni Malinen11869be2011-09-02 20:07:06 +0300902 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300903
904 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
905 if (channels == NULL) {
906 ath6kl_warn("failed to set scan channels, "
907 "scan all channels");
908 n_channels = 0;
909 }
910
911 for (i = 0; i < n_channels; i++)
912 channels[i] = request->channels[i]->center_freq;
913 }
914
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530915 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530916 force_fg_scan = 1;
917
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800918 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
919 ar->fw_capabilities)) {
920 /*
921 * If capable of doing P2P mgmt operations using
922 * station interface, send additional information like
923 * supported rates to advertise and xmit rates for
924 * probe requests
925 */
926 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
927 WMI_LONG_SCAN, force_fg_scan,
928 false, 0, 0, n_channels,
929 channels, request->no_cck,
930 request->rates);
931 } else {
932 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
933 WMI_LONG_SCAN, force_fg_scan,
934 false, 0, 0, n_channels,
935 channels);
936 }
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300937 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300938 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300939 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530940 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300941
Edward Lu1276c9e2011-08-30 21:58:00 +0300942 kfree(channels);
943
Kalle Valobdcd8172011-07-18 00:22:30 +0300944 return ret;
945}
946
Kalle Valo1c17d312011-11-01 08:43:56 +0200947void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300948{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530949 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300950 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300951
Kalle Valo1c17d312011-11-01 08:43:56 +0200952 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
953 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300954
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530955 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300956 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300957
Kalle Valo1c17d312011-11-01 08:43:56 +0200958 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300959 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300960
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530961 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
962 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530963 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
964 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300965 0, NULL);
966 }
967 }
968
969out:
Kalle Valocb938212011-10-27 18:47:46 +0300970 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530971 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300972}
973
974static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
975 u8 key_index, bool pairwise,
976 const u8 *mac_addr,
977 struct key_params *params)
978{
Kalle Valod6d5c062011-11-25 13:17:37 +0200979 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530980 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300981 struct ath6kl_key *key = NULL;
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +0530982 int seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300983 u8 key_usage;
984 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300985
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530986 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300987 return -EIO;
988
Jouni Malinen837cb972011-10-11 17:31:57 +0300989 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
990 if (params->key_len != WMI_KRK_LEN)
991 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530992 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
993 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300994 }
995
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530996 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300997 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
998 "%s: key index %d out of bounds\n", __func__,
999 key_index);
1000 return -ENOENT;
1001 }
1002
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301003 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001004 memset(key, 0, sizeof(struct ath6kl_key));
1005
1006 if (pairwise)
1007 key_usage = PAIRWISE_USAGE;
1008 else
1009 key_usage = GROUP_USAGE;
1010
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301011 seq_len = params->seq_len;
1012 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1013 seq_len > ATH6KL_KEY_SEQ_LEN) {
1014 /* Only first half of the WPI PN is configured */
1015 seq_len = ATH6KL_KEY_SEQ_LEN;
Kalle Valobdcd8172011-07-18 00:22:30 +03001016 }
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301017 if (params->key_len > WLAN_MAX_KEY_LEN ||
1018 seq_len > sizeof(key->seq))
1019 return -EINVAL;
1020
1021 key->key_len = params->key_len;
1022 memcpy(key->key, params->key, key->key_len);
1023 key->seq_len = seq_len;
1024 memcpy(key->seq, params->seq, key->seq_len);
1025 key->cipher = params->cipher;
Kalle Valobdcd8172011-07-18 00:22:30 +03001026
1027 switch (key->cipher) {
1028 case WLAN_CIPHER_SUITE_WEP40:
1029 case WLAN_CIPHER_SUITE_WEP104:
1030 key_type = WEP_CRYPT;
1031 break;
1032
1033 case WLAN_CIPHER_SUITE_TKIP:
1034 key_type = TKIP_CRYPT;
1035 break;
1036
1037 case WLAN_CIPHER_SUITE_CCMP:
1038 key_type = AES_CRYPT;
1039 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001040 case WLAN_CIPHER_SUITE_SMS4:
1041 key_type = WAPI_CRYPT;
1042 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001043
1044 default:
1045 return -ENOTSUPP;
1046 }
1047
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301048 if (((vif->auth_mode == WPA_PSK_AUTH)
1049 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +03001050 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301051 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001052
1053 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1054 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1055 __func__, key_index, key->key_len, key_type,
1056 key_usage, key->seq_len);
1057
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301058 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001059 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
1060 key_type == WAPI_CRYPT) && params) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001061 ar->ap_mode_bkey.valid = true;
1062 ar->ap_mode_bkey.key_index = key_index;
1063 ar->ap_mode_bkey.key_type = key_type;
1064 ar->ap_mode_bkey.key_len = key->key_len;
1065 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301066 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001067 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1068 "key configuration until AP mode has been "
1069 "started\n");
1070 /*
1071 * The key will be set in ath6kl_connect_ap_mode() once
1072 * the connected event is received from the target.
1073 */
1074 return 0;
1075 }
1076 }
1077
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301078 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301079 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001080 /*
1081 * Store the key locally so that it can be re-configured after
1082 * the AP mode has properly started
1083 * (ath6kl_install_statioc_wep_keys).
1084 */
1085 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1086 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301087 vif->wep_key_list[key_index].key_len = key->key_len;
1088 memcpy(vif->wep_key_list[key_index].key, key->key,
1089 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001090 return 0;
1091 }
1092
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301093 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001094 key_type, key_usage, key->key_len,
1095 key->seq, key->seq_len, key->key,
1096 KEY_OP_INIT_VAL,
1097 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001098}
1099
1100static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1101 u8 key_index, bool pairwise,
1102 const u8 *mac_addr)
1103{
Kalle Valod6d5c062011-11-25 13:17:37 +02001104 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301105 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001106
1107 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1108
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301109 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001110 return -EIO;
1111
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301112 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001113 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1114 "%s: key index %d out of bounds\n", __func__,
1115 key_index);
1116 return -ENOENT;
1117 }
1118
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301119 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001120 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1121 "%s: index %d is empty\n", __func__, key_index);
1122 return 0;
1123 }
1124
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301125 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001126
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301127 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001128}
1129
1130static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1131 u8 key_index, bool pairwise,
1132 const u8 *mac_addr, void *cookie,
1133 void (*callback) (void *cookie,
1134 struct key_params *))
1135{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301136 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001137 struct ath6kl_key *key = NULL;
1138 struct key_params params;
1139
1140 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1141
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301142 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001143 return -EIO;
1144
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301145 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001146 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1147 "%s: key index %d out of bounds\n", __func__,
1148 key_index);
1149 return -ENOENT;
1150 }
1151
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301152 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001153 memset(&params, 0, sizeof(params));
1154 params.cipher = key->cipher;
1155 params.key_len = key->key_len;
1156 params.seq_len = key->seq_len;
1157 params.seq = key->seq;
1158 params.key = key->key;
1159
1160 callback(cookie, &params);
1161
1162 return key->key_len ? 0 : -ENOENT;
1163}
1164
1165static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1166 struct net_device *ndev,
1167 u8 key_index, bool unicast,
1168 bool multicast)
1169{
Kalle Valod6d5c062011-11-25 13:17:37 +02001170 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301171 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001172 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001173 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001174 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001175
1176 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1177
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301178 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001179 return -EIO;
1180
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301181 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001182 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1183 "%s: key index %d out of bounds\n",
1184 __func__, key_index);
1185 return -ENOENT;
1186 }
1187
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301188 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001189 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1190 __func__, key_index);
1191 return -EINVAL;
1192 }
1193
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301194 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301195 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001196 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301197 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001198 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001199 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301200 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001201 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301202 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001203
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301204 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001205 return 0; /* Delay until AP mode has been started */
1206
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001207 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1208 vif->def_txkey_index,
1209 key_type, key_usage,
1210 key->key_len, key->seq, key->seq_len,
1211 key->key,
1212 KEY_OP_INIT_VAL, NULL,
1213 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001214}
1215
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301216void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001217 bool ismcast)
1218{
1219 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1220 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1221
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301222 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001223 (ismcast ? NL80211_KEYTYPE_GROUP :
1224 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1225 GFP_KERNEL);
1226}
1227
1228static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1229{
1230 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301231 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001232 int ret;
1233
1234 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1235 changed);
1236
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301237 vif = ath6kl_vif_first(ar);
1238 if (!vif)
1239 return -EIO;
1240
1241 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001242 return -EIO;
1243
1244 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1245 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1246 if (ret != 0) {
1247 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1248 return -EIO;
1249 }
1250 }
1251
1252 return 0;
1253}
1254
1255/*
1256 * The type nl80211_tx_power_setting replaces the following
1257 * data type from 2.6.36 onwards
1258*/
1259static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1260 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001261 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001262{
1263 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301264 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001265 u8 ath6kl_dbm;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001266 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001267
1268 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1269 type, dbm);
1270
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301271 vif = ath6kl_vif_first(ar);
1272 if (!vif)
1273 return -EIO;
1274
1275 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001276 return -EIO;
1277
1278 switch (type) {
1279 case NL80211_TX_POWER_AUTOMATIC:
1280 return 0;
1281 case NL80211_TX_POWER_LIMITED:
1282 ar->tx_pwr = ath6kl_dbm = dbm;
1283 break;
1284 default:
1285 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1286 __func__, type);
1287 return -EOPNOTSUPP;
1288 }
1289
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301290 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001291
1292 return 0;
1293}
1294
1295static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1296{
1297 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301298 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001299
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301300 vif = ath6kl_vif_first(ar);
1301 if (!vif)
1302 return -EIO;
1303
1304 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001305 return -EIO;
1306
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301307 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001308 ar->tx_pwr = 0;
1309
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301310 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001311 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1312 return -EIO;
1313 }
1314
1315 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1316 5 * HZ);
1317
1318 if (signal_pending(current)) {
1319 ath6kl_err("target did not respond\n");
1320 return -EINTR;
1321 }
1322 }
1323
1324 *dbm = ar->tx_pwr;
1325 return 0;
1326}
1327
1328static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1329 struct net_device *dev,
1330 bool pmgmt, int timeout)
1331{
1332 struct ath6kl *ar = ath6kl_priv(dev);
1333 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301334 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001335
1336 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1337 __func__, pmgmt, timeout);
1338
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301339 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001340 return -EIO;
1341
1342 if (pmgmt) {
1343 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1344 mode.pwr_mode = REC_POWER;
1345 } else {
1346 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1347 mode.pwr_mode = MAX_PERF_POWER;
1348 }
1349
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301350 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1351 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001352 ath6kl_err("wmi_powermode_cmd failed\n");
1353 return -EIO;
1354 }
1355
1356 return 0;
1357}
1358
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301359static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1360 char *name,
1361 enum nl80211_iftype type,
1362 u32 *flags,
1363 struct vif_params *params)
1364{
1365 struct ath6kl *ar = wiphy_priv(wiphy);
1366 struct net_device *ndev;
1367 u8 if_idx, nw_type;
1368
Kalle Valo71f96ee2011-11-14 19:31:30 +02001369 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301370 ath6kl_err("Reached maximum number of supported vif\n");
1371 return ERR_PTR(-EINVAL);
1372 }
1373
1374 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1375 ath6kl_err("Not a supported interface type\n");
1376 return ERR_PTR(-EINVAL);
1377 }
1378
1379 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1380 if (!ndev)
1381 return ERR_PTR(-ENOMEM);
1382
1383 ar->num_vif++;
1384
1385 return ndev;
1386}
1387
1388static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1389 struct net_device *ndev)
1390{
1391 struct ath6kl *ar = wiphy_priv(wiphy);
1392 struct ath6kl_vif *vif = netdev_priv(ndev);
1393
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301394 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301395 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301396 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301397
1398 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1399
Kalle Valoc25889e2012-01-17 20:08:27 +02001400 ath6kl_cfg80211_vif_cleanup(vif);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301401
1402 return 0;
1403}
1404
Kalle Valobdcd8172011-07-18 00:22:30 +03001405static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1406 struct net_device *ndev,
1407 enum nl80211_iftype type, u32 *flags,
1408 struct vif_params *params)
1409{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301410 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001411
1412 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1413
Kalle Valobdcd8172011-07-18 00:22:30 +03001414 switch (type) {
1415 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301416 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001417 break;
1418 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301419 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001420 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001421 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301422 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001423 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001424 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301425 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001426 break;
1427 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301428 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001429 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001430 default:
1431 ath6kl_err("invalid interface type %u\n", type);
1432 return -EOPNOTSUPP;
1433 }
1434
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301435 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001436
1437 return 0;
1438}
1439
1440static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1441 struct net_device *dev,
1442 struct cfg80211_ibss_params *ibss_param)
1443{
1444 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301445 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001446 int status;
1447
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301448 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001449 return -EIO;
1450
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301451 vif->ssid_len = ibss_param->ssid_len;
1452 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001453
1454 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301455 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001456
1457 if (ibss_param->channel_fixed) {
1458 /*
1459 * TODO: channel_fixed: The channel should be fixed, do not
1460 * search for IBSSs to join on other channels. Target
1461 * firmware does not support this feature, needs to be
1462 * updated.
1463 */
1464 return -EOPNOTSUPP;
1465 }
1466
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301467 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001468 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301469 memcpy(vif->req_bssid, ibss_param->bssid,
1470 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001471
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301472 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001473
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301474 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001475 if (status)
1476 return status;
1477
1478 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301479 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1480 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001481 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301482 ath6kl_set_cipher(vif, 0, true);
1483 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001484 }
1485
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301486 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001487
1488 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1489 "%s: connect called with authmode %d dot11 auth %d"
1490 " PW crypto %d PW crypto len %d GRP crypto %d"
1491 " GRP crypto len %d channel hint %u\n",
1492 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301493 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1494 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301495 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001496
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301497 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301498 vif->dot11_auth_mode, vif->auth_mode,
1499 vif->prwise_crypto,
1500 vif->prwise_crypto_len,
1501 vif->grp_crypto, vif->grp_crypto_len,
1502 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301503 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001504 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301505 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001506
1507 return 0;
1508}
1509
1510static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1511 struct net_device *dev)
1512{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301513 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001514
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301515 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001516 return -EIO;
1517
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301518 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301519 memset(vif->ssid, 0, sizeof(vif->ssid));
1520 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001521
1522 return 0;
1523}
1524
1525static const u32 cipher_suites[] = {
1526 WLAN_CIPHER_SUITE_WEP40,
1527 WLAN_CIPHER_SUITE_WEP104,
1528 WLAN_CIPHER_SUITE_TKIP,
1529 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001530 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001531 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001532};
1533
1534static bool is_rate_legacy(s32 rate)
1535{
1536 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1537 6000, 9000, 12000, 18000, 24000,
1538 36000, 48000, 54000
1539 };
1540 u8 i;
1541
1542 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1543 if (rate == legacy[i])
1544 return true;
1545
1546 return false;
1547}
1548
1549static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1550{
1551 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1552 52000, 58500, 65000, 72200
1553 };
1554 u8 i;
1555
1556 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1557 if (rate == ht20[i]) {
1558 if (i == ARRAY_SIZE(ht20) - 1)
1559 /* last rate uses sgi */
1560 *sgi = true;
1561 else
1562 *sgi = false;
1563
1564 *mcs = i;
1565 return true;
1566 }
1567 }
1568 return false;
1569}
1570
1571static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1572{
1573 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1574 81000, 108000, 121500, 135000,
1575 150000
1576 };
1577 u8 i;
1578
1579 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1580 if (rate == ht40[i]) {
1581 if (i == ARRAY_SIZE(ht40) - 1)
1582 /* last rate uses sgi */
1583 *sgi = true;
1584 else
1585 *sgi = false;
1586
1587 *mcs = i;
1588 return true;
1589 }
1590 }
1591
1592 return false;
1593}
1594
1595static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1596 u8 *mac, struct station_info *sinfo)
1597{
1598 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301599 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001600 long left;
1601 bool sgi;
1602 s32 rate;
1603 int ret;
1604 u8 mcs;
1605
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301606 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001607 return -ENOENT;
1608
1609 if (down_interruptible(&ar->sem))
1610 return -EBUSY;
1611
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301612 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001613
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301614 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001615
1616 if (ret != 0) {
1617 up(&ar->sem);
1618 return -EIO;
1619 }
1620
1621 left = wait_event_interruptible_timeout(ar->event_wq,
1622 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301623 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001624 WMI_TIMEOUT);
1625
1626 up(&ar->sem);
1627
1628 if (left == 0)
1629 return -ETIMEDOUT;
1630 else if (left < 0)
1631 return left;
1632
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301633 if (vif->target_stats.rx_byte) {
1634 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001635 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301636 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001637 sinfo->filled |= STATION_INFO_RX_PACKETS;
1638 }
1639
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301640 if (vif->target_stats.tx_byte) {
1641 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001642 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301643 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001644 sinfo->filled |= STATION_INFO_TX_PACKETS;
1645 }
1646
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301647 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001648 sinfo->filled |= STATION_INFO_SIGNAL;
1649
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301650 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001651
1652 if (is_rate_legacy(rate)) {
1653 sinfo->txrate.legacy = rate / 100;
1654 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1655 if (sgi) {
1656 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1657 sinfo->txrate.mcs = mcs - 1;
1658 } else {
1659 sinfo->txrate.mcs = mcs;
1660 }
1661
1662 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1663 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1664 if (sgi) {
1665 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1666 sinfo->txrate.mcs = mcs - 1;
1667 } else {
1668 sinfo->txrate.mcs = mcs;
1669 }
1670
1671 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1672 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1673 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001674 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1675 "invalid rate from stats: %d\n", rate);
1676 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001677 return 0;
1678 }
1679
1680 sinfo->filled |= STATION_INFO_TX_BITRATE;
1681
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301682 if (test_bit(CONNECTED, &vif->flags) &&
1683 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301684 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001685 sinfo->filled |= STATION_INFO_BSS_PARAM;
1686 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301687 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1688 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001689 }
1690
Kalle Valobdcd8172011-07-18 00:22:30 +03001691 return 0;
1692}
1693
1694static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1695 struct cfg80211_pmksa *pmksa)
1696{
1697 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301698 struct ath6kl_vif *vif = netdev_priv(netdev);
1699
1700 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001701 pmksa->pmkid, true);
1702}
1703
1704static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1705 struct cfg80211_pmksa *pmksa)
1706{
1707 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301708 struct ath6kl_vif *vif = netdev_priv(netdev);
1709
1710 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001711 pmksa->pmkid, false);
1712}
1713
1714static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1715{
1716 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301717 struct ath6kl_vif *vif = netdev_priv(netdev);
1718
1719 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301720 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1721 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001722 return 0;
1723}
1724
Raja Mani6cb3c712011-11-07 22:52:45 +02001725static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1726{
Raja Manic08631c2011-12-16 14:24:24 +05301727 struct in_device *in_dev;
1728 struct in_ifaddr *ifa;
Raja Mani6cb3c712011-11-07 22:52:45 +02001729 struct ath6kl_vif *vif;
1730 int ret, pos, left;
1731 u32 filter = 0;
1732 u16 i;
Raja Manic08631c2011-12-16 14:24:24 +05301733 u8 mask[WOW_MASK_SIZE], index = 0;
1734 __be32 ips[MAX_IP_ADDRS];
Raja Mani6cb3c712011-11-07 22:52:45 +02001735
1736 vif = ath6kl_vif_first(ar);
1737 if (!vif)
1738 return -EIO;
1739
1740 if (!ath6kl_cfg80211_ready(vif))
1741 return -EIO;
1742
1743 if (!test_bit(CONNECTED, &vif->flags))
1744 return -EINVAL;
1745
1746 /* Clear existing WOW patterns */
1747 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1748 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1749 WOW_LIST_ID, i);
1750 /* Configure new WOW patterns */
1751 for (i = 0; i < wow->n_patterns; i++) {
1752
1753 /*
1754 * Convert given nl80211 specific mask value to equivalent
1755 * driver specific mask value and send it to the chip along
1756 * with patterns. For example, If the mask value defined in
1757 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1758 * then equivalent driver specific mask value is
1759 * "0xFF 0x00 0xFF 0x00".
1760 */
1761 memset(&mask, 0, sizeof(mask));
1762 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1763 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1764 mask[pos] = 0xFF;
1765 }
1766 /*
1767 * Note: Pattern's offset is not passed as part of wowlan
1768 * parameter from CFG layer. So it's always passed as ZERO
1769 * to the firmware. It means, given WOW patterns are always
1770 * matched from the first byte of received pkt in the firmware.
1771 */
1772 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1773 vif->fw_vif_idx, WOW_LIST_ID,
1774 wow->patterns[i].pattern_len,
1775 0 /* pattern offset */,
1776 wow->patterns[i].pattern, mask);
1777 if (ret)
1778 return ret;
1779 }
1780
Raja Manic08631c2011-12-16 14:24:24 +05301781 /* Setup own IP addr for ARP agent. */
1782 in_dev = __in_dev_get_rtnl(vif->ndev);
1783 if (!in_dev)
1784 goto skip_arp;
1785
1786 ifa = in_dev->ifa_list;
1787 memset(&ips, 0, sizeof(ips));
1788
1789 /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
1790 while (index < MAX_IP_ADDRS && ifa) {
1791 ips[index] = ifa->ifa_local;
1792 ifa = ifa->ifa_next;
1793 index++;
1794 }
1795
1796 if (ifa) {
1797 ath6kl_err("total IP addr count is exceeding fw limit\n");
1798 return -EINVAL;
1799 }
1800
1801 ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
1802 if (ret) {
1803 ath6kl_err("fail to setup ip for arp agent\n");
1804 return ret;
1805 }
1806
1807skip_arp:
Raja Mani6cb3c712011-11-07 22:52:45 +02001808 if (wow->disconnect)
1809 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1810
1811 if (wow->magic_pkt)
1812 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1813
1814 if (wow->gtk_rekey_failure)
1815 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1816
1817 if (wow->eap_identity_req)
1818 filter |= WOW_FILTER_OPTION_EAP_REQ;
1819
1820 if (wow->four_way_handshake)
1821 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1822
1823 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1824 ATH6KL_WOW_MODE_ENABLE,
1825 filter,
1826 WOW_HOST_REQ_DELAY);
1827 if (ret)
1828 return ret;
1829
1830 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1831 ATH6KL_HOST_MODE_ASLEEP);
1832 if (ret)
1833 return ret;
1834
1835 if (ar->tx_pending[ar->ctrl_ep]) {
1836 left = wait_event_interruptible_timeout(ar->event_wq,
1837 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1838 if (left == 0) {
1839 ath6kl_warn("clear wmi ctrl data timeout\n");
1840 ret = -ETIMEDOUT;
1841 } else if (left < 0) {
1842 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1843 ret = left;
1844 }
1845 }
1846
1847 return ret;
1848}
1849
1850static int ath6kl_wow_resume(struct ath6kl *ar)
1851{
1852 struct ath6kl_vif *vif;
1853 int ret;
1854
1855 vif = ath6kl_vif_first(ar);
1856 if (!vif)
1857 return -EIO;
1858
1859 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1860 ATH6KL_HOST_MODE_AWAKE);
1861 return ret;
1862}
1863
Kalle Valo52d81a62011-11-01 08:44:21 +02001864int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001865 enum ath6kl_cfg_suspend_mode mode,
1866 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001867{
1868 int ret;
1869
Kalle Valo52d81a62011-11-01 08:44:21 +02001870 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001871 case ATH6KL_CFG_SUSPEND_WOW:
1872
1873 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1874
1875 /* Flush all non control pkts in TX path */
1876 ath6kl_tx_data_cleanup(ar);
1877
1878 ret = ath6kl_wow_suspend(ar, wow);
1879 if (ret) {
1880 ath6kl_err("wow suspend failed: %d\n", ret);
1881 return ret;
1882 }
1883 ar->state = ATH6KL_STATE_WOW;
1884 break;
1885
Kalle Valo52d81a62011-11-01 08:44:21 +02001886 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001887
Kalle Valo7125f012011-12-13 14:51:37 +02001888 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001889
Kalle Valo52d81a62011-11-01 08:44:21 +02001890 /* save the current power mode before enabling power save */
1891 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1892
1893 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1894 if (ret) {
1895 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1896 ret);
1897 }
1898
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001899 ar->state = ATH6KL_STATE_DEEPSLEEP;
1900
Kalle Valo52d81a62011-11-01 08:44:21 +02001901 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001902
1903 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001904
Kalle Valo7125f012011-12-13 14:51:37 +02001905 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001906
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001907 if (ar->state == ATH6KL_STATE_OFF) {
1908 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1909 "suspend hw off, no action for cutpower\n");
1910 break;
1911 }
1912
1913 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1914
1915 ret = ath6kl_init_hw_stop(ar);
1916 if (ret) {
1917 ath6kl_warn("failed to stop hw during suspend: %d\n",
1918 ret);
1919 }
1920
1921 ar->state = ATH6KL_STATE_CUTPOWER;
1922
1923 break;
1924
Kalle Valo10509f92011-12-13 14:52:07 +02001925 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
1926 /*
1927 * Nothing needed for schedule scan, firmware is already in
1928 * wow mode and sleeping most of the time.
1929 */
1930 break;
1931
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001932 default:
1933 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001934 }
1935
1936 return 0;
1937}
1938
1939int ath6kl_cfg80211_resume(struct ath6kl *ar)
1940{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001941 int ret;
1942
1943 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001944 case ATH6KL_STATE_WOW:
1945 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1946
1947 ret = ath6kl_wow_resume(ar);
1948 if (ret) {
1949 ath6kl_warn("wow mode resume failed: %d\n", ret);
1950 return ret;
1951 }
1952
1953 ar->state = ATH6KL_STATE_ON;
1954 break;
1955
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001956 case ATH6KL_STATE_DEEPSLEEP:
1957 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1958 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1959 ar->wmi->saved_pwr_mode);
1960 if (ret) {
1961 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1962 ret);
1963 }
1964 }
1965
1966 ar->state = ATH6KL_STATE_ON;
1967
1968 break;
1969
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001970 case ATH6KL_STATE_CUTPOWER:
1971 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1972
1973 ret = ath6kl_init_hw_start(ar);
1974 if (ret) {
1975 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1976 return ret;
1977 }
Raja Manid7c44e02011-11-07 22:52:46 +02001978 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001979
Kalle Valo10509f92011-12-13 14:52:07 +02001980 case ATH6KL_STATE_SCHED_SCAN:
1981 break;
1982
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001983 default:
1984 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001985 }
1986
1987 return 0;
1988}
1989
Kalle Valoabcb3442011-07-22 08:26:20 +03001990#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001991
1992/* hif layer decides what suspend mode to use */
1993static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001994 struct cfg80211_wowlan *wow)
1995{
1996 struct ath6kl *ar = wiphy_priv(wiphy);
1997
Raja Mani0f60e9f2011-11-07 22:52:45 +02001998 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001999}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002000
Kalle Valo52d81a62011-11-01 08:44:21 +02002001static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002002{
2003 struct ath6kl *ar = wiphy_priv(wiphy);
2004
2005 return ath6kl_hif_resume(ar);
2006}
Raja Mania918fb32011-11-07 22:52:46 +02002007
2008/*
2009 * FIXME: WOW suspend mode is selected if the host sdio controller supports
2010 * both sdio irq wake up and keep power. The target pulls sdio data line to
2011 * wake up the host when WOW pattern matches. This causes sdio irq handler
2012 * is being called in the host side which internally hits ath6kl's RX path.
2013 *
2014 * Since sdio interrupt is not disabled, RX path executes even before
2015 * the host executes the actual resume operation from PM module.
2016 *
2017 * In the current scenario, WOW resume should happen before start processing
2018 * any data from the target. So It's required to perform WOW resume in RX path.
2019 * Ideally we should perform WOW resume only in the actual platform
2020 * resume path. This area needs bit rework to avoid WOW resume in RX path.
2021 *
2022 * ath6kl_check_wow_status() is called from ath6kl_rx().
2023 */
2024void ath6kl_check_wow_status(struct ath6kl *ar)
2025{
2026 if (ar->state == ATH6KL_STATE_WOW)
2027 ath6kl_cfg80211_resume(ar);
2028}
2029
2030#else
2031
2032void ath6kl_check_wow_status(struct ath6kl *ar)
2033{
2034}
Kalle Valoabcb3442011-07-22 08:26:20 +03002035#endif
2036
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002037static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
2038 struct ieee80211_channel *chan,
2039 enum nl80211_channel_type channel_type)
2040{
Sujith Manoharane68f6752011-12-22 12:15:27 +05302041 struct ath6kl_vif *vif;
2042
2043 /*
2044 * 'dev' could be NULL if a channel change is required for the hardware
2045 * device itself, instead of a particular VIF.
2046 *
2047 * FIXME: To be handled properly when monitor mode is supported.
2048 */
2049 if (!dev)
2050 return -EBUSY;
2051
2052 vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002053
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302054 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002055 return -EIO;
2056
2057 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
2058 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302059 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002060
2061 return 0;
2062}
2063
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002064static bool ath6kl_is_p2p_ie(const u8 *pos)
2065{
2066 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2067 pos[2] == 0x50 && pos[3] == 0x6f &&
2068 pos[4] == 0x9a && pos[5] == 0x09;
2069}
2070
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302071static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2072 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002073{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302074 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002075 const u8 *pos;
2076 u8 *buf = NULL;
2077 size_t len = 0;
2078 int ret;
2079
2080 /*
2081 * Filter out P2P IE(s) since they will be included depending on
2082 * the Probe Request frame in ath6kl_send_go_probe_resp().
2083 */
2084
2085 if (ies && ies_len) {
2086 buf = kmalloc(ies_len, GFP_KERNEL);
2087 if (buf == NULL)
2088 return -ENOMEM;
2089 pos = ies;
2090 while (pos + 1 < ies + ies_len) {
2091 if (pos + 2 + pos[1] > ies + ies_len)
2092 break;
2093 if (!ath6kl_is_p2p_ie(pos)) {
2094 memcpy(buf + len, pos, 2 + pos[1]);
2095 len += 2 + pos[1];
2096 }
2097 pos += 2 + pos[1];
2098 }
2099 }
2100
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302101 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2102 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002103 kfree(buf);
2104 return ret;
2105}
2106
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002107static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2108 struct beacon_parameters *info, bool add)
2109{
2110 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302111 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002112 struct ieee80211_mgmt *mgmt;
2113 u8 *ies;
2114 int ies_len;
2115 struct wmi_connect_cmd p;
2116 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302117 int i, ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002118
2119 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2120
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302121 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002122 return -EIO;
2123
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302124 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002125 return -EOPNOTSUPP;
2126
2127 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302128 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2129 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002130 info->beacon_ies,
2131 info->beacon_ies_len);
2132 if (res)
2133 return res;
2134 }
2135 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302136 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002137 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002138 if (res)
2139 return res;
2140 }
2141 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302142 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2143 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002144 info->assocresp_ies,
2145 info->assocresp_ies_len);
2146 if (res)
2147 return res;
2148 }
2149
2150 if (!add)
2151 return 0;
2152
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002153 ar->ap_mode_bkey.valid = false;
2154
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002155 /* TODO:
2156 * info->interval
2157 * info->dtim_period
2158 */
2159
2160 if (info->head == NULL)
2161 return -EINVAL;
2162 mgmt = (struct ieee80211_mgmt *) info->head;
2163 ies = mgmt->u.beacon.variable;
2164 if (ies > info->head + info->head_len)
2165 return -EINVAL;
2166 ies_len = info->head + info->head_len - ies;
2167
2168 if (info->ssid == NULL)
2169 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302170 memcpy(vif->ssid, info->ssid, info->ssid_len);
2171 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002172 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2173 return -EOPNOTSUPP; /* TODO */
2174
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302175 ret = ath6kl_set_auth_type(vif, info->auth_type);
2176 if (ret)
2177 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002178
2179 memset(&p, 0, sizeof(p));
2180
2181 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2182 switch (info->crypto.akm_suites[i]) {
2183 case WLAN_AKM_SUITE_8021X:
2184 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2185 p.auth_mode |= WPA_AUTH;
2186 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2187 p.auth_mode |= WPA2_AUTH;
2188 break;
2189 case WLAN_AKM_SUITE_PSK:
2190 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2191 p.auth_mode |= WPA_PSK_AUTH;
2192 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2193 p.auth_mode |= WPA2_PSK_AUTH;
2194 break;
2195 }
2196 }
2197 if (p.auth_mode == 0)
2198 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302199 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002200
2201 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2202 switch (info->crypto.ciphers_pairwise[i]) {
2203 case WLAN_CIPHER_SUITE_WEP40:
2204 case WLAN_CIPHER_SUITE_WEP104:
2205 p.prwise_crypto_type |= WEP_CRYPT;
2206 break;
2207 case WLAN_CIPHER_SUITE_TKIP:
2208 p.prwise_crypto_type |= TKIP_CRYPT;
2209 break;
2210 case WLAN_CIPHER_SUITE_CCMP:
2211 p.prwise_crypto_type |= AES_CRYPT;
2212 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002213 case WLAN_CIPHER_SUITE_SMS4:
2214 p.prwise_crypto_type |= WAPI_CRYPT;
2215 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002216 }
2217 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002218 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002219 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302220 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002221 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302222 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002223
2224 switch (info->crypto.cipher_group) {
2225 case WLAN_CIPHER_SUITE_WEP40:
2226 case WLAN_CIPHER_SUITE_WEP104:
2227 p.grp_crypto_type = WEP_CRYPT;
2228 break;
2229 case WLAN_CIPHER_SUITE_TKIP:
2230 p.grp_crypto_type = TKIP_CRYPT;
2231 break;
2232 case WLAN_CIPHER_SUITE_CCMP:
2233 p.grp_crypto_type = AES_CRYPT;
2234 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002235 case WLAN_CIPHER_SUITE_SMS4:
2236 p.grp_crypto_type = WAPI_CRYPT;
2237 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002238 default:
2239 p.grp_crypto_type = NONE_CRYPT;
2240 break;
2241 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302242 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002243
2244 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302245 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002246
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302247 p.ssid_len = vif->ssid_len;
2248 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2249 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302250 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002251
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302252 /* Enable uAPSD support by default */
2253 res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
2254 if (res < 0)
2255 return res;
2256
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002257 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2258 p.nw_subtype = SUBTYPE_P2PGO;
2259 } else {
2260 /*
2261 * Due to firmware limitation, it is not possible to
2262 * do P2P mgmt operations in AP mode
2263 */
2264 p.nw_subtype = SUBTYPE_NONE;
2265 }
2266
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302267 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002268 if (res < 0)
2269 return res;
2270
2271 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002272}
2273
2274static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2275 struct beacon_parameters *info)
2276{
2277 return ath6kl_ap_beacon(wiphy, dev, info, true);
2278}
2279
2280static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2281 struct beacon_parameters *info)
2282{
2283 return ath6kl_ap_beacon(wiphy, dev, info, false);
2284}
2285
2286static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2287{
2288 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302289 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002290
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302291 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002292 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302293 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002294 return -ENOTCONN;
2295
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302296 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302297 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002298
2299 return 0;
2300}
2301
Jouni Malinen33e53082011-12-27 11:02:56 +02002302static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2303
2304static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
2305 u8 *mac)
2306{
2307 struct ath6kl *ar = ath6kl_priv(dev);
2308 struct ath6kl_vif *vif = netdev_priv(dev);
2309 const u8 *addr = mac ? mac : bcast_addr;
2310
2311 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
2312 addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
2313}
2314
Jouni Malinen23875132011-08-30 21:57:53 +03002315static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2316 u8 *mac, struct station_parameters *params)
2317{
2318 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302319 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002320
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302321 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002322 return -EOPNOTSUPP;
2323
2324 /* Use this only for authorizing/unauthorizing a station */
2325 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2326 return -EOPNOTSUPP;
2327
2328 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302329 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2330 WMI_AP_MLME_AUTHORIZE, mac, 0);
2331 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2332 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002333}
2334
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002335static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2336 struct net_device *dev,
2337 struct ieee80211_channel *chan,
2338 enum nl80211_channel_type channel_type,
2339 unsigned int duration,
2340 u64 *cookie)
2341{
2342 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302343 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002344 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002345
2346 /* TODO: if already pending or ongoing remain-on-channel,
2347 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002348 id = ++vif->last_roc_id;
2349 if (id == 0) {
2350 /* Do not use 0 as the cookie value */
2351 id = ++vif->last_roc_id;
2352 }
2353 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002354
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302355 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2356 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002357}
2358
2359static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2360 struct net_device *dev,
2361 u64 cookie)
2362{
2363 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302364 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002365
Jouni Malinen10522612011-10-27 16:00:13 +03002366 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002367 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002368 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002369
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302370 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002371}
2372
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302373static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2374 const u8 *buf, size_t len,
2375 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002376{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302377 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002378 const u8 *pos;
2379 u8 *p2p;
2380 int p2p_len;
2381 int ret;
2382 const struct ieee80211_mgmt *mgmt;
2383
2384 mgmt = (const struct ieee80211_mgmt *) buf;
2385
2386 /* Include P2P IE(s) from the frame generated in user space. */
2387
2388 p2p = kmalloc(len, GFP_KERNEL);
2389 if (p2p == NULL)
2390 return -ENOMEM;
2391 p2p_len = 0;
2392
2393 pos = mgmt->u.probe_resp.variable;
2394 while (pos + 1 < buf + len) {
2395 if (pos + 2 + pos[1] > buf + len)
2396 break;
2397 if (ath6kl_is_p2p_ie(pos)) {
2398 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2399 p2p_len += 2 + pos[1];
2400 }
2401 pos += 2 + pos[1];
2402 }
2403
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302404 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2405 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002406 kfree(p2p);
2407 return ret;
2408}
2409
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002410static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2411 struct ieee80211_channel *chan, bool offchan,
2412 enum nl80211_channel_type channel_type,
2413 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002414 const u8 *buf, size_t len, bool no_cck,
2415 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002416{
2417 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302418 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002419 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002420 const struct ieee80211_mgmt *mgmt;
2421
2422 mgmt = (const struct ieee80211_mgmt *) buf;
2423 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302424 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002425 ieee80211_is_probe_resp(mgmt->frame_control)) {
2426 /*
2427 * Send Probe Response frame in AP mode using a separate WMI
2428 * command to allow the target to fill in the generic IEs.
2429 */
2430 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302431 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002432 chan->center_freq);
2433 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002434
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302435 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002436 if (id == 0) {
2437 /*
2438 * 0 is a reserved value in the WMI command and shall not be
2439 * used for the command.
2440 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302441 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002442 }
2443
2444 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002445
2446 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
2447 ar->fw_capabilities)) {
2448 /*
2449 * If capable of doing P2P mgmt operations using
2450 * station interface, send additional information like
2451 * supported rates to advertise and xmit rates for
2452 * probe requests
2453 */
2454 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
2455 chan->center_freq, wait,
2456 buf, len, no_cck);
2457 } else {
2458 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2459 chan->center_freq, wait,
2460 buf, len);
2461 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002462}
2463
Jouni Malinenae32c302011-08-30 21:58:01 +03002464static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2465 struct net_device *dev,
2466 u16 frame_type, bool reg)
2467{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302468 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002469
2470 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2471 __func__, frame_type, reg);
2472 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2473 /*
2474 * Note: This notification callback is not allowed to sleep, so
2475 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2476 * hardcode target to report Probe Request frames all the time.
2477 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302478 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002479 }
2480}
2481
Kalle Valo10509f92011-12-13 14:52:07 +02002482static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2483 struct net_device *dev,
2484 struct cfg80211_sched_scan_request *request)
2485{
2486 struct ath6kl *ar = ath6kl_priv(dev);
2487 struct ath6kl_vif *vif = netdev_priv(dev);
2488 u16 interval;
2489 int ret;
2490 u8 i;
2491
2492 if (ar->state != ATH6KL_STATE_ON)
2493 return -EIO;
2494
2495 if (vif->sme_state != SME_DISCONNECTED)
2496 return -EBUSY;
2497
2498 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2499 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2500 i, DISABLE_SSID_FLAG,
2501 0, NULL);
2502 }
2503
2504 /* fw uses seconds, also make sure that it's >0 */
2505 interval = max_t(u16, 1, request->interval / 1000);
2506
2507 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2508 interval, interval,
2509 10, 0, 0, 0, 3, 0, 0, 0);
2510
2511 if (request->n_ssids && request->ssids[0].ssid_len) {
2512 for (i = 0; i < request->n_ssids; i++) {
2513 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2514 i, SPECIFIC_SSID_FLAG,
2515 request->ssids[i].ssid_len,
2516 request->ssids[i].ssid);
2517 }
2518 }
2519
2520 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2521 ATH6KL_WOW_MODE_ENABLE,
2522 WOW_FILTER_SSID,
2523 WOW_HOST_REQ_DELAY);
2524 if (ret) {
2525 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
2526 return ret;
2527 }
2528
2529 /* this also clears IE in fw if it's not set */
2530 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2531 WMI_FRAME_PROBE_REQ,
2532 request->ie, request->ie_len);
2533 if (ret) {
2534 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
2535 ret);
2536 return ret;
2537 }
2538
2539 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2540 ATH6KL_HOST_MODE_ASLEEP);
2541 if (ret) {
2542 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
2543 ret);
2544 return ret;
2545 }
2546
2547 ar->state = ATH6KL_STATE_SCHED_SCAN;
2548
2549 return ret;
2550}
2551
2552static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
2553 struct net_device *dev)
2554{
2555 struct ath6kl_vif *vif = netdev_priv(dev);
2556 bool stopped;
2557
2558 stopped = __ath6kl_cfg80211_sscan_stop(vif);
2559
2560 if (!stopped)
2561 return -EIO;
2562
2563 return 0;
2564}
2565
Jouni Malinenf80574a2011-08-30 21:58:04 +03002566static const struct ieee80211_txrx_stypes
2567ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2568 [NL80211_IFTYPE_STATION] = {
2569 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2570 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2571 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2572 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2573 },
Jouni Malinenba1f6fe2011-12-27 11:03:53 +02002574 [NL80211_IFTYPE_AP] = {
2575 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2576 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2577 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2578 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2579 },
Jouni Malinenf80574a2011-08-30 21:58:04 +03002580 [NL80211_IFTYPE_P2P_CLIENT] = {
2581 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2582 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2583 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2584 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2585 },
2586 [NL80211_IFTYPE_P2P_GO] = {
2587 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2588 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2589 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2590 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2591 },
2592};
2593
Kalle Valobdcd8172011-07-18 00:22:30 +03002594static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302595 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2596 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002597 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2598 .scan = ath6kl_cfg80211_scan,
2599 .connect = ath6kl_cfg80211_connect,
2600 .disconnect = ath6kl_cfg80211_disconnect,
2601 .add_key = ath6kl_cfg80211_add_key,
2602 .get_key = ath6kl_cfg80211_get_key,
2603 .del_key = ath6kl_cfg80211_del_key,
2604 .set_default_key = ath6kl_cfg80211_set_default_key,
2605 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2606 .set_tx_power = ath6kl_cfg80211_set_txpower,
2607 .get_tx_power = ath6kl_cfg80211_get_txpower,
2608 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2609 .join_ibss = ath6kl_cfg80211_join_ibss,
2610 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2611 .get_station = ath6kl_get_station,
2612 .set_pmksa = ath6kl_set_pmksa,
2613 .del_pmksa = ath6kl_del_pmksa,
2614 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002615 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002616#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002617 .suspend = __ath6kl_cfg80211_suspend,
2618 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002619#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002620 .set_channel = ath6kl_set_channel,
2621 .add_beacon = ath6kl_add_beacon,
2622 .set_beacon = ath6kl_set_beacon,
2623 .del_beacon = ath6kl_del_beacon,
Jouni Malinen33e53082011-12-27 11:02:56 +02002624 .del_station = ath6kl_del_station,
Jouni Malinen23875132011-08-30 21:57:53 +03002625 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002626 .remain_on_channel = ath6kl_remain_on_channel,
2627 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002628 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002629 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valo10509f92011-12-13 14:52:07 +02002630 .sched_scan_start = ath6kl_cfg80211_sscan_start,
2631 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Kalle Valobdcd8172011-07-18 00:22:30 +03002632};
2633
Kalle Valo7125f012011-12-13 14:51:37 +02002634void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02002635{
Kalle Valo10509f92011-12-13 14:52:07 +02002636 ath6kl_cfg80211_sscan_disable(vif);
2637
Kalle Valoec4b7f62011-11-01 08:44:04 +02002638 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02002639 case SME_DISCONNECTED:
2640 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02002641 case SME_CONNECTING:
2642 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2643 NULL, 0,
2644 WLAN_STATUS_UNSPECIFIED_FAILURE,
2645 GFP_KERNEL);
2646 break;
2647 case SME_CONNECTED:
Kalle Valoec4b7f62011-11-01 08:44:04 +02002648 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2649 break;
2650 }
2651
2652 if (test_bit(CONNECTED, &vif->flags) ||
2653 test_bit(CONNECT_PEND, &vif->flags))
Kalle Valo7125f012011-12-13 14:51:37 +02002654 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002655
2656 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002657 clear_bit(CONNECTED, &vif->flags);
2658 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002659
2660 /* disable scanning */
Kalle Valo7125f012011-12-13 14:51:37 +02002661 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
2662 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
2663 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02002664
2665 ath6kl_cfg80211_scan_complete_event(vif, true);
2666}
2667
Kalle Valo7125f012011-12-13 14:51:37 +02002668void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
2669{
2670 struct ath6kl_vif *vif;
2671
2672 vif = ath6kl_vif_first(ar);
2673 if (!vif) {
2674 /* save the current power mode before enabling power save */
2675 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2676
2677 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2678 ath6kl_warn("ath6kl_deep_sleep_enable: "
2679 "wmi_powermode_cmd failed\n");
2680 return;
2681 }
2682
2683 /*
2684 * FIXME: we should take ar->list_lock to protect changes in the
2685 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
2686 * sleeps.
2687 */
2688 list_for_each_entry(vif, &ar->vif_list, list)
2689 ath6kl_cfg80211_stop(vif);
2690}
2691
Kalle Valoc25889e2012-01-17 20:08:27 +02002692static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002693{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302694 vif->aggr_cntxt = aggr_init(vif->ndev);
2695 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302696 ath6kl_err("failed to initialize aggr\n");
2697 return -ENOMEM;
2698 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002699
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302700 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302701 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02002702 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
2703 (unsigned long) vif);
2704
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302705 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302706 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302707
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302708 INIT_LIST_HEAD(&vif->mc_filter);
2709
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302710 return 0;
2711}
2712
Kalle Valoc25889e2012-01-17 20:08:27 +02002713void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302714{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302715 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302716 struct ath6kl_mc_filter *mc_filter, *tmp;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302717
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302718 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302719
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302720 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2721
2722 if (vif->nw_type == ADHOC_NETWORK)
2723 ar->ibss_if_active = false;
2724
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302725 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
2726 list_del(&mc_filter->list);
2727 kfree(mc_filter);
2728 }
2729
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302730 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302731
2732 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302733}
2734
2735struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302736 enum nl80211_iftype type, u8 fw_vif_idx,
2737 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302738{
2739 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302740 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302741
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302742 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302743 if (!ndev)
2744 return NULL;
2745
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302746 vif = netdev_priv(ndev);
2747 ndev->ieee80211_ptr = &vif->wdev;
2748 vif->wdev.wiphy = ar->wiphy;
2749 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302750 vif->ndev = ndev;
2751 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2752 vif->wdev.netdev = ndev;
2753 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302754 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302755 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302756
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302757 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2758 if (fw_vif_idx != 0)
2759 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2760 0x2;
2761
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302762 init_netdev(ndev);
2763
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302764 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302765
Kalle Valoc25889e2012-01-17 20:08:27 +02002766 if (ath6kl_cfg80211_vif_init(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302767 goto err;
2768
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302769 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302770 goto err;
2771
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302772 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302773 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302774 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302775 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302776 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302777
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302778 if (type == NL80211_IFTYPE_ADHOC)
2779 ar->ibss_if_active = true;
2780
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302781 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302782 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302783 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302784
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302785 return ndev;
2786
2787err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302788 aggr_module_destroy(vif->aggr_cntxt);
2789 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302790 return NULL;
2791}
2792
Kalle Valo46d33a22012-01-17 20:08:40 +02002793int ath6kl_cfg80211_init(struct ath6kl *ar)
2794{
2795 struct wiphy *wiphy = ar->wiphy;
2796 int ret;
2797
2798 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
2799
2800 wiphy->max_remain_on_channel_duration = 5000;
2801
2802 /* set device pointer for wiphy */
2803 set_wiphy_dev(wiphy, ar->dev);
2804
2805 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2806 BIT(NL80211_IFTYPE_ADHOC) |
2807 BIT(NL80211_IFTYPE_AP);
2808 if (ar->p2p) {
2809 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
2810 BIT(NL80211_IFTYPE_P2P_CLIENT);
2811 }
2812
2813 /* max num of ssids that can be probed during scanning */
2814 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2815 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2816 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2817 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2818 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
2819
2820 wiphy->cipher_suites = cipher_suites;
2821 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2822
2823 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2824 WIPHY_WOWLAN_DISCONNECT |
2825 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2826 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2827 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2828 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2829 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2830 wiphy->wowlan.pattern_min_len = 1;
2831 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2832
2833 wiphy->max_sched_scan_ssids = 10;
2834
2835 ret = wiphy_register(wiphy);
2836 if (ret < 0) {
2837 ath6kl_err("couldn't register wiphy device\n");
2838 return ret;
2839 }
2840
2841 return 0;
2842}
2843
2844void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302845{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302846 wiphy_unregister(ar->wiphy);
Kalle Valo45eaa782012-01-17 20:09:05 +02002847}
Kalle Valo46d33a22012-01-17 20:08:40 +02002848
Kalle Valo45eaa782012-01-17 20:09:05 +02002849struct ath6kl *ath6kl_cfg80211_create(void)
2850{
2851 struct ath6kl *ar;
2852 struct wiphy *wiphy;
2853
2854 /* create a new wiphy for use with cfg80211 */
2855 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
2856
2857 if (!wiphy) {
2858 ath6kl_err("couldn't allocate wiphy device\n");
2859 return NULL;
2860 }
2861
2862 ar = wiphy_priv(wiphy);
2863 ar->wiphy = wiphy;
2864
2865 return ar;
2866}
2867
2868/* Note: ar variable must not be accessed after calling this! */
2869void ath6kl_cfg80211_destroy(struct ath6kl *ar)
2870{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302871 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002872}
Kalle Valo45eaa782012-01-17 20:09:05 +02002873