blob: 7e92dc9799acfbd53b0f3a39fd3d21761556aad2 [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
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030026static unsigned int ath6kl_p2p;
27
28module_param(ath6kl_p2p, uint, 0644);
29
Kalle Valobdcd8172011-07-18 00:22:30 +030030#define RATETAB_ENT(_rate, _rateid, _flags) { \
31 .bitrate = (_rate), \
32 .flags = (_flags), \
33 .hw_value = (_rateid), \
34}
35
36#define CHAN2G(_channel, _freq, _flags) { \
37 .band = IEEE80211_BAND_2GHZ, \
38 .hw_value = (_channel), \
39 .center_freq = (_freq), \
40 .flags = (_flags), \
41 .max_antenna_gain = 0, \
42 .max_power = 30, \
43}
44
45#define CHAN5G(_channel, _flags) { \
46 .band = IEEE80211_BAND_5GHZ, \
47 .hw_value = (_channel), \
48 .center_freq = 5000 + (5 * (_channel)), \
49 .flags = (_flags), \
50 .max_antenna_gain = 0, \
51 .max_power = 30, \
52}
53
54static struct ieee80211_rate ath6kl_rates[] = {
55 RATETAB_ENT(10, 0x1, 0),
56 RATETAB_ENT(20, 0x2, 0),
57 RATETAB_ENT(55, 0x4, 0),
58 RATETAB_ENT(110, 0x8, 0),
59 RATETAB_ENT(60, 0x10, 0),
60 RATETAB_ENT(90, 0x20, 0),
61 RATETAB_ENT(120, 0x40, 0),
62 RATETAB_ENT(180, 0x80, 0),
63 RATETAB_ENT(240, 0x100, 0),
64 RATETAB_ENT(360, 0x200, 0),
65 RATETAB_ENT(480, 0x400, 0),
66 RATETAB_ENT(540, 0x800, 0),
67};
68
69#define ath6kl_a_rates (ath6kl_rates + 4)
70#define ath6kl_a_rates_size 8
71#define ath6kl_g_rates (ath6kl_rates + 0)
72#define ath6kl_g_rates_size 12
73
74static struct ieee80211_channel ath6kl_2ghz_channels[] = {
75 CHAN2G(1, 2412, 0),
76 CHAN2G(2, 2417, 0),
77 CHAN2G(3, 2422, 0),
78 CHAN2G(4, 2427, 0),
79 CHAN2G(5, 2432, 0),
80 CHAN2G(6, 2437, 0),
81 CHAN2G(7, 2442, 0),
82 CHAN2G(8, 2447, 0),
83 CHAN2G(9, 2452, 0),
84 CHAN2G(10, 2457, 0),
85 CHAN2G(11, 2462, 0),
86 CHAN2G(12, 2467, 0),
87 CHAN2G(13, 2472, 0),
88 CHAN2G(14, 2484, 0),
89};
90
91static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
92 CHAN5G(34, 0), CHAN5G(36, 0),
93 CHAN5G(38, 0), CHAN5G(40, 0),
94 CHAN5G(42, 0), CHAN5G(44, 0),
95 CHAN5G(46, 0), CHAN5G(48, 0),
96 CHAN5G(52, 0), CHAN5G(56, 0),
97 CHAN5G(60, 0), CHAN5G(64, 0),
98 CHAN5G(100, 0), CHAN5G(104, 0),
99 CHAN5G(108, 0), CHAN5G(112, 0),
100 CHAN5G(116, 0), CHAN5G(120, 0),
101 CHAN5G(124, 0), CHAN5G(128, 0),
102 CHAN5G(132, 0), CHAN5G(136, 0),
103 CHAN5G(140, 0), CHAN5G(149, 0),
104 CHAN5G(153, 0), CHAN5G(157, 0),
105 CHAN5G(161, 0), CHAN5G(165, 0),
106 CHAN5G(184, 0), CHAN5G(188, 0),
107 CHAN5G(192, 0), CHAN5G(196, 0),
108 CHAN5G(200, 0), CHAN5G(204, 0),
109 CHAN5G(208, 0), CHAN5G(212, 0),
110 CHAN5G(216, 0),
111};
112
113static struct ieee80211_supported_band ath6kl_band_2ghz = {
114 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
115 .channels = ath6kl_2ghz_channels,
116 .n_bitrates = ath6kl_g_rates_size,
117 .bitrates = ath6kl_g_rates,
118};
119
120static struct ieee80211_supported_band ath6kl_band_5ghz = {
121 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
122 .channels = ath6kl_5ghz_a_channels,
123 .n_bitrates = ath6kl_a_rates_size,
124 .bitrates = ath6kl_a_rates,
125};
126
Jouni Malinen837cb972011-10-11 17:31:57 +0300127#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
128
Kalle Valo10509f92011-12-13 14:52:07 +0200129/* returns true if scheduled scan was stopped */
130static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
131{
132 struct ath6kl *ar = vif->ar;
133
134 if (ar->state != ATH6KL_STATE_SCHED_SCAN)
135 return false;
136
137 del_timer_sync(&vif->sched_scan_timer);
138
139 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
140 ATH6KL_HOST_MODE_AWAKE);
141
142 ar->state = ATH6KL_STATE_ON;
143
144 return true;
145}
146
147static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
148{
149 struct ath6kl *ar = vif->ar;
150 bool stopped;
151
152 stopped = __ath6kl_cfg80211_sscan_stop(vif);
153
154 if (!stopped)
155 return;
156
157 cfg80211_sched_scan_stopped(ar->wiphy);
158}
159
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530160static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300161 enum nl80211_wpa_versions wpa_version)
162{
163 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
164
165 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530166 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300167 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530168 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300169 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530170 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300171 } else {
172 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
173 return -ENOTSUPP;
174 }
175
176 return 0;
177}
178
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530179static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300180 enum nl80211_auth_type auth_type)
181{
Kalle Valobdcd8172011-07-18 00:22:30 +0300182 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
183
184 switch (auth_type) {
185 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530186 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300187 break;
188 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530189 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300190 break;
191 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530192 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300193 break;
194
195 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530196 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300197 break;
198
199 default:
200 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
201 return -ENOTSUPP;
202 }
203
204 return 0;
205}
206
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530207static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300208{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530209 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
210 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
211 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300212
213 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
214 __func__, cipher, ucast);
215
216 switch (cipher) {
217 case 0:
218 /* our own hack to use value 0 as no crypto used */
219 *ar_cipher = NONE_CRYPT;
220 *ar_cipher_len = 0;
221 break;
222 case WLAN_CIPHER_SUITE_WEP40:
223 *ar_cipher = WEP_CRYPT;
224 *ar_cipher_len = 5;
225 break;
226 case WLAN_CIPHER_SUITE_WEP104:
227 *ar_cipher = WEP_CRYPT;
228 *ar_cipher_len = 13;
229 break;
230 case WLAN_CIPHER_SUITE_TKIP:
231 *ar_cipher = TKIP_CRYPT;
232 *ar_cipher_len = 0;
233 break;
234 case WLAN_CIPHER_SUITE_CCMP:
235 *ar_cipher = AES_CRYPT;
236 *ar_cipher_len = 0;
237 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200238 case WLAN_CIPHER_SUITE_SMS4:
239 *ar_cipher = WAPI_CRYPT;
240 *ar_cipher_len = 0;
241 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300242 default:
243 ath6kl_err("cipher 0x%x not supported\n", cipher);
244 return -ENOTSUPP;
245 }
246
247 return 0;
248}
249
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530250static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300251{
252 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
253
254 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530255 if (vif->auth_mode == WPA_AUTH)
256 vif->auth_mode = WPA_PSK_AUTH;
257 else if (vif->auth_mode == WPA2_AUTH)
258 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300259 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530260 if (vif->auth_mode == WPA_AUTH)
261 vif->auth_mode = WPA_AUTH_CCKM;
262 else if (vif->auth_mode == WPA2_AUTH)
263 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300264 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530265 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300266 }
267}
268
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530269static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300270{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530271 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530272
Kalle Valobdcd8172011-07-18 00:22:30 +0300273 if (!test_bit(WMI_READY, &ar->flag)) {
274 ath6kl_err("wmi is not ready\n");
275 return false;
276 }
277
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530278 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300279 ath6kl_err("wlan disabled\n");
280 return false;
281 }
282
283 return true;
284}
285
Kevin Fang6981ffd2011-10-07 08:51:19 +0800286static bool ath6kl_is_wpa_ie(const u8 *pos)
287{
288 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
289 pos[2] == 0x00 && pos[3] == 0x50 &&
290 pos[4] == 0xf2 && pos[5] == 0x01;
291}
292
293static bool ath6kl_is_rsn_ie(const u8 *pos)
294{
295 return pos[0] == WLAN_EID_RSN;
296}
297
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700298static bool ath6kl_is_wps_ie(const u8 *pos)
299{
300 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
301 pos[1] >= 4 &&
302 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
303 pos[5] == 0x04);
304}
305
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530306static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
307 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800308{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530309 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800310 const u8 *pos;
311 u8 *buf = NULL;
312 size_t len = 0;
313 int ret;
314
315 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700316 * Clear previously set flag
317 */
318
319 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
320
321 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800322 * Filter out RSN/WPA IE(s)
323 */
324
325 if (ies && ies_len) {
326 buf = kmalloc(ies_len, GFP_KERNEL);
327 if (buf == NULL)
328 return -ENOMEM;
329 pos = ies;
330
331 while (pos + 1 < ies + ies_len) {
332 if (pos + 2 + pos[1] > ies + ies_len)
333 break;
334 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
335 memcpy(buf + len, pos, 2 + pos[1]);
336 len += 2 + pos[1];
337 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700338
339 if (ath6kl_is_wps_ie(pos))
340 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
341
Kevin Fang6981ffd2011-10-07 08:51:19 +0800342 pos += 2 + pos[1];
343 }
344 }
345
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530346 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
347 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800348 kfree(buf);
349 return ret;
350}
351
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530352static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
353{
354 switch (type) {
355 case NL80211_IFTYPE_STATION:
356 *nw_type = INFRA_NETWORK;
357 break;
358 case NL80211_IFTYPE_ADHOC:
359 *nw_type = ADHOC_NETWORK;
360 break;
361 case NL80211_IFTYPE_AP:
362 *nw_type = AP_NETWORK;
363 break;
364 case NL80211_IFTYPE_P2P_CLIENT:
365 *nw_type = INFRA_NETWORK;
366 break;
367 case NL80211_IFTYPE_P2P_GO:
368 *nw_type = AP_NETWORK;
369 break;
370 default:
371 ath6kl_err("invalid interface type %u\n", type);
372 return -ENOTSUPP;
373 }
374
375 return 0;
376}
377
378static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
379 u8 *if_idx, u8 *nw_type)
380{
381 int i;
382
383 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
384 return false;
385
386 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
387 ar->num_vif))
388 return false;
389
390 if (type == NL80211_IFTYPE_STATION ||
391 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200392 for (i = 0; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530393 if ((ar->avail_idx_map >> i) & BIT(0)) {
394 *if_idx = i;
395 return true;
396 }
397 }
398 }
399
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530400 if (type == NL80211_IFTYPE_P2P_CLIENT ||
401 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200402 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530403 if ((ar->avail_idx_map >> i) & BIT(0)) {
404 *if_idx = i;
405 return true;
406 }
407 }
408 }
409
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530410 return false;
411}
412
Kalle Valobdcd8172011-07-18 00:22:30 +0300413static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
414 struct cfg80211_connect_params *sme)
415{
416 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530417 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300418 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800419 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Kalle Valobdcd8172011-07-18 00:22:30 +0300420
Kalle Valo10509f92011-12-13 14:52:07 +0200421 ath6kl_cfg80211_sscan_disable(vif);
422
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530423 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300424
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530425 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300426 return -EIO;
427
428 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
429 ath6kl_err("destroy in progress\n");
430 return -EBUSY;
431 }
432
433 if (test_bit(SKIP_SCAN, &ar->flag) &&
434 ((sme->channel && sme->channel->center_freq == 0) ||
435 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
436 ath6kl_err("SkipScan: channel or bssid invalid\n");
437 return -EINVAL;
438 }
439
440 if (down_interruptible(&ar->sem)) {
441 ath6kl_err("busy, couldn't get access\n");
442 return -ERESTARTSYS;
443 }
444
445 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
446 ath6kl_err("busy, destroy in progress\n");
447 up(&ar->sem);
448 return -EBUSY;
449 }
450
451 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
452 /*
453 * sleep until the command queue drains
454 */
455 wait_event_interruptible_timeout(ar->event_wq,
456 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
457 WMI_TIMEOUT);
458 if (signal_pending(current)) {
459 ath6kl_err("cmd queue drain timeout\n");
460 up(&ar->sem);
461 return -EINTR;
462 }
463 }
464
Jouni Malinen6e786cb2011-12-15 14:16:00 +0200465 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
466 if (status) {
467 up(&ar->sem);
468 return status;
469 }
470
471 if (sme->ie == NULL || sme->ie_len == 0)
Raja Mani542c5192011-11-15 14:14:56 +0530472 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800473
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530474 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530475 vif->ssid_len == sme->ssid_len &&
476 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530477 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530478 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
479 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530480 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300481
482 up(&ar->sem);
483 if (status) {
484 ath6kl_err("wmi_reconnect_cmd failed\n");
485 return -EIO;
486 }
487 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530488 } else if (vif->ssid_len == sme->ssid_len &&
489 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530490 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300491 }
492
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530493 memset(vif->ssid, 0, sizeof(vif->ssid));
494 vif->ssid_len = sme->ssid_len;
495 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300496
497 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530498 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300499
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530500 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300501 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530502 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300503
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530504 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300505
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530506 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300507 if (status) {
508 up(&ar->sem);
509 return status;
510 }
511
512 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530513 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300514 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530515 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300516
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530517 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300518
519 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530520 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300521
522 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530523 (vif->auth_mode == NONE_AUTH) &&
524 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300525 struct ath6kl_key *key = NULL;
526
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530527 if (sme->key_idx > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300528 ath6kl_err("key index %d out of bounds\n",
529 sme->key_idx);
530 up(&ar->sem);
531 return -ENOENT;
532 }
533
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530534 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300535 key->key_len = sme->key_len;
536 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530537 key->cipher = vif->prwise_crypto;
538 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300539
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530540 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530541 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300542 GROUP_USAGE | TX_USAGE,
543 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200544 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300545 key->key, KEY_OP_INIT_VAL, NULL,
546 NO_SYNC_WMIFLAG);
547 }
548
549 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530550 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530551 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
552 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300553 ath6kl_err("couldn't set bss filtering\n");
554 up(&ar->sem);
555 return -EIO;
556 }
557 }
558
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530559 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300560
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800561 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
562 nw_subtype = SUBTYPE_P2PCLIENT;
563
Kalle Valobdcd8172011-07-18 00:22:30 +0300564 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
565 "%s: connect called with authmode %d dot11 auth %d"
566 " PW crypto %d PW crypto len %d GRP crypto %d"
567 " GRP crypto len %d channel hint %u\n",
568 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530569 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
570 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530571 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300572
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530573 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530574 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530575 vif->dot11_auth_mode, vif->auth_mode,
576 vif->prwise_crypto,
577 vif->prwise_crypto_len,
578 vif->grp_crypto, vif->grp_crypto_len,
579 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530580 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800581 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300582
583 up(&ar->sem);
584
585 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530586 memset(vif->ssid, 0, sizeof(vif->ssid));
587 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300588 ath6kl_err("invalid request\n");
589 return -ENOENT;
590 } else if (status) {
591 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
592 return -EIO;
593 }
594
595 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530596 ((vif->auth_mode == WPA_PSK_AUTH)
597 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530598 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300599 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
600 }
601
602 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530603 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300604
605 return 0;
606}
607
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530608static struct cfg80211_bss *
609ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
610 enum network_type nw_type,
611 const u8 *bssid,
612 struct ieee80211_channel *chan,
613 const u8 *beacon_ie,
614 size_t beacon_ie_len)
Jouni Malinen01cac472011-09-19 19:14:59 +0300615{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530616 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300617 struct cfg80211_bss *bss;
Raja Mani4eab6f42011-11-09 17:02:23 +0530618 u16 cap_mask, cap_val;
Jouni Malinen01cac472011-09-19 19:14:59 +0300619 u8 *ie;
620
Raja Mani4eab6f42011-11-09 17:02:23 +0530621 if (nw_type & ADHOC_NETWORK) {
622 cap_mask = WLAN_CAPABILITY_IBSS;
623 cap_val = WLAN_CAPABILITY_IBSS;
624 } else {
625 cap_mask = WLAN_CAPABILITY_ESS;
626 cap_val = WLAN_CAPABILITY_ESS;
627 }
628
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530629 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530630 vif->ssid, vif->ssid_len,
631 cap_mask, cap_val);
Jouni Malinen01cac472011-09-19 19:14:59 +0300632 if (bss == NULL) {
633 /*
634 * Since cfg80211 may not yet know about the BSS,
635 * generate a partial entry until the first BSS info
636 * event becomes available.
637 *
638 * Prepend SSID element since it is not included in the Beacon
639 * IEs from the target.
640 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530641 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300642 if (ie == NULL)
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530643 return NULL;
Jouni Malinen01cac472011-09-19 19:14:59 +0300644 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530645 ie[1] = vif->ssid_len;
646 memcpy(ie + 2, vif->ssid, vif->ssid_len);
647 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530648 bss = cfg80211_inform_bss(ar->wiphy, chan,
Raja Mani4eab6f42011-11-09 17:02:23 +0530649 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530650 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300651 0, GFP_KERNEL);
652 if (bss)
Raja Mani4eab6f42011-11-09 17:02:23 +0530653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
654 "cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300655 kfree(ie);
656 } else
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530657 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
Jouni Malinen01cac472011-09-19 19:14:59 +0300658
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530659 return bss;
Jouni Malinen01cac472011-09-19 19:14:59 +0300660}
661
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530662void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300663 u8 *bssid, u16 listen_intvl,
664 u16 beacon_intvl,
665 enum network_type nw_type,
666 u8 beacon_ie_len, u8 assoc_req_len,
667 u8 assoc_resp_len, u8 *assoc_info)
668{
Jouni Malinen01cac472011-09-19 19:14:59 +0300669 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530670 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530671 struct cfg80211_bss *bss;
Kalle Valobdcd8172011-07-18 00:22:30 +0300672
673 /* capinfo + listen interval */
674 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
675
676 /* capinfo + status code + associd */
677 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
678
679 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
680 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
681 assoc_resp_ie_offset;
682
683 assoc_req_len -= assoc_req_ie_offset;
684 assoc_resp_len -= assoc_resp_ie_offset;
685
Jouni Malinen32c10872011-09-19 19:15:07 +0300686 /*
687 * Store Beacon interval here; DTIM period will be available only once
688 * a Beacon frame from the AP is seen.
689 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530690 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530691 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300692
Kalle Valobdcd8172011-07-18 00:22:30 +0300693 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530694 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300695 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
696 "%s: ath6k not in ibss mode\n", __func__);
697 return;
698 }
699 }
700
701 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530702 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
703 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300704 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
705 "%s: ath6k not in station mode\n", __func__);
706 return;
707 }
708 }
709
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530710 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300711
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530712 bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
713 assoc_info, beacon_ie_len);
714 if (!bss) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530715 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300716 return;
717 }
718
Raja Mani4eab6f42011-11-09 17:02:23 +0530719 if (nw_type & ADHOC_NETWORK) {
720 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
721 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
722 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530723 cfg80211_put_bss(bss);
Jouni Malinen01cac472011-09-19 19:14:59 +0300724 return;
725 }
726
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530727 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300728 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530729 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530730 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300731 assoc_req_ie, assoc_req_len,
732 assoc_resp_ie, assoc_resp_len,
733 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530734 cfg80211_put_bss(bss);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530735 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300736 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530737 cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
738 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300739 }
740}
741
742static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
743 struct net_device *dev, u16 reason_code)
744{
Kalle Valod6d5c062011-11-25 13:17:37 +0200745 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530746 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300747
748 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
749 reason_code);
750
Kalle Valo10509f92011-12-13 14:52:07 +0200751 ath6kl_cfg80211_sscan_disable(vif);
752
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530753 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300754 return -EIO;
755
756 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
757 ath6kl_err("busy, destroy in progress\n");
758 return -EBUSY;
759 }
760
761 if (down_interruptible(&ar->sem)) {
762 ath6kl_err("busy, couldn't get access\n");
763 return -ERESTARTSYS;
764 }
765
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530766 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530767 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530768 memset(vif->ssid, 0, sizeof(vif->ssid));
769 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300770
771 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530772 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300773
774 up(&ar->sem);
775
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530776 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530777
Kalle Valobdcd8172011-07-18 00:22:30 +0300778 return 0;
779}
780
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530781void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300782 u8 *bssid, u8 assoc_resp_len,
783 u8 *assoc_info, u16 proto_reason)
784{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530785 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530786
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530787 if (vif->scan_req) {
788 cfg80211_scan_done(vif->scan_req, true);
789 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300790 }
791
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530792 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530793 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
795 "%s: ath6k not in ibss mode\n", __func__);
796 return;
797 }
798 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530799 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300800 return;
801 }
802
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530803 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530804 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
805 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300806 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
807 "%s: ath6k not in station mode\n", __func__);
808 return;
809 }
810 }
811
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530812 /*
813 * Send a disconnect command to target when a disconnect event is
814 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
815 * request from host) to make the firmware stop trying to connect even
816 * after giving disconnect event. There will be one more disconnect
817 * event for this disconnect command with reason code DISCONNECT_CMD
818 * which will be notified to cfg80211.
819 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300820
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530821 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530822 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300823 return;
824 }
825
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530826 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300827
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530828 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530829 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530830 bssid, NULL, 0,
831 NULL, 0,
832 WLAN_STATUS_UNSPECIFIED_FAILURE,
833 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530834 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530835 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530836 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300837 }
838
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530839 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300840}
841
Kalle Valobdcd8172011-07-18 00:22:30 +0300842static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
843 struct cfg80211_scan_request *request)
844{
Kalle Valod6d5c062011-11-25 13:17:37 +0200845 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530846 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300847 s8 n_channels = 0;
848 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300849 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530850 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300851
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530852 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300853 return -EIO;
854
Kalle Valo10509f92011-12-13 14:52:07 +0200855 ath6kl_cfg80211_sscan_disable(vif);
856
Kalle Valobdcd8172011-07-18 00:22:30 +0300857 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530858 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300859 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530860 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530861 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300862 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
863 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300864 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300865 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300866 }
867 }
868
869 if (request->n_ssids && request->ssids[0].ssid_len) {
870 u8 i;
871
872 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
873 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
874
875 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530876 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
877 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300878 request->ssids[i].ssid_len,
879 request->ssids[i].ssid);
880 }
881
Kalle Valo10509f92011-12-13 14:52:07 +0200882 /*
883 * FIXME: we should clear the IE in fw if it's not set so just
884 * remove the check altogether
885 */
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300886 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530887 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
888 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300889 request->ie, request->ie_len);
890 if (ret) {
891 ath6kl_err("failed to set Probe Request appie for "
892 "scan");
893 return ret;
894 }
895 }
896
Jouni Malinen11869be2011-09-02 20:07:06 +0300897 /*
898 * Scan only the requested channels if the request specifies a set of
899 * channels. If the list is longer than the target supports, do not
900 * configure the list and instead, scan all available channels.
901 */
902 if (request->n_channels > 0 &&
903 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300904 u8 i;
905
Jouni Malinen11869be2011-09-02 20:07:06 +0300906 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300907
908 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
909 if (channels == NULL) {
910 ath6kl_warn("failed to set scan channels, "
911 "scan all channels");
912 n_channels = 0;
913 }
914
915 for (i = 0; i < n_channels; i++)
916 channels[i] = request->channels[i]->center_freq;
917 }
918
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530919 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530920 force_fg_scan = 1;
921
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800922 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
923 ar->fw_capabilities)) {
924 /*
925 * If capable of doing P2P mgmt operations using
926 * station interface, send additional information like
927 * supported rates to advertise and xmit rates for
928 * probe requests
929 */
930 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
931 WMI_LONG_SCAN, force_fg_scan,
932 false, 0, 0, n_channels,
933 channels, request->no_cck,
934 request->rates);
935 } else {
936 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
937 WMI_LONG_SCAN, force_fg_scan,
938 false, 0, 0, n_channels,
939 channels);
940 }
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300941 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300942 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300943 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530944 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300945
Edward Lu1276c9e2011-08-30 21:58:00 +0300946 kfree(channels);
947
Kalle Valobdcd8172011-07-18 00:22:30 +0300948 return ret;
949}
950
Kalle Valo1c17d312011-11-01 08:43:56 +0200951void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300952{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530953 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300954 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300955
Kalle Valo1c17d312011-11-01 08:43:56 +0200956 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
957 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300958
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530959 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300960 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300961
Kalle Valo1c17d312011-11-01 08:43:56 +0200962 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300963 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300964
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530965 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
966 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530967 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
968 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300969 0, NULL);
970 }
971 }
972
973out:
Kalle Valocb938212011-10-27 18:47:46 +0300974 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530975 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300976}
977
978static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
979 u8 key_index, bool pairwise,
980 const u8 *mac_addr,
981 struct key_params *params)
982{
Kalle Valod6d5c062011-11-25 13:17:37 +0200983 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530984 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300985 struct ath6kl_key *key = NULL;
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +0530986 int seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300987 u8 key_usage;
988 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300989
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530990 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300991 return -EIO;
992
Jouni Malinen837cb972011-10-11 17:31:57 +0300993 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
994 if (params->key_len != WMI_KRK_LEN)
995 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530996 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
997 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300998 }
999
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301000 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001001 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1002 "%s: key index %d out of bounds\n", __func__,
1003 key_index);
1004 return -ENOENT;
1005 }
1006
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301007 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001008 memset(key, 0, sizeof(struct ath6kl_key));
1009
1010 if (pairwise)
1011 key_usage = PAIRWISE_USAGE;
1012 else
1013 key_usage = GROUP_USAGE;
1014
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301015 seq_len = params->seq_len;
1016 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1017 seq_len > ATH6KL_KEY_SEQ_LEN) {
1018 /* Only first half of the WPI PN is configured */
1019 seq_len = ATH6KL_KEY_SEQ_LEN;
Kalle Valobdcd8172011-07-18 00:22:30 +03001020 }
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301021 if (params->key_len > WLAN_MAX_KEY_LEN ||
1022 seq_len > sizeof(key->seq))
1023 return -EINVAL;
1024
1025 key->key_len = params->key_len;
1026 memcpy(key->key, params->key, key->key_len);
1027 key->seq_len = seq_len;
1028 memcpy(key->seq, params->seq, key->seq_len);
1029 key->cipher = params->cipher;
Kalle Valobdcd8172011-07-18 00:22:30 +03001030
1031 switch (key->cipher) {
1032 case WLAN_CIPHER_SUITE_WEP40:
1033 case WLAN_CIPHER_SUITE_WEP104:
1034 key_type = WEP_CRYPT;
1035 break;
1036
1037 case WLAN_CIPHER_SUITE_TKIP:
1038 key_type = TKIP_CRYPT;
1039 break;
1040
1041 case WLAN_CIPHER_SUITE_CCMP:
1042 key_type = AES_CRYPT;
1043 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001044 case WLAN_CIPHER_SUITE_SMS4:
1045 key_type = WAPI_CRYPT;
1046 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001047
1048 default:
1049 return -ENOTSUPP;
1050 }
1051
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301052 if (((vif->auth_mode == WPA_PSK_AUTH)
1053 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +03001054 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301055 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001056
1057 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1058 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1059 __func__, key_index, key->key_len, key_type,
1060 key_usage, key->seq_len);
1061
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301062 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001063 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
1064 key_type == WAPI_CRYPT) && params) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001065 ar->ap_mode_bkey.valid = true;
1066 ar->ap_mode_bkey.key_index = key_index;
1067 ar->ap_mode_bkey.key_type = key_type;
1068 ar->ap_mode_bkey.key_len = key->key_len;
1069 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301070 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001071 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1072 "key configuration until AP mode has been "
1073 "started\n");
1074 /*
1075 * The key will be set in ath6kl_connect_ap_mode() once
1076 * the connected event is received from the target.
1077 */
1078 return 0;
1079 }
1080 }
1081
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301082 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301083 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001084 /*
1085 * Store the key locally so that it can be re-configured after
1086 * the AP mode has properly started
1087 * (ath6kl_install_statioc_wep_keys).
1088 */
1089 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1090 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301091 vif->wep_key_list[key_index].key_len = key->key_len;
1092 memcpy(vif->wep_key_list[key_index].key, key->key,
1093 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001094 return 0;
1095 }
1096
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301097 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001098 key_type, key_usage, key->key_len,
1099 key->seq, key->seq_len, key->key,
1100 KEY_OP_INIT_VAL,
1101 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001102}
1103
1104static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1105 u8 key_index, bool pairwise,
1106 const u8 *mac_addr)
1107{
Kalle Valod6d5c062011-11-25 13:17:37 +02001108 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301109 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001110
1111 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1112
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301113 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001114 return -EIO;
1115
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301116 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001117 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1118 "%s: key index %d out of bounds\n", __func__,
1119 key_index);
1120 return -ENOENT;
1121 }
1122
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301123 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001124 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1125 "%s: index %d is empty\n", __func__, key_index);
1126 return 0;
1127 }
1128
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301129 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001130
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301131 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001132}
1133
1134static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1135 u8 key_index, bool pairwise,
1136 const u8 *mac_addr, void *cookie,
1137 void (*callback) (void *cookie,
1138 struct key_params *))
1139{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301140 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001141 struct ath6kl_key *key = NULL;
1142 struct key_params params;
1143
1144 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1145
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301146 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001147 return -EIO;
1148
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301149 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001150 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1151 "%s: key index %d out of bounds\n", __func__,
1152 key_index);
1153 return -ENOENT;
1154 }
1155
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301156 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001157 memset(&params, 0, sizeof(params));
1158 params.cipher = key->cipher;
1159 params.key_len = key->key_len;
1160 params.seq_len = key->seq_len;
1161 params.seq = key->seq;
1162 params.key = key->key;
1163
1164 callback(cookie, &params);
1165
1166 return key->key_len ? 0 : -ENOENT;
1167}
1168
1169static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1170 struct net_device *ndev,
1171 u8 key_index, bool unicast,
1172 bool multicast)
1173{
Kalle Valod6d5c062011-11-25 13:17:37 +02001174 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301175 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001176 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001177 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001178 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001179
1180 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1181
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301182 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001183 return -EIO;
1184
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301185 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001186 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1187 "%s: key index %d out of bounds\n",
1188 __func__, key_index);
1189 return -ENOENT;
1190 }
1191
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301192 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001193 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1194 __func__, key_index);
1195 return -EINVAL;
1196 }
1197
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301198 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301199 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001200 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301201 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001202 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001203 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301204 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001205 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301206 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001207
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301208 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001209 return 0; /* Delay until AP mode has been started */
1210
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001211 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1212 vif->def_txkey_index,
1213 key_type, key_usage,
1214 key->key_len, key->seq, key->seq_len,
1215 key->key,
1216 KEY_OP_INIT_VAL, NULL,
1217 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001218}
1219
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301220void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001221 bool ismcast)
1222{
1223 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1224 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1225
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301226 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001227 (ismcast ? NL80211_KEYTYPE_GROUP :
1228 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1229 GFP_KERNEL);
1230}
1231
1232static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1233{
1234 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301235 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001236 int ret;
1237
1238 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1239 changed);
1240
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301241 vif = ath6kl_vif_first(ar);
1242 if (!vif)
1243 return -EIO;
1244
1245 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001246 return -EIO;
1247
1248 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1249 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1250 if (ret != 0) {
1251 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1252 return -EIO;
1253 }
1254 }
1255
1256 return 0;
1257}
1258
1259/*
1260 * The type nl80211_tx_power_setting replaces the following
1261 * data type from 2.6.36 onwards
1262*/
1263static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1264 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001265 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001266{
1267 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301268 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001269 u8 ath6kl_dbm;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001270 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001271
1272 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1273 type, dbm);
1274
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301275 vif = ath6kl_vif_first(ar);
1276 if (!vif)
1277 return -EIO;
1278
1279 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001280 return -EIO;
1281
1282 switch (type) {
1283 case NL80211_TX_POWER_AUTOMATIC:
1284 return 0;
1285 case NL80211_TX_POWER_LIMITED:
1286 ar->tx_pwr = ath6kl_dbm = dbm;
1287 break;
1288 default:
1289 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1290 __func__, type);
1291 return -EOPNOTSUPP;
1292 }
1293
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301294 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001295
1296 return 0;
1297}
1298
1299static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1300{
1301 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301302 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001303
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301304 vif = ath6kl_vif_first(ar);
1305 if (!vif)
1306 return -EIO;
1307
1308 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001309 return -EIO;
1310
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301311 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001312 ar->tx_pwr = 0;
1313
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301314 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001315 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1316 return -EIO;
1317 }
1318
1319 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1320 5 * HZ);
1321
1322 if (signal_pending(current)) {
1323 ath6kl_err("target did not respond\n");
1324 return -EINTR;
1325 }
1326 }
1327
1328 *dbm = ar->tx_pwr;
1329 return 0;
1330}
1331
1332static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1333 struct net_device *dev,
1334 bool pmgmt, int timeout)
1335{
1336 struct ath6kl *ar = ath6kl_priv(dev);
1337 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301338 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001339
1340 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1341 __func__, pmgmt, timeout);
1342
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301343 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001344 return -EIO;
1345
1346 if (pmgmt) {
1347 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1348 mode.pwr_mode = REC_POWER;
1349 } else {
1350 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1351 mode.pwr_mode = MAX_PERF_POWER;
1352 }
1353
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301354 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1355 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001356 ath6kl_err("wmi_powermode_cmd failed\n");
1357 return -EIO;
1358 }
1359
1360 return 0;
1361}
1362
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301363static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1364 char *name,
1365 enum nl80211_iftype type,
1366 u32 *flags,
1367 struct vif_params *params)
1368{
1369 struct ath6kl *ar = wiphy_priv(wiphy);
1370 struct net_device *ndev;
1371 u8 if_idx, nw_type;
1372
Kalle Valo71f96ee2011-11-14 19:31:30 +02001373 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301374 ath6kl_err("Reached maximum number of supported vif\n");
1375 return ERR_PTR(-EINVAL);
1376 }
1377
1378 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1379 ath6kl_err("Not a supported interface type\n");
1380 return ERR_PTR(-EINVAL);
1381 }
1382
1383 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1384 if (!ndev)
1385 return ERR_PTR(-ENOMEM);
1386
1387 ar->num_vif++;
1388
1389 return ndev;
1390}
1391
1392static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1393 struct net_device *ndev)
1394{
1395 struct ath6kl *ar = wiphy_priv(wiphy);
1396 struct ath6kl_vif *vif = netdev_priv(ndev);
1397
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301398 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301399 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301400 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301401
1402 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1403
Kalle Valoc25889e2012-01-17 20:08:27 +02001404 ath6kl_cfg80211_vif_cleanup(vif);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301405
1406 return 0;
1407}
1408
Kalle Valobdcd8172011-07-18 00:22:30 +03001409static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1410 struct net_device *ndev,
1411 enum nl80211_iftype type, u32 *flags,
1412 struct vif_params *params)
1413{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301414 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001415
1416 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1417
Kalle Valobdcd8172011-07-18 00:22:30 +03001418 switch (type) {
1419 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301420 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001421 break;
1422 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301423 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001424 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001425 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301426 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001427 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001428 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301429 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001430 break;
1431 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301432 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001433 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001434 default:
1435 ath6kl_err("invalid interface type %u\n", type);
1436 return -EOPNOTSUPP;
1437 }
1438
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301439 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001440
1441 return 0;
1442}
1443
1444static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1445 struct net_device *dev,
1446 struct cfg80211_ibss_params *ibss_param)
1447{
1448 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301449 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001450 int status;
1451
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301452 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001453 return -EIO;
1454
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301455 vif->ssid_len = ibss_param->ssid_len;
1456 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001457
1458 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301459 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001460
1461 if (ibss_param->channel_fixed) {
1462 /*
1463 * TODO: channel_fixed: The channel should be fixed, do not
1464 * search for IBSSs to join on other channels. Target
1465 * firmware does not support this feature, needs to be
1466 * updated.
1467 */
1468 return -EOPNOTSUPP;
1469 }
1470
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301471 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001472 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301473 memcpy(vif->req_bssid, ibss_param->bssid,
1474 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001475
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301476 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001477
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301478 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001479 if (status)
1480 return status;
1481
1482 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301483 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1484 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001485 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301486 ath6kl_set_cipher(vif, 0, true);
1487 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001488 }
1489
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301490 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001491
1492 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1493 "%s: connect called with authmode %d dot11 auth %d"
1494 " PW crypto %d PW crypto len %d GRP crypto %d"
1495 " GRP crypto len %d channel hint %u\n",
1496 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301497 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1498 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301499 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001500
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301501 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301502 vif->dot11_auth_mode, vif->auth_mode,
1503 vif->prwise_crypto,
1504 vif->prwise_crypto_len,
1505 vif->grp_crypto, vif->grp_crypto_len,
1506 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301507 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001508 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301509 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001510
1511 return 0;
1512}
1513
1514static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1515 struct net_device *dev)
1516{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301517 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301519 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001520 return -EIO;
1521
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301522 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301523 memset(vif->ssid, 0, sizeof(vif->ssid));
1524 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001525
1526 return 0;
1527}
1528
1529static const u32 cipher_suites[] = {
1530 WLAN_CIPHER_SUITE_WEP40,
1531 WLAN_CIPHER_SUITE_WEP104,
1532 WLAN_CIPHER_SUITE_TKIP,
1533 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001534 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001535 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001536};
1537
1538static bool is_rate_legacy(s32 rate)
1539{
1540 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1541 6000, 9000, 12000, 18000, 24000,
1542 36000, 48000, 54000
1543 };
1544 u8 i;
1545
1546 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1547 if (rate == legacy[i])
1548 return true;
1549
1550 return false;
1551}
1552
1553static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1554{
1555 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1556 52000, 58500, 65000, 72200
1557 };
1558 u8 i;
1559
1560 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1561 if (rate == ht20[i]) {
1562 if (i == ARRAY_SIZE(ht20) - 1)
1563 /* last rate uses sgi */
1564 *sgi = true;
1565 else
1566 *sgi = false;
1567
1568 *mcs = i;
1569 return true;
1570 }
1571 }
1572 return false;
1573}
1574
1575static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1576{
1577 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1578 81000, 108000, 121500, 135000,
1579 150000
1580 };
1581 u8 i;
1582
1583 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1584 if (rate == ht40[i]) {
1585 if (i == ARRAY_SIZE(ht40) - 1)
1586 /* last rate uses sgi */
1587 *sgi = true;
1588 else
1589 *sgi = false;
1590
1591 *mcs = i;
1592 return true;
1593 }
1594 }
1595
1596 return false;
1597}
1598
1599static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1600 u8 *mac, struct station_info *sinfo)
1601{
1602 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301603 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001604 long left;
1605 bool sgi;
1606 s32 rate;
1607 int ret;
1608 u8 mcs;
1609
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301610 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001611 return -ENOENT;
1612
1613 if (down_interruptible(&ar->sem))
1614 return -EBUSY;
1615
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301616 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001617
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301618 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001619
1620 if (ret != 0) {
1621 up(&ar->sem);
1622 return -EIO;
1623 }
1624
1625 left = wait_event_interruptible_timeout(ar->event_wq,
1626 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301627 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001628 WMI_TIMEOUT);
1629
1630 up(&ar->sem);
1631
1632 if (left == 0)
1633 return -ETIMEDOUT;
1634 else if (left < 0)
1635 return left;
1636
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301637 if (vif->target_stats.rx_byte) {
1638 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001639 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301640 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001641 sinfo->filled |= STATION_INFO_RX_PACKETS;
1642 }
1643
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301644 if (vif->target_stats.tx_byte) {
1645 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001646 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301647 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001648 sinfo->filled |= STATION_INFO_TX_PACKETS;
1649 }
1650
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301651 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001652 sinfo->filled |= STATION_INFO_SIGNAL;
1653
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301654 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001655
1656 if (is_rate_legacy(rate)) {
1657 sinfo->txrate.legacy = rate / 100;
1658 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1659 if (sgi) {
1660 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1661 sinfo->txrate.mcs = mcs - 1;
1662 } else {
1663 sinfo->txrate.mcs = mcs;
1664 }
1665
1666 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1667 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1668 if (sgi) {
1669 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1670 sinfo->txrate.mcs = mcs - 1;
1671 } else {
1672 sinfo->txrate.mcs = mcs;
1673 }
1674
1675 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1676 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1677 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001678 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1679 "invalid rate from stats: %d\n", rate);
1680 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001681 return 0;
1682 }
1683
1684 sinfo->filled |= STATION_INFO_TX_BITRATE;
1685
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301686 if (test_bit(CONNECTED, &vif->flags) &&
1687 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301688 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001689 sinfo->filled |= STATION_INFO_BSS_PARAM;
1690 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301691 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1692 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001693 }
1694
Kalle Valobdcd8172011-07-18 00:22:30 +03001695 return 0;
1696}
1697
1698static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1699 struct cfg80211_pmksa *pmksa)
1700{
1701 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301702 struct ath6kl_vif *vif = netdev_priv(netdev);
1703
1704 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001705 pmksa->pmkid, true);
1706}
1707
1708static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1709 struct cfg80211_pmksa *pmksa)
1710{
1711 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301712 struct ath6kl_vif *vif = netdev_priv(netdev);
1713
1714 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001715 pmksa->pmkid, false);
1716}
1717
1718static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1719{
1720 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301721 struct ath6kl_vif *vif = netdev_priv(netdev);
1722
1723 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301724 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1725 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001726 return 0;
1727}
1728
Raja Mani6cb3c712011-11-07 22:52:45 +02001729static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1730{
Raja Manic08631c2011-12-16 14:24:24 +05301731 struct in_device *in_dev;
1732 struct in_ifaddr *ifa;
Raja Mani6cb3c712011-11-07 22:52:45 +02001733 struct ath6kl_vif *vif;
1734 int ret, pos, left;
1735 u32 filter = 0;
1736 u16 i;
Raja Manic08631c2011-12-16 14:24:24 +05301737 u8 mask[WOW_MASK_SIZE], index = 0;
1738 __be32 ips[MAX_IP_ADDRS];
Raja Mani6cb3c712011-11-07 22:52:45 +02001739
1740 vif = ath6kl_vif_first(ar);
1741 if (!vif)
1742 return -EIO;
1743
1744 if (!ath6kl_cfg80211_ready(vif))
1745 return -EIO;
1746
1747 if (!test_bit(CONNECTED, &vif->flags))
1748 return -EINVAL;
1749
1750 /* Clear existing WOW patterns */
1751 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1752 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1753 WOW_LIST_ID, i);
1754 /* Configure new WOW patterns */
1755 for (i = 0; i < wow->n_patterns; i++) {
1756
1757 /*
1758 * Convert given nl80211 specific mask value to equivalent
1759 * driver specific mask value and send it to the chip along
1760 * with patterns. For example, If the mask value defined in
1761 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1762 * then equivalent driver specific mask value is
1763 * "0xFF 0x00 0xFF 0x00".
1764 */
1765 memset(&mask, 0, sizeof(mask));
1766 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1767 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1768 mask[pos] = 0xFF;
1769 }
1770 /*
1771 * Note: Pattern's offset is not passed as part of wowlan
1772 * parameter from CFG layer. So it's always passed as ZERO
1773 * to the firmware. It means, given WOW patterns are always
1774 * matched from the first byte of received pkt in the firmware.
1775 */
1776 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1777 vif->fw_vif_idx, WOW_LIST_ID,
1778 wow->patterns[i].pattern_len,
1779 0 /* pattern offset */,
1780 wow->patterns[i].pattern, mask);
1781 if (ret)
1782 return ret;
1783 }
1784
Raja Manic08631c2011-12-16 14:24:24 +05301785 /* Setup own IP addr for ARP agent. */
1786 in_dev = __in_dev_get_rtnl(vif->ndev);
1787 if (!in_dev)
1788 goto skip_arp;
1789
1790 ifa = in_dev->ifa_list;
1791 memset(&ips, 0, sizeof(ips));
1792
1793 /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
1794 while (index < MAX_IP_ADDRS && ifa) {
1795 ips[index] = ifa->ifa_local;
1796 ifa = ifa->ifa_next;
1797 index++;
1798 }
1799
1800 if (ifa) {
1801 ath6kl_err("total IP addr count is exceeding fw limit\n");
1802 return -EINVAL;
1803 }
1804
1805 ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
1806 if (ret) {
1807 ath6kl_err("fail to setup ip for arp agent\n");
1808 return ret;
1809 }
1810
1811skip_arp:
Raja Mani6cb3c712011-11-07 22:52:45 +02001812 if (wow->disconnect)
1813 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1814
1815 if (wow->magic_pkt)
1816 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1817
1818 if (wow->gtk_rekey_failure)
1819 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1820
1821 if (wow->eap_identity_req)
1822 filter |= WOW_FILTER_OPTION_EAP_REQ;
1823
1824 if (wow->four_way_handshake)
1825 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1826
1827 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1828 ATH6KL_WOW_MODE_ENABLE,
1829 filter,
1830 WOW_HOST_REQ_DELAY);
1831 if (ret)
1832 return ret;
1833
1834 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1835 ATH6KL_HOST_MODE_ASLEEP);
1836 if (ret)
1837 return ret;
1838
1839 if (ar->tx_pending[ar->ctrl_ep]) {
1840 left = wait_event_interruptible_timeout(ar->event_wq,
1841 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1842 if (left == 0) {
1843 ath6kl_warn("clear wmi ctrl data timeout\n");
1844 ret = -ETIMEDOUT;
1845 } else if (left < 0) {
1846 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1847 ret = left;
1848 }
1849 }
1850
1851 return ret;
1852}
1853
1854static int ath6kl_wow_resume(struct ath6kl *ar)
1855{
1856 struct ath6kl_vif *vif;
1857 int ret;
1858
1859 vif = ath6kl_vif_first(ar);
1860 if (!vif)
1861 return -EIO;
1862
1863 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1864 ATH6KL_HOST_MODE_AWAKE);
1865 return ret;
1866}
1867
Kalle Valo52d81a62011-11-01 08:44:21 +02001868int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001869 enum ath6kl_cfg_suspend_mode mode,
1870 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001871{
1872 int ret;
1873
Kalle Valo52d81a62011-11-01 08:44:21 +02001874 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001875 case ATH6KL_CFG_SUSPEND_WOW:
1876
1877 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1878
1879 /* Flush all non control pkts in TX path */
1880 ath6kl_tx_data_cleanup(ar);
1881
1882 ret = ath6kl_wow_suspend(ar, wow);
1883 if (ret) {
1884 ath6kl_err("wow suspend failed: %d\n", ret);
1885 return ret;
1886 }
1887 ar->state = ATH6KL_STATE_WOW;
1888 break;
1889
Kalle Valo52d81a62011-11-01 08:44:21 +02001890 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001891
Kalle Valo7125f012011-12-13 14:51:37 +02001892 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001893
Kalle Valo52d81a62011-11-01 08:44:21 +02001894 /* save the current power mode before enabling power save */
1895 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1896
1897 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1898 if (ret) {
1899 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1900 ret);
1901 }
1902
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001903 ar->state = ATH6KL_STATE_DEEPSLEEP;
1904
Kalle Valo52d81a62011-11-01 08:44:21 +02001905 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001906
1907 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001908
Kalle Valo7125f012011-12-13 14:51:37 +02001909 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02001910
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001911 if (ar->state == ATH6KL_STATE_OFF) {
1912 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1913 "suspend hw off, no action for cutpower\n");
1914 break;
1915 }
1916
1917 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1918
1919 ret = ath6kl_init_hw_stop(ar);
1920 if (ret) {
1921 ath6kl_warn("failed to stop hw during suspend: %d\n",
1922 ret);
1923 }
1924
1925 ar->state = ATH6KL_STATE_CUTPOWER;
1926
1927 break;
1928
Kalle Valo10509f92011-12-13 14:52:07 +02001929 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
1930 /*
1931 * Nothing needed for schedule scan, firmware is already in
1932 * wow mode and sleeping most of the time.
1933 */
1934 break;
1935
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001936 default:
1937 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001938 }
1939
1940 return 0;
1941}
1942
1943int ath6kl_cfg80211_resume(struct ath6kl *ar)
1944{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001945 int ret;
1946
1947 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001948 case ATH6KL_STATE_WOW:
1949 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1950
1951 ret = ath6kl_wow_resume(ar);
1952 if (ret) {
1953 ath6kl_warn("wow mode resume failed: %d\n", ret);
1954 return ret;
1955 }
1956
1957 ar->state = ATH6KL_STATE_ON;
1958 break;
1959
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001960 case ATH6KL_STATE_DEEPSLEEP:
1961 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1962 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1963 ar->wmi->saved_pwr_mode);
1964 if (ret) {
1965 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1966 ret);
1967 }
1968 }
1969
1970 ar->state = ATH6KL_STATE_ON;
1971
1972 break;
1973
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001974 case ATH6KL_STATE_CUTPOWER:
1975 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1976
1977 ret = ath6kl_init_hw_start(ar);
1978 if (ret) {
1979 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1980 return ret;
1981 }
Raja Manid7c44e02011-11-07 22:52:46 +02001982 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001983
Kalle Valo10509f92011-12-13 14:52:07 +02001984 case ATH6KL_STATE_SCHED_SCAN:
1985 break;
1986
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001987 default:
1988 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001989 }
1990
1991 return 0;
1992}
1993
Kalle Valoabcb3442011-07-22 08:26:20 +03001994#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001995
1996/* hif layer decides what suspend mode to use */
1997static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001998 struct cfg80211_wowlan *wow)
1999{
2000 struct ath6kl *ar = wiphy_priv(wiphy);
2001
Raja Mani0f60e9f2011-11-07 22:52:45 +02002002 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03002003}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002004
Kalle Valo52d81a62011-11-01 08:44:21 +02002005static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002006{
2007 struct ath6kl *ar = wiphy_priv(wiphy);
2008
2009 return ath6kl_hif_resume(ar);
2010}
Raja Mania918fb32011-11-07 22:52:46 +02002011
2012/*
2013 * FIXME: WOW suspend mode is selected if the host sdio controller supports
2014 * both sdio irq wake up and keep power. The target pulls sdio data line to
2015 * wake up the host when WOW pattern matches. This causes sdio irq handler
2016 * is being called in the host side which internally hits ath6kl's RX path.
2017 *
2018 * Since sdio interrupt is not disabled, RX path executes even before
2019 * the host executes the actual resume operation from PM module.
2020 *
2021 * In the current scenario, WOW resume should happen before start processing
2022 * any data from the target. So It's required to perform WOW resume in RX path.
2023 * Ideally we should perform WOW resume only in the actual platform
2024 * resume path. This area needs bit rework to avoid WOW resume in RX path.
2025 *
2026 * ath6kl_check_wow_status() is called from ath6kl_rx().
2027 */
2028void ath6kl_check_wow_status(struct ath6kl *ar)
2029{
2030 if (ar->state == ATH6KL_STATE_WOW)
2031 ath6kl_cfg80211_resume(ar);
2032}
2033
2034#else
2035
2036void ath6kl_check_wow_status(struct ath6kl *ar)
2037{
2038}
Kalle Valoabcb3442011-07-22 08:26:20 +03002039#endif
2040
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002041static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
2042 struct ieee80211_channel *chan,
2043 enum nl80211_channel_type channel_type)
2044{
Sujith Manoharane68f6752011-12-22 12:15:27 +05302045 struct ath6kl_vif *vif;
2046
2047 /*
2048 * 'dev' could be NULL if a channel change is required for the hardware
2049 * device itself, instead of a particular VIF.
2050 *
2051 * FIXME: To be handled properly when monitor mode is supported.
2052 */
2053 if (!dev)
2054 return -EBUSY;
2055
2056 vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002057
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302058 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002059 return -EIO;
2060
2061 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
2062 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302063 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002064
2065 return 0;
2066}
2067
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002068static bool ath6kl_is_p2p_ie(const u8 *pos)
2069{
2070 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2071 pos[2] == 0x50 && pos[3] == 0x6f &&
2072 pos[4] == 0x9a && pos[5] == 0x09;
2073}
2074
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302075static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2076 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002077{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302078 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002079 const u8 *pos;
2080 u8 *buf = NULL;
2081 size_t len = 0;
2082 int ret;
2083
2084 /*
2085 * Filter out P2P IE(s) since they will be included depending on
2086 * the Probe Request frame in ath6kl_send_go_probe_resp().
2087 */
2088
2089 if (ies && ies_len) {
2090 buf = kmalloc(ies_len, GFP_KERNEL);
2091 if (buf == NULL)
2092 return -ENOMEM;
2093 pos = ies;
2094 while (pos + 1 < ies + ies_len) {
2095 if (pos + 2 + pos[1] > ies + ies_len)
2096 break;
2097 if (!ath6kl_is_p2p_ie(pos)) {
2098 memcpy(buf + len, pos, 2 + pos[1]);
2099 len += 2 + pos[1];
2100 }
2101 pos += 2 + pos[1];
2102 }
2103 }
2104
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302105 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2106 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002107 kfree(buf);
2108 return ret;
2109}
2110
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002111static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2112 struct beacon_parameters *info, bool add)
2113{
2114 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302115 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002116 struct ieee80211_mgmt *mgmt;
2117 u8 *ies;
2118 int ies_len;
2119 struct wmi_connect_cmd p;
2120 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302121 int i, ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002122
2123 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2124
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302125 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002126 return -EIO;
2127
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302128 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002129 return -EOPNOTSUPP;
2130
2131 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302132 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2133 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002134 info->beacon_ies,
2135 info->beacon_ies_len);
2136 if (res)
2137 return res;
2138 }
2139 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302140 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002141 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002142 if (res)
2143 return res;
2144 }
2145 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302146 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2147 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002148 info->assocresp_ies,
2149 info->assocresp_ies_len);
2150 if (res)
2151 return res;
2152 }
2153
2154 if (!add)
2155 return 0;
2156
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002157 ar->ap_mode_bkey.valid = false;
2158
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002159 /* TODO:
2160 * info->interval
2161 * info->dtim_period
2162 */
2163
2164 if (info->head == NULL)
2165 return -EINVAL;
2166 mgmt = (struct ieee80211_mgmt *) info->head;
2167 ies = mgmt->u.beacon.variable;
2168 if (ies > info->head + info->head_len)
2169 return -EINVAL;
2170 ies_len = info->head + info->head_len - ies;
2171
2172 if (info->ssid == NULL)
2173 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302174 memcpy(vif->ssid, info->ssid, info->ssid_len);
2175 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002176 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2177 return -EOPNOTSUPP; /* TODO */
2178
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302179 ret = ath6kl_set_auth_type(vif, info->auth_type);
2180 if (ret)
2181 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002182
2183 memset(&p, 0, sizeof(p));
2184
2185 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2186 switch (info->crypto.akm_suites[i]) {
2187 case WLAN_AKM_SUITE_8021X:
2188 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2189 p.auth_mode |= WPA_AUTH;
2190 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2191 p.auth_mode |= WPA2_AUTH;
2192 break;
2193 case WLAN_AKM_SUITE_PSK:
2194 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2195 p.auth_mode |= WPA_PSK_AUTH;
2196 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2197 p.auth_mode |= WPA2_PSK_AUTH;
2198 break;
2199 }
2200 }
2201 if (p.auth_mode == 0)
2202 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302203 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002204
2205 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2206 switch (info->crypto.ciphers_pairwise[i]) {
2207 case WLAN_CIPHER_SUITE_WEP40:
2208 case WLAN_CIPHER_SUITE_WEP104:
2209 p.prwise_crypto_type |= WEP_CRYPT;
2210 break;
2211 case WLAN_CIPHER_SUITE_TKIP:
2212 p.prwise_crypto_type |= TKIP_CRYPT;
2213 break;
2214 case WLAN_CIPHER_SUITE_CCMP:
2215 p.prwise_crypto_type |= AES_CRYPT;
2216 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002217 case WLAN_CIPHER_SUITE_SMS4:
2218 p.prwise_crypto_type |= WAPI_CRYPT;
2219 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002220 }
2221 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002222 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002223 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302224 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002225 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302226 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002227
2228 switch (info->crypto.cipher_group) {
2229 case WLAN_CIPHER_SUITE_WEP40:
2230 case WLAN_CIPHER_SUITE_WEP104:
2231 p.grp_crypto_type = WEP_CRYPT;
2232 break;
2233 case WLAN_CIPHER_SUITE_TKIP:
2234 p.grp_crypto_type = TKIP_CRYPT;
2235 break;
2236 case WLAN_CIPHER_SUITE_CCMP:
2237 p.grp_crypto_type = AES_CRYPT;
2238 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002239 case WLAN_CIPHER_SUITE_SMS4:
2240 p.grp_crypto_type = WAPI_CRYPT;
2241 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002242 default:
2243 p.grp_crypto_type = NONE_CRYPT;
2244 break;
2245 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302246 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002247
2248 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302249 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002250
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302251 p.ssid_len = vif->ssid_len;
2252 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2253 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302254 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002255
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302256 /* Enable uAPSD support by default */
2257 res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
2258 if (res < 0)
2259 return res;
2260
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002261 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2262 p.nw_subtype = SUBTYPE_P2PGO;
2263 } else {
2264 /*
2265 * Due to firmware limitation, it is not possible to
2266 * do P2P mgmt operations in AP mode
2267 */
2268 p.nw_subtype = SUBTYPE_NONE;
2269 }
2270
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302271 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002272 if (res < 0)
2273 return res;
2274
2275 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002276}
2277
2278static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2279 struct beacon_parameters *info)
2280{
2281 return ath6kl_ap_beacon(wiphy, dev, info, true);
2282}
2283
2284static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2285 struct beacon_parameters *info)
2286{
2287 return ath6kl_ap_beacon(wiphy, dev, info, false);
2288}
2289
2290static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2291{
2292 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302293 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002294
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302295 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002296 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302297 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002298 return -ENOTCONN;
2299
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302300 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302301 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002302
2303 return 0;
2304}
2305
Jouni Malinen33e53082011-12-27 11:02:56 +02002306static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2307
2308static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
2309 u8 *mac)
2310{
2311 struct ath6kl *ar = ath6kl_priv(dev);
2312 struct ath6kl_vif *vif = netdev_priv(dev);
2313 const u8 *addr = mac ? mac : bcast_addr;
2314
2315 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
2316 addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
2317}
2318
Jouni Malinen23875132011-08-30 21:57:53 +03002319static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2320 u8 *mac, struct station_parameters *params)
2321{
2322 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302323 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002324
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302325 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002326 return -EOPNOTSUPP;
2327
2328 /* Use this only for authorizing/unauthorizing a station */
2329 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2330 return -EOPNOTSUPP;
2331
2332 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302333 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2334 WMI_AP_MLME_AUTHORIZE, mac, 0);
2335 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2336 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002337}
2338
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002339static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2340 struct net_device *dev,
2341 struct ieee80211_channel *chan,
2342 enum nl80211_channel_type channel_type,
2343 unsigned int duration,
2344 u64 *cookie)
2345{
2346 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302347 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002348 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002349
2350 /* TODO: if already pending or ongoing remain-on-channel,
2351 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002352 id = ++vif->last_roc_id;
2353 if (id == 0) {
2354 /* Do not use 0 as the cookie value */
2355 id = ++vif->last_roc_id;
2356 }
2357 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002358
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302359 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2360 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002361}
2362
2363static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2364 struct net_device *dev,
2365 u64 cookie)
2366{
2367 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302368 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002369
Jouni Malinen10522612011-10-27 16:00:13 +03002370 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002371 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002372 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002373
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302374 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002375}
2376
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302377static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2378 const u8 *buf, size_t len,
2379 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002380{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302381 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002382 const u8 *pos;
2383 u8 *p2p;
2384 int p2p_len;
2385 int ret;
2386 const struct ieee80211_mgmt *mgmt;
2387
2388 mgmt = (const struct ieee80211_mgmt *) buf;
2389
2390 /* Include P2P IE(s) from the frame generated in user space. */
2391
2392 p2p = kmalloc(len, GFP_KERNEL);
2393 if (p2p == NULL)
2394 return -ENOMEM;
2395 p2p_len = 0;
2396
2397 pos = mgmt->u.probe_resp.variable;
2398 while (pos + 1 < buf + len) {
2399 if (pos + 2 + pos[1] > buf + len)
2400 break;
2401 if (ath6kl_is_p2p_ie(pos)) {
2402 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2403 p2p_len += 2 + pos[1];
2404 }
2405 pos += 2 + pos[1];
2406 }
2407
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302408 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2409 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002410 kfree(p2p);
2411 return ret;
2412}
2413
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002414static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2415 struct ieee80211_channel *chan, bool offchan,
2416 enum nl80211_channel_type channel_type,
2417 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002418 const u8 *buf, size_t len, bool no_cck,
2419 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002420{
2421 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302422 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002423 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002424 const struct ieee80211_mgmt *mgmt;
2425
2426 mgmt = (const struct ieee80211_mgmt *) buf;
2427 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302428 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002429 ieee80211_is_probe_resp(mgmt->frame_control)) {
2430 /*
2431 * Send Probe Response frame in AP mode using a separate WMI
2432 * command to allow the target to fill in the generic IEs.
2433 */
2434 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302435 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002436 chan->center_freq);
2437 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002438
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302439 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002440 if (id == 0) {
2441 /*
2442 * 0 is a reserved value in the WMI command and shall not be
2443 * used for the command.
2444 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302445 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002446 }
2447
2448 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002449
2450 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
2451 ar->fw_capabilities)) {
2452 /*
2453 * If capable of doing P2P mgmt operations using
2454 * station interface, send additional information like
2455 * supported rates to advertise and xmit rates for
2456 * probe requests
2457 */
2458 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
2459 chan->center_freq, wait,
2460 buf, len, no_cck);
2461 } else {
2462 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2463 chan->center_freq, wait,
2464 buf, len);
2465 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002466}
2467
Jouni Malinenae32c302011-08-30 21:58:01 +03002468static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2469 struct net_device *dev,
2470 u16 frame_type, bool reg)
2471{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302472 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002473
2474 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2475 __func__, frame_type, reg);
2476 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2477 /*
2478 * Note: This notification callback is not allowed to sleep, so
2479 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2480 * hardcode target to report Probe Request frames all the time.
2481 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302482 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002483 }
2484}
2485
Kalle Valo10509f92011-12-13 14:52:07 +02002486static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2487 struct net_device *dev,
2488 struct cfg80211_sched_scan_request *request)
2489{
2490 struct ath6kl *ar = ath6kl_priv(dev);
2491 struct ath6kl_vif *vif = netdev_priv(dev);
2492 u16 interval;
2493 int ret;
2494 u8 i;
2495
2496 if (ar->state != ATH6KL_STATE_ON)
2497 return -EIO;
2498
2499 if (vif->sme_state != SME_DISCONNECTED)
2500 return -EBUSY;
2501
2502 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2503 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2504 i, DISABLE_SSID_FLAG,
2505 0, NULL);
2506 }
2507
2508 /* fw uses seconds, also make sure that it's >0 */
2509 interval = max_t(u16, 1, request->interval / 1000);
2510
2511 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2512 interval, interval,
2513 10, 0, 0, 0, 3, 0, 0, 0);
2514
2515 if (request->n_ssids && request->ssids[0].ssid_len) {
2516 for (i = 0; i < request->n_ssids; i++) {
2517 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2518 i, SPECIFIC_SSID_FLAG,
2519 request->ssids[i].ssid_len,
2520 request->ssids[i].ssid);
2521 }
2522 }
2523
2524 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2525 ATH6KL_WOW_MODE_ENABLE,
2526 WOW_FILTER_SSID,
2527 WOW_HOST_REQ_DELAY);
2528 if (ret) {
2529 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
2530 return ret;
2531 }
2532
2533 /* this also clears IE in fw if it's not set */
2534 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2535 WMI_FRAME_PROBE_REQ,
2536 request->ie, request->ie_len);
2537 if (ret) {
2538 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
2539 ret);
2540 return ret;
2541 }
2542
2543 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2544 ATH6KL_HOST_MODE_ASLEEP);
2545 if (ret) {
2546 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
2547 ret);
2548 return ret;
2549 }
2550
2551 ar->state = ATH6KL_STATE_SCHED_SCAN;
2552
2553 return ret;
2554}
2555
2556static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
2557 struct net_device *dev)
2558{
2559 struct ath6kl_vif *vif = netdev_priv(dev);
2560 bool stopped;
2561
2562 stopped = __ath6kl_cfg80211_sscan_stop(vif);
2563
2564 if (!stopped)
2565 return -EIO;
2566
2567 return 0;
2568}
2569
Jouni Malinenf80574a2011-08-30 21:58:04 +03002570static const struct ieee80211_txrx_stypes
2571ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2572 [NL80211_IFTYPE_STATION] = {
2573 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2574 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2575 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2576 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2577 },
Jouni Malinenba1f6fe2011-12-27 11:03:53 +02002578 [NL80211_IFTYPE_AP] = {
2579 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2580 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2581 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2582 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2583 },
Jouni Malinenf80574a2011-08-30 21:58:04 +03002584 [NL80211_IFTYPE_P2P_CLIENT] = {
2585 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2586 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2587 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2588 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2589 },
2590 [NL80211_IFTYPE_P2P_GO] = {
2591 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2592 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2593 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2594 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2595 },
2596};
2597
Kalle Valobdcd8172011-07-18 00:22:30 +03002598static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302599 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2600 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002601 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2602 .scan = ath6kl_cfg80211_scan,
2603 .connect = ath6kl_cfg80211_connect,
2604 .disconnect = ath6kl_cfg80211_disconnect,
2605 .add_key = ath6kl_cfg80211_add_key,
2606 .get_key = ath6kl_cfg80211_get_key,
2607 .del_key = ath6kl_cfg80211_del_key,
2608 .set_default_key = ath6kl_cfg80211_set_default_key,
2609 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2610 .set_tx_power = ath6kl_cfg80211_set_txpower,
2611 .get_tx_power = ath6kl_cfg80211_get_txpower,
2612 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2613 .join_ibss = ath6kl_cfg80211_join_ibss,
2614 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2615 .get_station = ath6kl_get_station,
2616 .set_pmksa = ath6kl_set_pmksa,
2617 .del_pmksa = ath6kl_del_pmksa,
2618 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002619 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002620#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002621 .suspend = __ath6kl_cfg80211_suspend,
2622 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002623#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002624 .set_channel = ath6kl_set_channel,
2625 .add_beacon = ath6kl_add_beacon,
2626 .set_beacon = ath6kl_set_beacon,
2627 .del_beacon = ath6kl_del_beacon,
Jouni Malinen33e53082011-12-27 11:02:56 +02002628 .del_station = ath6kl_del_station,
Jouni Malinen23875132011-08-30 21:57:53 +03002629 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002630 .remain_on_channel = ath6kl_remain_on_channel,
2631 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002632 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002633 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valo10509f92011-12-13 14:52:07 +02002634 .sched_scan_start = ath6kl_cfg80211_sscan_start,
2635 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Kalle Valobdcd8172011-07-18 00:22:30 +03002636};
2637
Kalle Valo7125f012011-12-13 14:51:37 +02002638void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02002639{
Kalle Valo10509f92011-12-13 14:52:07 +02002640 ath6kl_cfg80211_sscan_disable(vif);
2641
Kalle Valoec4b7f62011-11-01 08:44:04 +02002642 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02002643 case SME_DISCONNECTED:
2644 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02002645 case SME_CONNECTING:
2646 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2647 NULL, 0,
2648 WLAN_STATUS_UNSPECIFIED_FAILURE,
2649 GFP_KERNEL);
2650 break;
2651 case SME_CONNECTED:
Kalle Valoec4b7f62011-11-01 08:44:04 +02002652 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2653 break;
2654 }
2655
2656 if (test_bit(CONNECTED, &vif->flags) ||
2657 test_bit(CONNECT_PEND, &vif->flags))
Kalle Valo7125f012011-12-13 14:51:37 +02002658 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002659
2660 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002661 clear_bit(CONNECTED, &vif->flags);
2662 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002663
2664 /* disable scanning */
Kalle Valo7125f012011-12-13 14:51:37 +02002665 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
2666 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
2667 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02002668
2669 ath6kl_cfg80211_scan_complete_event(vif, true);
2670}
2671
Kalle Valo7125f012011-12-13 14:51:37 +02002672void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
2673{
2674 struct ath6kl_vif *vif;
2675
2676 vif = ath6kl_vif_first(ar);
2677 if (!vif) {
2678 /* save the current power mode before enabling power save */
2679 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2680
2681 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2682 ath6kl_warn("ath6kl_deep_sleep_enable: "
2683 "wmi_powermode_cmd failed\n");
2684 return;
2685 }
2686
2687 /*
2688 * FIXME: we should take ar->list_lock to protect changes in the
2689 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
2690 * sleeps.
2691 */
2692 list_for_each_entry(vif, &ar->vif_list, list)
2693 ath6kl_cfg80211_stop(vif);
2694}
2695
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302696struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002697{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002698 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302699 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302700 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002701
2702 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302703 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302704
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302705 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002706 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002707 return NULL;
2708 }
2709
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302710 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan774439a2011-11-18 10:05:26 +05302711 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302712 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302713 ar->dev = dev;
2714
Kalle Valo71f96ee2011-11-14 19:31:30 +02002715 ar->vif_max = 1;
2716
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302717 ar->max_norm_iface = 1;
2718
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302719 spin_lock_init(&ar->lock);
2720 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302721 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302722
2723 init_waitqueue_head(&ar->event_wq);
2724 sema_init(&ar->sem, 1);
2725
2726 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302727 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302728
2729 clear_bit(WMI_ENABLED, &ar->flag);
2730 clear_bit(SKIP_SCAN, &ar->flag);
2731 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2732
Sujith Manoharan82327362012-01-10 09:54:10 +05302733 ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302734 ar->tx_pwr = 0;
2735
2736 ar->intra_bss = 1;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302737 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2738
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002739 ar->state = ATH6KL_STATE_OFF;
2740
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302741 memset((u8 *)ar->sta_list, 0,
2742 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2743
2744 /* Init the PS queues */
2745 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2746 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2747 skb_queue_head_init(&ar->sta_list[ctr].psq);
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302748 skb_queue_head_init(&ar->sta_list[ctr].apsdq);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302749 }
2750
2751 skb_queue_head_init(&ar->mcastpsq);
2752
2753 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2754
2755 return ar;
2756}
2757
2758int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2759{
2760 struct wiphy *wiphy = ar->wiphy;
2761 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002762
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302763 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002764
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302765 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002766
Kalle Valobdcd8172011-07-18 00:22:30 +03002767 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302768 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002769
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302770 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302771 BIT(NL80211_IFTYPE_ADHOC) |
2772 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002773 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302774 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302775 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002776 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302777
Kalle Valobdcd8172011-07-18 00:22:30 +03002778 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302779 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2780 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2781 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2782 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2783 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002784
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302785 wiphy->cipher_suites = cipher_suites;
2786 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002787
Raja Manieae9e062011-11-07 22:52:46 +02002788 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2789 WIPHY_WOWLAN_DISCONNECT |
2790 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2791 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2792 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2793 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2794 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2795 wiphy->wowlan.pattern_min_len = 1;
2796 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2797
Kalle Valo10509f92011-12-13 14:52:07 +02002798 wiphy->max_sched_scan_ssids = 10;
2799
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302800 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002801 if (ret < 0) {
2802 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302803 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002804 }
2805
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302806 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002807}
2808
Kalle Valoc25889e2012-01-17 20:08:27 +02002809static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002810{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302811 vif->aggr_cntxt = aggr_init(vif->ndev);
2812 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302813 ath6kl_err("failed to initialize aggr\n");
2814 return -ENOMEM;
2815 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002816
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302817 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302818 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02002819 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
2820 (unsigned long) vif);
2821
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302822 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302823 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302824
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302825 INIT_LIST_HEAD(&vif->mc_filter);
2826
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302827 return 0;
2828}
2829
Kalle Valoc25889e2012-01-17 20:08:27 +02002830void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302831{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302832 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302833 struct ath6kl_mc_filter *mc_filter, *tmp;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302834
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302835 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302836
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302837 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2838
2839 if (vif->nw_type == ADHOC_NETWORK)
2840 ar->ibss_if_active = false;
2841
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05302842 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
2843 list_del(&mc_filter->list);
2844 kfree(mc_filter);
2845 }
2846
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302847 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302848
2849 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302850}
2851
2852struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302853 enum nl80211_iftype type, u8 fw_vif_idx,
2854 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302855{
2856 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302857 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302858
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302859 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302860 if (!ndev)
2861 return NULL;
2862
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302863 vif = netdev_priv(ndev);
2864 ndev->ieee80211_ptr = &vif->wdev;
2865 vif->wdev.wiphy = ar->wiphy;
2866 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302867 vif->ndev = ndev;
2868 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2869 vif->wdev.netdev = ndev;
2870 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302871 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302872 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302873
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302874 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2875 if (fw_vif_idx != 0)
2876 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2877 0x2;
2878
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302879 init_netdev(ndev);
2880
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302881 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302882
Kalle Valoc25889e2012-01-17 20:08:27 +02002883 if (ath6kl_cfg80211_vif_init(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302884 goto err;
2885
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302886 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302887 goto err;
2888
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302889 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302890 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302891 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302892 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302893 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302894
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302895 if (type == NL80211_IFTYPE_ADHOC)
2896 ar->ibss_if_active = true;
2897
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302898 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302899 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302900 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302901
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302902 return ndev;
2903
2904err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302905 aggr_module_destroy(vif->aggr_cntxt);
2906 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302907 return NULL;
2908}
2909
2910void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2911{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302912 wiphy_unregister(ar->wiphy);
2913 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002914}