blob: 5dab4f20146a05fa682ccef1c59a6f7ddd30bf84 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053024static unsigned int multi_norm_if_support;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030025
26module_param(ath6kl_p2p, uint, 0644);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053027module_param(multi_norm_if_support, uint, 0644);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030028
Kalle Valobdcd8172011-07-18 00:22:30 +030029#define RATETAB_ENT(_rate, _rateid, _flags) { \
30 .bitrate = (_rate), \
31 .flags = (_flags), \
32 .hw_value = (_rateid), \
33}
34
35#define CHAN2G(_channel, _freq, _flags) { \
36 .band = IEEE80211_BAND_2GHZ, \
37 .hw_value = (_channel), \
38 .center_freq = (_freq), \
39 .flags = (_flags), \
40 .max_antenna_gain = 0, \
41 .max_power = 30, \
42}
43
44#define CHAN5G(_channel, _flags) { \
45 .band = IEEE80211_BAND_5GHZ, \
46 .hw_value = (_channel), \
47 .center_freq = 5000 + (5 * (_channel)), \
48 .flags = (_flags), \
49 .max_antenna_gain = 0, \
50 .max_power = 30, \
51}
52
53static struct ieee80211_rate ath6kl_rates[] = {
54 RATETAB_ENT(10, 0x1, 0),
55 RATETAB_ENT(20, 0x2, 0),
56 RATETAB_ENT(55, 0x4, 0),
57 RATETAB_ENT(110, 0x8, 0),
58 RATETAB_ENT(60, 0x10, 0),
59 RATETAB_ENT(90, 0x20, 0),
60 RATETAB_ENT(120, 0x40, 0),
61 RATETAB_ENT(180, 0x80, 0),
62 RATETAB_ENT(240, 0x100, 0),
63 RATETAB_ENT(360, 0x200, 0),
64 RATETAB_ENT(480, 0x400, 0),
65 RATETAB_ENT(540, 0x800, 0),
66};
67
68#define ath6kl_a_rates (ath6kl_rates + 4)
69#define ath6kl_a_rates_size 8
70#define ath6kl_g_rates (ath6kl_rates + 0)
71#define ath6kl_g_rates_size 12
72
73static struct ieee80211_channel ath6kl_2ghz_channels[] = {
74 CHAN2G(1, 2412, 0),
75 CHAN2G(2, 2417, 0),
76 CHAN2G(3, 2422, 0),
77 CHAN2G(4, 2427, 0),
78 CHAN2G(5, 2432, 0),
79 CHAN2G(6, 2437, 0),
80 CHAN2G(7, 2442, 0),
81 CHAN2G(8, 2447, 0),
82 CHAN2G(9, 2452, 0),
83 CHAN2G(10, 2457, 0),
84 CHAN2G(11, 2462, 0),
85 CHAN2G(12, 2467, 0),
86 CHAN2G(13, 2472, 0),
87 CHAN2G(14, 2484, 0),
88};
89
90static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
91 CHAN5G(34, 0), CHAN5G(36, 0),
92 CHAN5G(38, 0), CHAN5G(40, 0),
93 CHAN5G(42, 0), CHAN5G(44, 0),
94 CHAN5G(46, 0), CHAN5G(48, 0),
95 CHAN5G(52, 0), CHAN5G(56, 0),
96 CHAN5G(60, 0), CHAN5G(64, 0),
97 CHAN5G(100, 0), CHAN5G(104, 0),
98 CHAN5G(108, 0), CHAN5G(112, 0),
99 CHAN5G(116, 0), CHAN5G(120, 0),
100 CHAN5G(124, 0), CHAN5G(128, 0),
101 CHAN5G(132, 0), CHAN5G(136, 0),
102 CHAN5G(140, 0), CHAN5G(149, 0),
103 CHAN5G(153, 0), CHAN5G(157, 0),
104 CHAN5G(161, 0), CHAN5G(165, 0),
105 CHAN5G(184, 0), CHAN5G(188, 0),
106 CHAN5G(192, 0), CHAN5G(196, 0),
107 CHAN5G(200, 0), CHAN5G(204, 0),
108 CHAN5G(208, 0), CHAN5G(212, 0),
109 CHAN5G(216, 0),
110};
111
112static struct ieee80211_supported_band ath6kl_band_2ghz = {
113 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
114 .channels = ath6kl_2ghz_channels,
115 .n_bitrates = ath6kl_g_rates_size,
116 .bitrates = ath6kl_g_rates,
117};
118
119static struct ieee80211_supported_band ath6kl_band_5ghz = {
120 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
121 .channels = ath6kl_5ghz_a_channels,
122 .n_bitrates = ath6kl_a_rates_size,
123 .bitrates = ath6kl_a_rates,
124};
125
Jouni Malinen837cb972011-10-11 17:31:57 +0300126#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
127
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530128static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300129 enum nl80211_wpa_versions wpa_version)
130{
131 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
132
133 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530134 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300135 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530136 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300137 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530138 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300139 } else {
140 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
141 return -ENOTSUPP;
142 }
143
144 return 0;
145}
146
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530147static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300148 enum nl80211_auth_type auth_type)
149{
Kalle Valobdcd8172011-07-18 00:22:30 +0300150 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
151
152 switch (auth_type) {
153 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530154 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300155 break;
156 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530157 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300158 break;
159 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530160 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300161 break;
162
163 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530164 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 break;
166
167 default:
168 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
169 return -ENOTSUPP;
170 }
171
172 return 0;
173}
174
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530175static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300176{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530177 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
178 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
179 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300180
181 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
182 __func__, cipher, ucast);
183
184 switch (cipher) {
185 case 0:
186 /* our own hack to use value 0 as no crypto used */
187 *ar_cipher = NONE_CRYPT;
188 *ar_cipher_len = 0;
189 break;
190 case WLAN_CIPHER_SUITE_WEP40:
191 *ar_cipher = WEP_CRYPT;
192 *ar_cipher_len = 5;
193 break;
194 case WLAN_CIPHER_SUITE_WEP104:
195 *ar_cipher = WEP_CRYPT;
196 *ar_cipher_len = 13;
197 break;
198 case WLAN_CIPHER_SUITE_TKIP:
199 *ar_cipher = TKIP_CRYPT;
200 *ar_cipher_len = 0;
201 break;
202 case WLAN_CIPHER_SUITE_CCMP:
203 *ar_cipher = AES_CRYPT;
204 *ar_cipher_len = 0;
205 break;
206 default:
207 ath6kl_err("cipher 0x%x not supported\n", cipher);
208 return -ENOTSUPP;
209 }
210
211 return 0;
212}
213
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530214static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300215{
216 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
217
218 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530219 if (vif->auth_mode == WPA_AUTH)
220 vif->auth_mode = WPA_PSK_AUTH;
221 else if (vif->auth_mode == WPA2_AUTH)
222 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300223 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530224 if (vif->auth_mode == WPA_AUTH)
225 vif->auth_mode = WPA_AUTH_CCKM;
226 else if (vif->auth_mode == WPA2_AUTH)
227 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300228 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530229 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300230 }
231}
232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530233static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300234{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530235 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530236
Kalle Valobdcd8172011-07-18 00:22:30 +0300237 if (!test_bit(WMI_READY, &ar->flag)) {
238 ath6kl_err("wmi is not ready\n");
239 return false;
240 }
241
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530242 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300243 ath6kl_err("wlan disabled\n");
244 return false;
245 }
246
247 return true;
248}
249
Kevin Fang6981ffd2011-10-07 08:51:19 +0800250static bool ath6kl_is_wpa_ie(const u8 *pos)
251{
252 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
253 pos[2] == 0x00 && pos[3] == 0x50 &&
254 pos[4] == 0xf2 && pos[5] == 0x01;
255}
256
257static bool ath6kl_is_rsn_ie(const u8 *pos)
258{
259 return pos[0] == WLAN_EID_RSN;
260}
261
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700262static bool ath6kl_is_wps_ie(const u8 *pos)
263{
264 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
265 pos[1] >= 4 &&
266 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
267 pos[5] == 0x04);
268}
269
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530270static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
271 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800272{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530273 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800274 const u8 *pos;
275 u8 *buf = NULL;
276 size_t len = 0;
277 int ret;
278
279 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700280 * Clear previously set flag
281 */
282
283 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
284
285 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800286 * Filter out RSN/WPA IE(s)
287 */
288
289 if (ies && ies_len) {
290 buf = kmalloc(ies_len, GFP_KERNEL);
291 if (buf == NULL)
292 return -ENOMEM;
293 pos = ies;
294
295 while (pos + 1 < ies + ies_len) {
296 if (pos + 2 + pos[1] > ies + ies_len)
297 break;
298 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
299 memcpy(buf + len, pos, 2 + pos[1]);
300 len += 2 + pos[1];
301 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700302
303 if (ath6kl_is_wps_ie(pos))
304 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
305
Kevin Fang6981ffd2011-10-07 08:51:19 +0800306 pos += 2 + pos[1];
307 }
308 }
309
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530310 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
311 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800312 kfree(buf);
313 return ret;
314}
315
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530316static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
317{
318 switch (type) {
319 case NL80211_IFTYPE_STATION:
320 *nw_type = INFRA_NETWORK;
321 break;
322 case NL80211_IFTYPE_ADHOC:
323 *nw_type = ADHOC_NETWORK;
324 break;
325 case NL80211_IFTYPE_AP:
326 *nw_type = AP_NETWORK;
327 break;
328 case NL80211_IFTYPE_P2P_CLIENT:
329 *nw_type = INFRA_NETWORK;
330 break;
331 case NL80211_IFTYPE_P2P_GO:
332 *nw_type = AP_NETWORK;
333 break;
334 default:
335 ath6kl_err("invalid interface type %u\n", type);
336 return -ENOTSUPP;
337 }
338
339 return 0;
340}
341
342static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
343 u8 *if_idx, u8 *nw_type)
344{
345 int i;
346
347 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
348 return false;
349
350 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
351 ar->num_vif))
352 return false;
353
354 if (type == NL80211_IFTYPE_STATION ||
355 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
356 for (i = 0; i < MAX_NUM_VIF; i++) {
357 if ((ar->avail_idx_map >> i) & BIT(0)) {
358 *if_idx = i;
359 return true;
360 }
361 }
362 }
363
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530364 if (type == NL80211_IFTYPE_P2P_CLIENT ||
365 type == NL80211_IFTYPE_P2P_GO) {
366 for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
367 if ((ar->avail_idx_map >> i) & BIT(0)) {
368 *if_idx = i;
369 return true;
370 }
371 }
372 }
373
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530374 return false;
375}
376
Kalle Valobdcd8172011-07-18 00:22:30 +0300377static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
378 struct cfg80211_connect_params *sme)
379{
380 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530381 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300382 int status;
383
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530384 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300385
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530386 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300387 return -EIO;
388
389 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
390 ath6kl_err("destroy in progress\n");
391 return -EBUSY;
392 }
393
394 if (test_bit(SKIP_SCAN, &ar->flag) &&
395 ((sme->channel && sme->channel->center_freq == 0) ||
396 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
397 ath6kl_err("SkipScan: channel or bssid invalid\n");
398 return -EINVAL;
399 }
400
401 if (down_interruptible(&ar->sem)) {
402 ath6kl_err("busy, couldn't get access\n");
403 return -ERESTARTSYS;
404 }
405
406 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
407 ath6kl_err("busy, destroy in progress\n");
408 up(&ar->sem);
409 return -EBUSY;
410 }
411
412 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
413 /*
414 * sleep until the command queue drains
415 */
416 wait_event_interruptible_timeout(ar->event_wq,
417 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
418 WMI_TIMEOUT);
419 if (signal_pending(current)) {
420 ath6kl_err("cmd queue drain timeout\n");
421 up(&ar->sem);
422 return -EINTR;
423 }
424 }
425
Kevin Fang6981ffd2011-10-07 08:51:19 +0800426 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530427 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800428 if (status)
429 return status;
430 }
431
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530432 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530433 vif->ssid_len == sme->ssid_len &&
434 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530435 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530436 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
437 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530438 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300439
440 up(&ar->sem);
441 if (status) {
442 ath6kl_err("wmi_reconnect_cmd failed\n");
443 return -EIO;
444 }
445 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530446 } else if (vif->ssid_len == sme->ssid_len &&
447 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530448 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300449 }
450
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530451 memset(vif->ssid, 0, sizeof(vif->ssid));
452 vif->ssid_len = sme->ssid_len;
453 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300454
455 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530456 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300457
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530458 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300459 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530460 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300461
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530462 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300463
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530464 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 if (status) {
466 up(&ar->sem);
467 return status;
468 }
469
470 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530471 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300472 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530473 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300474
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530475 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300476
477 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530478 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300479
480 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530481 (vif->auth_mode == NONE_AUTH) &&
482 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300483 struct ath6kl_key *key = NULL;
484
485 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
486 sme->key_idx > WMI_MAX_KEY_INDEX) {
487 ath6kl_err("key index %d out of bounds\n",
488 sme->key_idx);
489 up(&ar->sem);
490 return -ENOENT;
491 }
492
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530493 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300494 key->key_len = sme->key_len;
495 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530496 key->cipher = vif->prwise_crypto;
497 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300498
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530499 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530500 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300501 GROUP_USAGE | TX_USAGE,
502 key->key_len,
503 NULL,
504 key->key, KEY_OP_INIT_VAL, NULL,
505 NO_SYNC_WMIFLAG);
506 }
507
508 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530509 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530510 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
511 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300512 ath6kl_err("couldn't set bss filtering\n");
513 up(&ar->sem);
514 return -EIO;
515 }
516 }
517
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530518 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300519
520 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
521 "%s: connect called with authmode %d dot11 auth %d"
522 " PW crypto %d PW crypto len %d GRP crypto %d"
523 " GRP crypto len %d channel hint %u\n",
524 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530525 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
526 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530527 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300528
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530529 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530530 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530531 vif->dot11_auth_mode, vif->auth_mode,
532 vif->prwise_crypto,
533 vif->prwise_crypto_len,
534 vif->grp_crypto, vif->grp_crypto_len,
535 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530536 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300537 ar->connect_ctrl_flags);
538
539 up(&ar->sem);
540
541 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530542 memset(vif->ssid, 0, sizeof(vif->ssid));
543 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300544 ath6kl_err("invalid request\n");
545 return -ENOENT;
546 } else if (status) {
547 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
548 return -EIO;
549 }
550
551 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530552 ((vif->auth_mode == WPA_PSK_AUTH)
553 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530554 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300555 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
556 }
557
558 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530559 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300560
561 return 0;
562}
563
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530564static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300565 struct ieee80211_channel *chan,
566 const u8 *beacon_ie, size_t beacon_ie_len)
567{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530568 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300569 struct cfg80211_bss *bss;
570 u8 *ie;
571
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530572 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530573 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300574 WLAN_CAPABILITY_ESS);
575 if (bss == NULL) {
576 /*
577 * Since cfg80211 may not yet know about the BSS,
578 * generate a partial entry until the first BSS info
579 * event becomes available.
580 *
581 * Prepend SSID element since it is not included in the Beacon
582 * IEs from the target.
583 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300585 if (ie == NULL)
586 return -ENOMEM;
587 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530588 ie[1] = vif->ssid_len;
589 memcpy(ie + 2, vif->ssid, vif->ssid_len);
590 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530591 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300592 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530593 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300594 0, GFP_KERNEL);
595 if (bss)
596 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
597 "%pM prior to indicating connect/roamed "
598 "event\n", bssid);
599 kfree(ie);
600 } else
601 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
602 "entry\n");
603
604 if (bss == NULL)
605 return -ENOMEM;
606
607 cfg80211_put_bss(bss);
608
609 return 0;
610}
611
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530612void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300613 u8 *bssid, u16 listen_intvl,
614 u16 beacon_intvl,
615 enum network_type nw_type,
616 u8 beacon_ie_len, u8 assoc_req_len,
617 u8 assoc_resp_len, u8 *assoc_info)
618{
Jouni Malinen01cac472011-09-19 19:14:59 +0300619 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530620 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300621
622 /* capinfo + listen interval */
623 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
624
625 /* capinfo + status code + associd */
626 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
627
628 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
629 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
630 assoc_resp_ie_offset;
631
632 assoc_req_len -= assoc_req_ie_offset;
633 assoc_resp_len -= assoc_resp_ie_offset;
634
Jouni Malinen32c10872011-09-19 19:15:07 +0300635 /*
636 * Store Beacon interval here; DTIM period will be available only once
637 * a Beacon frame from the AP is seen.
638 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530639 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530640 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300641
Kalle Valobdcd8172011-07-18 00:22:30 +0300642 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530643 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300644 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
645 "%s: ath6k not in ibss mode\n", __func__);
646 return;
647 }
648 }
649
650 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530651 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
652 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
654 "%s: ath6k not in station mode\n", __func__);
655 return;
656 }
657 }
658
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530659 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300660
Kalle Valobdcd8172011-07-18 00:22:30 +0300661
662 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530663 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 return;
665 }
666
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530667 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300668 beacon_ie_len) < 0) {
669 ath6kl_err("could not add cfg80211 bss entry for "
670 "connect/roamed notification\n");
671 return;
672 }
673
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530674 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300675 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530676 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530677 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300678 assoc_req_ie, assoc_req_len,
679 assoc_resp_ie, assoc_resp_len,
680 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530681 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530683 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300684 assoc_req_ie, assoc_req_len,
685 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
686 }
687}
688
689static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
690 struct net_device *dev, u16 reason_code)
691{
692 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530693 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300694
695 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
696 reason_code);
697
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530698 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300699 return -EIO;
700
701 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
702 ath6kl_err("busy, destroy in progress\n");
703 return -EBUSY;
704 }
705
706 if (down_interruptible(&ar->sem)) {
707 ath6kl_err("busy, couldn't get access\n");
708 return -ERESTARTSYS;
709 }
710
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530711 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530712 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530713 memset(vif->ssid, 0, sizeof(vif->ssid));
714 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300715
716 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530717 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300718
719 up(&ar->sem);
720
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530721 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530722
Kalle Valobdcd8172011-07-18 00:22:30 +0300723 return 0;
724}
725
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 u8 *bssid, u8 assoc_resp_len,
728 u8 *assoc_info, u16 proto_reason)
729{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530730 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530731
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530732 if (vif->scan_req) {
733 cfg80211_scan_done(vif->scan_req, true);
734 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300735 }
736
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530737 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530738 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300739 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
740 "%s: ath6k not in ibss mode\n", __func__);
741 return;
742 }
743 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300745 return;
746 }
747
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530748 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530749 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
750 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300751 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
752 "%s: ath6k not in station mode\n", __func__);
753 return;
754 }
755 }
756
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530757 /*
758 * Send a disconnect command to target when a disconnect event is
759 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
760 * request from host) to make the firmware stop trying to connect even
761 * after giving disconnect event. There will be one more disconnect
762 * event for this disconnect command with reason code DISCONNECT_CMD
763 * which will be notified to cfg80211.
764 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300765
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530766 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530767 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 return;
769 }
770
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530771 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300772
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530773 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530774 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530775 bssid, NULL, 0,
776 NULL, 0,
777 WLAN_STATUS_UNSPECIFIED_FAILURE,
778 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530779 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530780 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530781 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300782 }
783
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530784 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300785}
786
Kalle Valobdcd8172011-07-18 00:22:30 +0300787static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
788 struct cfg80211_scan_request *request)
789{
790 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530791 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300792 s8 n_channels = 0;
793 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530795 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300796
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530797 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300798 return -EIO;
799
800 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530801 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300802 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530803 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530804 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300805 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
806 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300807 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300808 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300809 }
810 }
811
812 if (request->n_ssids && request->ssids[0].ssid_len) {
813 u8 i;
814
815 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
816 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
817
818 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530819 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
820 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300821 request->ssids[i].ssid_len,
822 request->ssids[i].ssid);
823 }
824
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300825 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530826 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
827 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300828 request->ie, request->ie_len);
829 if (ret) {
830 ath6kl_err("failed to set Probe Request appie for "
831 "scan");
832 return ret;
833 }
834 }
835
Jouni Malinen11869be2011-09-02 20:07:06 +0300836 /*
837 * Scan only the requested channels if the request specifies a set of
838 * channels. If the list is longer than the target supports, do not
839 * configure the list and instead, scan all available channels.
840 */
841 if (request->n_channels > 0 &&
842 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300843 u8 i;
844
Jouni Malinen11869be2011-09-02 20:07:06 +0300845 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300846
847 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
848 if (channels == NULL) {
849 ath6kl_warn("failed to set scan channels, "
850 "scan all channels");
851 n_channels = 0;
852 }
853
854 for (i = 0; i < n_channels; i++)
855 channels[i] = request->channels[i]->center_freq;
856 }
857
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530858 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530859 force_fg_scan = 1;
860
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530861 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
862 force_fg_scan, false, 0, 0, n_channels,
863 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300864 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300865 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300866 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530867 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300868
Edward Lu1276c9e2011-08-30 21:58:00 +0300869 kfree(channels);
870
Kalle Valobdcd8172011-07-18 00:22:30 +0300871 return ret;
872}
873
Kalle Valo1c17d312011-11-01 08:43:56 +0200874void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300875{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530876 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300877 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300878
Kalle Valo1c17d312011-11-01 08:43:56 +0200879 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
880 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300881
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530882 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300883 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300884
Kalle Valo1c17d312011-11-01 08:43:56 +0200885 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300886 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300887
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530888 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
889 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530890 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
891 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300892 0, NULL);
893 }
894 }
895
896out:
Kalle Valocb938212011-10-27 18:47:46 +0300897 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530898 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300899}
900
901static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
902 u8 key_index, bool pairwise,
903 const u8 *mac_addr,
904 struct key_params *params)
905{
906 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530907 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300908 struct ath6kl_key *key = NULL;
909 u8 key_usage;
910 u8 key_type;
911 int status = 0;
912
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530913 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300914 return -EIO;
915
Jouni Malinen837cb972011-10-11 17:31:57 +0300916 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
917 if (params->key_len != WMI_KRK_LEN)
918 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530919 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
920 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300921 }
922
Kalle Valobdcd8172011-07-18 00:22:30 +0300923 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
924 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
925 "%s: key index %d out of bounds\n", __func__,
926 key_index);
927 return -ENOENT;
928 }
929
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530930 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300931 memset(key, 0, sizeof(struct ath6kl_key));
932
933 if (pairwise)
934 key_usage = PAIRWISE_USAGE;
935 else
936 key_usage = GROUP_USAGE;
937
938 if (params) {
939 if (params->key_len > WLAN_MAX_KEY_LEN ||
940 params->seq_len > sizeof(key->seq))
941 return -EINVAL;
942
943 key->key_len = params->key_len;
944 memcpy(key->key, params->key, key->key_len);
945 key->seq_len = params->seq_len;
946 memcpy(key->seq, params->seq, key->seq_len);
947 key->cipher = params->cipher;
948 }
949
950 switch (key->cipher) {
951 case WLAN_CIPHER_SUITE_WEP40:
952 case WLAN_CIPHER_SUITE_WEP104:
953 key_type = WEP_CRYPT;
954 break;
955
956 case WLAN_CIPHER_SUITE_TKIP:
957 key_type = TKIP_CRYPT;
958 break;
959
960 case WLAN_CIPHER_SUITE_CCMP:
961 key_type = AES_CRYPT;
962 break;
963
964 default:
965 return -ENOTSUPP;
966 }
967
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530968 if (((vif->auth_mode == WPA_PSK_AUTH)
969 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300970 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530971 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300972
973 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
974 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
975 __func__, key_index, key->key_len, key_type,
976 key_usage, key->seq_len);
977
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530978 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300979
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530980 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300981 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
982 ar->ap_mode_bkey.valid = true;
983 ar->ap_mode_bkey.key_index = key_index;
984 ar->ap_mode_bkey.key_type = key_type;
985 ar->ap_mode_bkey.key_len = key->key_len;
986 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530987 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300988 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
989 "key configuration until AP mode has been "
990 "started\n");
991 /*
992 * The key will be set in ath6kl_connect_ap_mode() once
993 * the connected event is received from the target.
994 */
995 return 0;
996 }
997 }
998
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530999 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301000 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001001 /*
1002 * Store the key locally so that it can be re-configured after
1003 * the AP mode has properly started
1004 * (ath6kl_install_statioc_wep_keys).
1005 */
1006 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1007 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301008 vif->wep_key_list[key_index].key_len = key->key_len;
1009 memcpy(vif->wep_key_list[key_index].key, key->key,
1010 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001011 return 0;
1012 }
1013
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301014 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1015 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +03001016 key_type, key_usage, key->key_len,
1017 key->seq, key->key, KEY_OP_INIT_VAL,
1018 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
1019
1020 if (status)
1021 return -EIO;
1022
1023 return 0;
1024}
1025
1026static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1027 u8 key_index, bool pairwise,
1028 const u8 *mac_addr)
1029{
1030 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301031 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001032
1033 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1034
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301035 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001036 return -EIO;
1037
1038 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1039 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1040 "%s: key index %d out of bounds\n", __func__,
1041 key_index);
1042 return -ENOENT;
1043 }
1044
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301045 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001046 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1047 "%s: index %d is empty\n", __func__, key_index);
1048 return 0;
1049 }
1050
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301051 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001052
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301053 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001054}
1055
1056static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1057 u8 key_index, bool pairwise,
1058 const u8 *mac_addr, void *cookie,
1059 void (*callback) (void *cookie,
1060 struct key_params *))
1061{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301062 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001063 struct ath6kl_key *key = NULL;
1064 struct key_params params;
1065
1066 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1067
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301068 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001069 return -EIO;
1070
1071 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1072 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1073 "%s: key index %d out of bounds\n", __func__,
1074 key_index);
1075 return -ENOENT;
1076 }
1077
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301078 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001079 memset(&params, 0, sizeof(params));
1080 params.cipher = key->cipher;
1081 params.key_len = key->key_len;
1082 params.seq_len = key->seq_len;
1083 params.seq = key->seq;
1084 params.key = key->key;
1085
1086 callback(cookie, &params);
1087
1088 return key->key_len ? 0 : -ENOENT;
1089}
1090
1091static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1092 struct net_device *ndev,
1093 u8 key_index, bool unicast,
1094 bool multicast)
1095{
1096 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301097 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001098 struct ath6kl_key *key = NULL;
1099 int status = 0;
1100 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001101 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001102
1103 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1104
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301105 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001106 return -EIO;
1107
1108 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1109 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1110 "%s: key index %d out of bounds\n",
1111 __func__, key_index);
1112 return -ENOENT;
1113 }
1114
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301115 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001116 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1117 __func__, key_index);
1118 return -EINVAL;
1119 }
1120
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301121 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301122 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001123 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301124 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001125 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001126 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301127 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001128 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301129 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001130
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301131 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001132 return 0; /* Delay until AP mode has been started */
1133
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301134 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1135 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001136 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001137 key->key_len, key->seq, key->key,
1138 KEY_OP_INIT_VAL, NULL,
1139 SYNC_BOTH_WMIFLAG);
1140 if (status)
1141 return -EIO;
1142
1143 return 0;
1144}
1145
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301146void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001147 bool ismcast)
1148{
1149 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1150 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1151
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301152 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001153 (ismcast ? NL80211_KEYTYPE_GROUP :
1154 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1155 GFP_KERNEL);
1156}
1157
1158static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1159{
1160 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301161 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001162 int ret;
1163
1164 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1165 changed);
1166
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301167 vif = ath6kl_vif_first(ar);
1168 if (!vif)
1169 return -EIO;
1170
1171 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001172 return -EIO;
1173
1174 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1175 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1176 if (ret != 0) {
1177 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1178 return -EIO;
1179 }
1180 }
1181
1182 return 0;
1183}
1184
1185/*
1186 * The type nl80211_tx_power_setting replaces the following
1187 * data type from 2.6.36 onwards
1188*/
1189static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1190 enum nl80211_tx_power_setting type,
1191 int dbm)
1192{
1193 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301194 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001195 u8 ath6kl_dbm;
1196
1197 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1198 type, dbm);
1199
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301200 vif = ath6kl_vif_first(ar);
1201 if (!vif)
1202 return -EIO;
1203
1204 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001205 return -EIO;
1206
1207 switch (type) {
1208 case NL80211_TX_POWER_AUTOMATIC:
1209 return 0;
1210 case NL80211_TX_POWER_LIMITED:
1211 ar->tx_pwr = ath6kl_dbm = dbm;
1212 break;
1213 default:
1214 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1215 __func__, type);
1216 return -EOPNOTSUPP;
1217 }
1218
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301219 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001220
1221 return 0;
1222}
1223
1224static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1225{
1226 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301227 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001228
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301229 vif = ath6kl_vif_first(ar);
1230 if (!vif)
1231 return -EIO;
1232
1233 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001234 return -EIO;
1235
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301236 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001237 ar->tx_pwr = 0;
1238
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301239 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001240 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1241 return -EIO;
1242 }
1243
1244 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1245 5 * HZ);
1246
1247 if (signal_pending(current)) {
1248 ath6kl_err("target did not respond\n");
1249 return -EINTR;
1250 }
1251 }
1252
1253 *dbm = ar->tx_pwr;
1254 return 0;
1255}
1256
1257static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1258 struct net_device *dev,
1259 bool pmgmt, int timeout)
1260{
1261 struct ath6kl *ar = ath6kl_priv(dev);
1262 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301263 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001264
1265 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1266 __func__, pmgmt, timeout);
1267
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301268 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001269 return -EIO;
1270
1271 if (pmgmt) {
1272 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1273 mode.pwr_mode = REC_POWER;
1274 } else {
1275 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1276 mode.pwr_mode = MAX_PERF_POWER;
1277 }
1278
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301279 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1280 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001281 ath6kl_err("wmi_powermode_cmd failed\n");
1282 return -EIO;
1283 }
1284
1285 return 0;
1286}
1287
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301288static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1289 char *name,
1290 enum nl80211_iftype type,
1291 u32 *flags,
1292 struct vif_params *params)
1293{
1294 struct ath6kl *ar = wiphy_priv(wiphy);
1295 struct net_device *ndev;
1296 u8 if_idx, nw_type;
1297
1298 if (ar->num_vif == MAX_NUM_VIF) {
1299 ath6kl_err("Reached maximum number of supported vif\n");
1300 return ERR_PTR(-EINVAL);
1301 }
1302
1303 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1304 ath6kl_err("Not a supported interface type\n");
1305 return ERR_PTR(-EINVAL);
1306 }
1307
1308 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1309 if (!ndev)
1310 return ERR_PTR(-ENOMEM);
1311
1312 ar->num_vif++;
1313
1314 return ndev;
1315}
1316
1317static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1318 struct net_device *ndev)
1319{
1320 struct ath6kl *ar = wiphy_priv(wiphy);
1321 struct ath6kl_vif *vif = netdev_priv(ndev);
1322
1323 spin_lock(&ar->list_lock);
1324 list_del(&vif->list);
1325 spin_unlock(&ar->list_lock);
1326
1327 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1328
1329 ath6kl_deinit_if_data(vif);
1330
1331 return 0;
1332}
1333
Kalle Valobdcd8172011-07-18 00:22:30 +03001334static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1335 struct net_device *ndev,
1336 enum nl80211_iftype type, u32 *flags,
1337 struct vif_params *params)
1338{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301339 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001340
1341 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
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 switch (type) {
1347 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301348 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001349 break;
1350 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301351 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001352 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001353 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301354 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001355 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001356 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301357 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001358 break;
1359 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301360 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001361 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001362 default:
1363 ath6kl_err("invalid interface type %u\n", type);
1364 return -EOPNOTSUPP;
1365 }
1366
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301367 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001368
1369 return 0;
1370}
1371
1372static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1373 struct net_device *dev,
1374 struct cfg80211_ibss_params *ibss_param)
1375{
1376 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301377 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001378 int status;
1379
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301380 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001381 return -EIO;
1382
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301383 vif->ssid_len = ibss_param->ssid_len;
1384 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001385
1386 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301387 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001388
1389 if (ibss_param->channel_fixed) {
1390 /*
1391 * TODO: channel_fixed: The channel should be fixed, do not
1392 * search for IBSSs to join on other channels. Target
1393 * firmware does not support this feature, needs to be
1394 * updated.
1395 */
1396 return -EOPNOTSUPP;
1397 }
1398
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301399 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001400 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301401 memcpy(vif->req_bssid, ibss_param->bssid,
1402 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001403
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301404 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001405
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301406 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001407 if (status)
1408 return status;
1409
1410 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301411 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1412 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001413 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301414 ath6kl_set_cipher(vif, 0, true);
1415 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001416 }
1417
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301418 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001419
1420 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1421 "%s: connect called with authmode %d dot11 auth %d"
1422 " PW crypto %d PW crypto len %d GRP crypto %d"
1423 " GRP crypto len %d channel hint %u\n",
1424 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301425 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1426 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301427 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001428
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301429 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301430 vif->dot11_auth_mode, vif->auth_mode,
1431 vif->prwise_crypto,
1432 vif->prwise_crypto_len,
1433 vif->grp_crypto, vif->grp_crypto_len,
1434 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301435 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001436 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301437 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001438
1439 return 0;
1440}
1441
1442static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1443 struct net_device *dev)
1444{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301445 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001446
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301447 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001448 return -EIO;
1449
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301450 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301451 memset(vif->ssid, 0, sizeof(vif->ssid));
1452 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001453
1454 return 0;
1455}
1456
1457static const u32 cipher_suites[] = {
1458 WLAN_CIPHER_SUITE_WEP40,
1459 WLAN_CIPHER_SUITE_WEP104,
1460 WLAN_CIPHER_SUITE_TKIP,
1461 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001462 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001463};
1464
1465static bool is_rate_legacy(s32 rate)
1466{
1467 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1468 6000, 9000, 12000, 18000, 24000,
1469 36000, 48000, 54000
1470 };
1471 u8 i;
1472
1473 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1474 if (rate == legacy[i])
1475 return true;
1476
1477 return false;
1478}
1479
1480static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1481{
1482 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1483 52000, 58500, 65000, 72200
1484 };
1485 u8 i;
1486
1487 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1488 if (rate == ht20[i]) {
1489 if (i == ARRAY_SIZE(ht20) - 1)
1490 /* last rate uses sgi */
1491 *sgi = true;
1492 else
1493 *sgi = false;
1494
1495 *mcs = i;
1496 return true;
1497 }
1498 }
1499 return false;
1500}
1501
1502static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1503{
1504 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1505 81000, 108000, 121500, 135000,
1506 150000
1507 };
1508 u8 i;
1509
1510 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1511 if (rate == ht40[i]) {
1512 if (i == ARRAY_SIZE(ht40) - 1)
1513 /* last rate uses sgi */
1514 *sgi = true;
1515 else
1516 *sgi = false;
1517
1518 *mcs = i;
1519 return true;
1520 }
1521 }
1522
1523 return false;
1524}
1525
1526static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1527 u8 *mac, struct station_info *sinfo)
1528{
1529 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301530 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001531 long left;
1532 bool sgi;
1533 s32 rate;
1534 int ret;
1535 u8 mcs;
1536
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301537 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001538 return -ENOENT;
1539
1540 if (down_interruptible(&ar->sem))
1541 return -EBUSY;
1542
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301543 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001544
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301545 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001546
1547 if (ret != 0) {
1548 up(&ar->sem);
1549 return -EIO;
1550 }
1551
1552 left = wait_event_interruptible_timeout(ar->event_wq,
1553 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301554 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001555 WMI_TIMEOUT);
1556
1557 up(&ar->sem);
1558
1559 if (left == 0)
1560 return -ETIMEDOUT;
1561 else if (left < 0)
1562 return left;
1563
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301564 if (vif->target_stats.rx_byte) {
1565 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001566 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301567 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001568 sinfo->filled |= STATION_INFO_RX_PACKETS;
1569 }
1570
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301571 if (vif->target_stats.tx_byte) {
1572 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001573 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301574 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001575 sinfo->filled |= STATION_INFO_TX_PACKETS;
1576 }
1577
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301578 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001579 sinfo->filled |= STATION_INFO_SIGNAL;
1580
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301581 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001582
1583 if (is_rate_legacy(rate)) {
1584 sinfo->txrate.legacy = rate / 100;
1585 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1586 if (sgi) {
1587 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1588 sinfo->txrate.mcs = mcs - 1;
1589 } else {
1590 sinfo->txrate.mcs = mcs;
1591 }
1592
1593 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1594 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1595 if (sgi) {
1596 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1597 sinfo->txrate.mcs = mcs - 1;
1598 } else {
1599 sinfo->txrate.mcs = mcs;
1600 }
1601
1602 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1603 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1604 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001605 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1606 "invalid rate from stats: %d\n", rate);
1607 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001608 return 0;
1609 }
1610
1611 sinfo->filled |= STATION_INFO_TX_BITRATE;
1612
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301613 if (test_bit(CONNECTED, &vif->flags) &&
1614 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301615 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001616 sinfo->filled |= STATION_INFO_BSS_PARAM;
1617 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301618 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1619 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001620 }
1621
Kalle Valobdcd8172011-07-18 00:22:30 +03001622 return 0;
1623}
1624
1625static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1626 struct cfg80211_pmksa *pmksa)
1627{
1628 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301629 struct ath6kl_vif *vif = netdev_priv(netdev);
1630
1631 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001632 pmksa->pmkid, true);
1633}
1634
1635static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1636 struct cfg80211_pmksa *pmksa)
1637{
1638 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301639 struct ath6kl_vif *vif = netdev_priv(netdev);
1640
1641 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001642 pmksa->pmkid, false);
1643}
1644
1645static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1646{
1647 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301648 struct ath6kl_vif *vif = netdev_priv(netdev);
1649
1650 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301651 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1652 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001653 return 0;
1654}
1655
Kalle Valo52d81a62011-11-01 08:44:21 +02001656int ath6kl_cfg80211_suspend(struct ath6kl *ar,
1657 enum ath6kl_cfg_suspend_mode mode)
1658{
1659 int ret;
1660
1661 ath6kl_cfg80211_stop(ar);
1662
1663 switch (mode) {
1664 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
1665 /* save the current power mode before enabling power save */
1666 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1667
1668 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1669 if (ret) {
1670 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1671 ret);
1672 }
1673
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001674 ar->state = ATH6KL_STATE_DEEPSLEEP;
1675
Kalle Valo52d81a62011-11-01 08:44:21 +02001676 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001677
1678 case ATH6KL_CFG_SUSPEND_CUTPOWER:
1679 if (ar->state == ATH6KL_STATE_OFF) {
1680 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1681 "suspend hw off, no action for cutpower\n");
1682 break;
1683 }
1684
1685 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1686
1687 ret = ath6kl_init_hw_stop(ar);
1688 if (ret) {
1689 ath6kl_warn("failed to stop hw during suspend: %d\n",
1690 ret);
1691 }
1692
1693 ar->state = ATH6KL_STATE_CUTPOWER;
1694
1695 break;
1696
1697 default:
1698 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001699 }
1700
1701 return 0;
1702}
1703
1704int ath6kl_cfg80211_resume(struct ath6kl *ar)
1705{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001706 int ret;
1707
1708 switch (ar->state) {
1709 case ATH6KL_STATE_DEEPSLEEP:
1710 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1711 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1712 ar->wmi->saved_pwr_mode);
1713 if (ret) {
1714 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1715 ret);
1716 }
1717 }
1718
1719 ar->state = ATH6KL_STATE_ON;
1720
1721 break;
1722
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001723 case ATH6KL_STATE_CUTPOWER:
1724 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1725
1726 ret = ath6kl_init_hw_start(ar);
1727 if (ret) {
1728 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1729 return ret;
1730 }
1731
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001732 default:
1733 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001734 }
1735
1736 return 0;
1737}
1738
Kalle Valoabcb3442011-07-22 08:26:20 +03001739#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001740
1741/* hif layer decides what suspend mode to use */
1742static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001743 struct cfg80211_wowlan *wow)
1744{
1745 struct ath6kl *ar = wiphy_priv(wiphy);
1746
1747 return ath6kl_hif_suspend(ar);
1748}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001749
Kalle Valo52d81a62011-11-01 08:44:21 +02001750static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001751{
1752 struct ath6kl *ar = wiphy_priv(wiphy);
1753
1754 return ath6kl_hif_resume(ar);
1755}
Kalle Valoabcb3442011-07-22 08:26:20 +03001756#endif
1757
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001758static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1759 struct ieee80211_channel *chan,
1760 enum nl80211_channel_type channel_type)
1761{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301762 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001763
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301764 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001765 return -EIO;
1766
1767 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1768 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301769 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001770
1771 return 0;
1772}
1773
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001774static bool ath6kl_is_p2p_ie(const u8 *pos)
1775{
1776 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1777 pos[2] == 0x50 && pos[3] == 0x6f &&
1778 pos[4] == 0x9a && pos[5] == 0x09;
1779}
1780
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301781static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1782 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001783{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301784 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001785 const u8 *pos;
1786 u8 *buf = NULL;
1787 size_t len = 0;
1788 int ret;
1789
1790 /*
1791 * Filter out P2P IE(s) since they will be included depending on
1792 * the Probe Request frame in ath6kl_send_go_probe_resp().
1793 */
1794
1795 if (ies && ies_len) {
1796 buf = kmalloc(ies_len, GFP_KERNEL);
1797 if (buf == NULL)
1798 return -ENOMEM;
1799 pos = ies;
1800 while (pos + 1 < ies + ies_len) {
1801 if (pos + 2 + pos[1] > ies + ies_len)
1802 break;
1803 if (!ath6kl_is_p2p_ie(pos)) {
1804 memcpy(buf + len, pos, 2 + pos[1]);
1805 len += 2 + pos[1];
1806 }
1807 pos += 2 + pos[1];
1808 }
1809 }
1810
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301811 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1812 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001813 kfree(buf);
1814 return ret;
1815}
1816
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001817static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1818 struct beacon_parameters *info, bool add)
1819{
1820 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301821 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001822 struct ieee80211_mgmt *mgmt;
1823 u8 *ies;
1824 int ies_len;
1825 struct wmi_connect_cmd p;
1826 int res;
1827 int i;
1828
1829 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1830
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301831 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001832 return -EIO;
1833
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301834 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001835 return -EOPNOTSUPP;
1836
1837 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301838 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1839 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001840 info->beacon_ies,
1841 info->beacon_ies_len);
1842 if (res)
1843 return res;
1844 }
1845 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301846 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001847 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001848 if (res)
1849 return res;
1850 }
1851 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301852 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1853 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001854 info->assocresp_ies,
1855 info->assocresp_ies_len);
1856 if (res)
1857 return res;
1858 }
1859
1860 if (!add)
1861 return 0;
1862
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001863 ar->ap_mode_bkey.valid = false;
1864
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001865 /* TODO:
1866 * info->interval
1867 * info->dtim_period
1868 */
1869
1870 if (info->head == NULL)
1871 return -EINVAL;
1872 mgmt = (struct ieee80211_mgmt *) info->head;
1873 ies = mgmt->u.beacon.variable;
1874 if (ies > info->head + info->head_len)
1875 return -EINVAL;
1876 ies_len = info->head + info->head_len - ies;
1877
1878 if (info->ssid == NULL)
1879 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301880 memcpy(vif->ssid, info->ssid, info->ssid_len);
1881 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001882 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1883 return -EOPNOTSUPP; /* TODO */
1884
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301885 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001886
1887 memset(&p, 0, sizeof(p));
1888
1889 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1890 switch (info->crypto.akm_suites[i]) {
1891 case WLAN_AKM_SUITE_8021X:
1892 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1893 p.auth_mode |= WPA_AUTH;
1894 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1895 p.auth_mode |= WPA2_AUTH;
1896 break;
1897 case WLAN_AKM_SUITE_PSK:
1898 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1899 p.auth_mode |= WPA_PSK_AUTH;
1900 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1901 p.auth_mode |= WPA2_PSK_AUTH;
1902 break;
1903 }
1904 }
1905 if (p.auth_mode == 0)
1906 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301907 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001908
1909 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1910 switch (info->crypto.ciphers_pairwise[i]) {
1911 case WLAN_CIPHER_SUITE_WEP40:
1912 case WLAN_CIPHER_SUITE_WEP104:
1913 p.prwise_crypto_type |= WEP_CRYPT;
1914 break;
1915 case WLAN_CIPHER_SUITE_TKIP:
1916 p.prwise_crypto_type |= TKIP_CRYPT;
1917 break;
1918 case WLAN_CIPHER_SUITE_CCMP:
1919 p.prwise_crypto_type |= AES_CRYPT;
1920 break;
1921 }
1922 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001923 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001924 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301925 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001926 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301927 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001928
1929 switch (info->crypto.cipher_group) {
1930 case WLAN_CIPHER_SUITE_WEP40:
1931 case WLAN_CIPHER_SUITE_WEP104:
1932 p.grp_crypto_type = WEP_CRYPT;
1933 break;
1934 case WLAN_CIPHER_SUITE_TKIP:
1935 p.grp_crypto_type = TKIP_CRYPT;
1936 break;
1937 case WLAN_CIPHER_SUITE_CCMP:
1938 p.grp_crypto_type = AES_CRYPT;
1939 break;
1940 default:
1941 p.grp_crypto_type = NONE_CRYPT;
1942 break;
1943 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301944 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001945
1946 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301947 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001948
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301949 p.ssid_len = vif->ssid_len;
1950 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1951 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301952 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001953
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301954 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001955 if (res < 0)
1956 return res;
1957
1958 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001959}
1960
1961static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1962 struct beacon_parameters *info)
1963{
1964 return ath6kl_ap_beacon(wiphy, dev, info, true);
1965}
1966
1967static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1968 struct beacon_parameters *info)
1969{
1970 return ath6kl_ap_beacon(wiphy, dev, info, false);
1971}
1972
1973static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1974{
1975 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301976 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001977
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301978 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001979 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301980 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001981 return -ENOTCONN;
1982
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301983 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301984 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001985
1986 return 0;
1987}
1988
Jouni Malinen23875132011-08-30 21:57:53 +03001989static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1990 u8 *mac, struct station_parameters *params)
1991{
1992 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301993 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001994
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301995 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001996 return -EOPNOTSUPP;
1997
1998 /* Use this only for authorizing/unauthorizing a station */
1999 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2000 return -EOPNOTSUPP;
2001
2002 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302003 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2004 WMI_AP_MLME_AUTHORIZE, mac, 0);
2005 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2006 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002007}
2008
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002009static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2010 struct net_device *dev,
2011 struct ieee80211_channel *chan,
2012 enum nl80211_channel_type channel_type,
2013 unsigned int duration,
2014 u64 *cookie)
2015{
2016 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302017 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002018 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002019
2020 /* TODO: if already pending or ongoing remain-on-channel,
2021 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002022 id = ++vif->last_roc_id;
2023 if (id == 0) {
2024 /* Do not use 0 as the cookie value */
2025 id = ++vif->last_roc_id;
2026 }
2027 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002028
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302029 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2030 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002031}
2032
2033static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2034 struct net_device *dev,
2035 u64 cookie)
2036{
2037 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302038 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002039
Jouni Malinen10522612011-10-27 16:00:13 +03002040 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002041 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002042 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002043
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302044 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002045}
2046
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302047static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2048 const u8 *buf, size_t len,
2049 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002050{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302051 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002052 const u8 *pos;
2053 u8 *p2p;
2054 int p2p_len;
2055 int ret;
2056 const struct ieee80211_mgmt *mgmt;
2057
2058 mgmt = (const struct ieee80211_mgmt *) buf;
2059
2060 /* Include P2P IE(s) from the frame generated in user space. */
2061
2062 p2p = kmalloc(len, GFP_KERNEL);
2063 if (p2p == NULL)
2064 return -ENOMEM;
2065 p2p_len = 0;
2066
2067 pos = mgmt->u.probe_resp.variable;
2068 while (pos + 1 < buf + len) {
2069 if (pos + 2 + pos[1] > buf + len)
2070 break;
2071 if (ath6kl_is_p2p_ie(pos)) {
2072 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2073 p2p_len += 2 + pos[1];
2074 }
2075 pos += 2 + pos[1];
2076 }
2077
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302078 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2079 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002080 kfree(p2p);
2081 return ret;
2082}
2083
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002084static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2085 struct ieee80211_channel *chan, bool offchan,
2086 enum nl80211_channel_type channel_type,
2087 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002088 const u8 *buf, size_t len, bool no_cck,
2089 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002090{
2091 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302092 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002093 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002094 const struct ieee80211_mgmt *mgmt;
2095
2096 mgmt = (const struct ieee80211_mgmt *) buf;
2097 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302098 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002099 ieee80211_is_probe_resp(mgmt->frame_control)) {
2100 /*
2101 * Send Probe Response frame in AP mode using a separate WMI
2102 * command to allow the target to fill in the generic IEs.
2103 */
2104 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302105 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002106 chan->center_freq);
2107 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002108
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302109 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002110 if (id == 0) {
2111 /*
2112 * 0 is a reserved value in the WMI command and shall not be
2113 * used for the command.
2114 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302115 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002116 }
2117
2118 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302119 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2120 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002121 buf, len);
2122}
2123
Jouni Malinenae32c302011-08-30 21:58:01 +03002124static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2125 struct net_device *dev,
2126 u16 frame_type, bool reg)
2127{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302128 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002129
2130 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2131 __func__, frame_type, reg);
2132 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2133 /*
2134 * Note: This notification callback is not allowed to sleep, so
2135 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2136 * hardcode target to report Probe Request frames all the time.
2137 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302138 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002139 }
2140}
2141
Jouni Malinenf80574a2011-08-30 21:58:04 +03002142static const struct ieee80211_txrx_stypes
2143ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2144 [NL80211_IFTYPE_STATION] = {
2145 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2146 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2147 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2148 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2149 },
2150 [NL80211_IFTYPE_P2P_CLIENT] = {
2151 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2152 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2153 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2154 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2155 },
2156 [NL80211_IFTYPE_P2P_GO] = {
2157 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2158 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2159 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2160 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2161 },
2162};
2163
Kalle Valobdcd8172011-07-18 00:22:30 +03002164static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302165 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2166 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002167 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2168 .scan = ath6kl_cfg80211_scan,
2169 .connect = ath6kl_cfg80211_connect,
2170 .disconnect = ath6kl_cfg80211_disconnect,
2171 .add_key = ath6kl_cfg80211_add_key,
2172 .get_key = ath6kl_cfg80211_get_key,
2173 .del_key = ath6kl_cfg80211_del_key,
2174 .set_default_key = ath6kl_cfg80211_set_default_key,
2175 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2176 .set_tx_power = ath6kl_cfg80211_set_txpower,
2177 .get_tx_power = ath6kl_cfg80211_get_txpower,
2178 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2179 .join_ibss = ath6kl_cfg80211_join_ibss,
2180 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2181 .get_station = ath6kl_get_station,
2182 .set_pmksa = ath6kl_set_pmksa,
2183 .del_pmksa = ath6kl_del_pmksa,
2184 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002185 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002186#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002187 .suspend = __ath6kl_cfg80211_suspend,
2188 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002189#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002190 .set_channel = ath6kl_set_channel,
2191 .add_beacon = ath6kl_add_beacon,
2192 .set_beacon = ath6kl_set_beacon,
2193 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002194 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002195 .remain_on_channel = ath6kl_remain_on_channel,
2196 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002197 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002198 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002199};
2200
Kalle Valoec4b7f62011-11-01 08:44:04 +02002201void ath6kl_cfg80211_stop(struct ath6kl *ar)
2202{
2203 struct ath6kl_vif *vif;
2204
2205 /* FIXME: for multi vif */
2206 vif = ath6kl_vif_first(ar);
2207 if (!vif) {
2208 /* save the current power mode before enabling power save */
2209 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2210
2211 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2212 ath6kl_warn("ath6kl_deep_sleep_enable: "
2213 "wmi_powermode_cmd failed\n");
2214 return;
2215 }
2216
2217 switch (vif->sme_state) {
2218 case SME_CONNECTING:
2219 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2220 NULL, 0,
2221 WLAN_STATUS_UNSPECIFIED_FAILURE,
2222 GFP_KERNEL);
2223 break;
2224 case SME_CONNECTED:
2225 default:
2226 /*
2227 * FIXME: oddly enough smeState is in DISCONNECTED during
2228 * suspend, why? Need to send disconnected event in that
2229 * state.
2230 */
2231 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2232 break;
2233 }
2234
2235 if (test_bit(CONNECTED, &vif->flags) ||
2236 test_bit(CONNECT_PEND, &vif->flags))
2237 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2238
2239 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002240 clear_bit(CONNECTED, &vif->flags);
2241 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002242
2243 /* disable scanning */
2244 if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
2245 0, 0, 0, 0, 0, 0, 0) != 0)
2246 printk(KERN_WARNING "ath6kl: failed to disable scan "
2247 "during suspend\n");
2248
2249 ath6kl_cfg80211_scan_complete_event(vif, true);
2250}
2251
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302252struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002253{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002254 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302255 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302256 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002257
2258 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302259 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302260
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302261 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002262 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002263 return NULL;
2264 }
2265
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302266 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302267 if (!multi_norm_if_support)
2268 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302269 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302270 ar->dev = dev;
2271
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302272 if (multi_norm_if_support)
2273 ar->max_norm_iface = 2;
2274 else
2275 ar->max_norm_iface = 1;
2276
2277 /* FIXME: Remove this once the multivif support is enabled */
2278 ar->max_norm_iface = 1;
2279
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302280 spin_lock_init(&ar->lock);
2281 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302282 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302283
2284 init_waitqueue_head(&ar->event_wq);
2285 sema_init(&ar->sem, 1);
2286
2287 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302288 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302289
2290 clear_bit(WMI_ENABLED, &ar->flag);
2291 clear_bit(SKIP_SCAN, &ar->flag);
2292 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2293
2294 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2295 ar->listen_intvl_b = 0;
2296 ar->tx_pwr = 0;
2297
2298 ar->intra_bss = 1;
2299 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2300 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2301 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2302 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2303
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002304 ar->state = ATH6KL_STATE_OFF;
2305
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302306 memset((u8 *)ar->sta_list, 0,
2307 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2308
2309 /* Init the PS queues */
2310 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2311 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2312 skb_queue_head_init(&ar->sta_list[ctr].psq);
2313 }
2314
2315 skb_queue_head_init(&ar->mcastpsq);
2316
2317 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2318
2319 return ar;
2320}
2321
2322int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2323{
2324 struct wiphy *wiphy = ar->wiphy;
2325 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002326
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302327 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002328
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302329 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002330
Kalle Valobdcd8172011-07-18 00:22:30 +03002331 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302332 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002333
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302334 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302335 BIT(NL80211_IFTYPE_ADHOC) |
2336 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002337 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302338 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302339 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002340 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302341
Kalle Valobdcd8172011-07-18 00:22:30 +03002342 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302343 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2344 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2345 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2346 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2347 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002348
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302349 wiphy->cipher_suites = cipher_suites;
2350 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002351
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302352 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002353 if (ret < 0) {
2354 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302355 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002356 }
2357
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302358 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002359}
2360
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302361static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002362{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302363 vif->aggr_cntxt = aggr_init(vif->ndev);
2364 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302365 ath6kl_err("failed to initialize aggr\n");
2366 return -ENOMEM;
2367 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002368
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302369 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302370 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302371 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302372 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302373
2374 return 0;
2375}
2376
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302377void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302378{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302379 struct ath6kl *ar = vif->ar;
2380
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302381 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302382
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302383 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2384
2385 if (vif->nw_type == ADHOC_NETWORK)
2386 ar->ibss_if_active = false;
2387
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302388 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302389
2390 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302391}
2392
2393struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302394 enum nl80211_iftype type, u8 fw_vif_idx,
2395 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302396{
2397 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302398 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302399
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302400 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302401 if (!ndev)
2402 return NULL;
2403
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302404 vif = netdev_priv(ndev);
2405 ndev->ieee80211_ptr = &vif->wdev;
2406 vif->wdev.wiphy = ar->wiphy;
2407 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302408 vif->ndev = ndev;
2409 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2410 vif->wdev.netdev = ndev;
2411 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302412 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302413 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302414
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302415 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2416 if (fw_vif_idx != 0)
2417 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2418 0x2;
2419
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302420 init_netdev(ndev);
2421
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302422 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302423
2424 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302425 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302426 goto err;
2427
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302428 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302429 goto err;
2430
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302431 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302432 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302433 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302434 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302435 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302436
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302437 if (type == NL80211_IFTYPE_ADHOC)
2438 ar->ibss_if_active = true;
2439
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302440 spin_lock(&ar->list_lock);
2441 list_add_tail(&vif->list, &ar->vif_list);
2442 spin_unlock(&ar->list_lock);
2443
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302444 return ndev;
2445
2446err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302447 aggr_module_destroy(vif->aggr_cntxt);
2448 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302449 return NULL;
2450}
2451
2452void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2453{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302454 wiphy_unregister(ar->wiphy);
2455 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002456}