blob: 41260c8b8876073beab2a7c9da7ca4165a9e99e1 [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;
Dai Shuibing5e070212011-11-03 11:39:37 +0200206 case WLAN_CIPHER_SUITE_SMS4:
207 *ar_cipher = WAPI_CRYPT;
208 *ar_cipher_len = 0;
209 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300210 default:
211 ath6kl_err("cipher 0x%x not supported\n", cipher);
212 return -ENOTSUPP;
213 }
214
215 return 0;
216}
217
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530218static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300219{
220 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
221
222 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530223 if (vif->auth_mode == WPA_AUTH)
224 vif->auth_mode = WPA_PSK_AUTH;
225 else if (vif->auth_mode == WPA2_AUTH)
226 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300227 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530228 if (vif->auth_mode == WPA_AUTH)
229 vif->auth_mode = WPA_AUTH_CCKM;
230 else if (vif->auth_mode == WPA2_AUTH)
231 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300232 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530233 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300234 }
235}
236
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530237static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300238{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530239 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530240
Kalle Valobdcd8172011-07-18 00:22:30 +0300241 if (!test_bit(WMI_READY, &ar->flag)) {
242 ath6kl_err("wmi is not ready\n");
243 return false;
244 }
245
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530246 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300247 ath6kl_err("wlan disabled\n");
248 return false;
249 }
250
251 return true;
252}
253
Kevin Fang6981ffd2011-10-07 08:51:19 +0800254static bool ath6kl_is_wpa_ie(const u8 *pos)
255{
256 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
257 pos[2] == 0x00 && pos[3] == 0x50 &&
258 pos[4] == 0xf2 && pos[5] == 0x01;
259}
260
261static bool ath6kl_is_rsn_ie(const u8 *pos)
262{
263 return pos[0] == WLAN_EID_RSN;
264}
265
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700266static bool ath6kl_is_wps_ie(const u8 *pos)
267{
268 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
269 pos[1] >= 4 &&
270 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
271 pos[5] == 0x04);
272}
273
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530274static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
275 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800276{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530277 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800278 const u8 *pos;
279 u8 *buf = NULL;
280 size_t len = 0;
281 int ret;
282
283 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700284 * Clear previously set flag
285 */
286
287 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
288
289 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800290 * Filter out RSN/WPA IE(s)
291 */
292
293 if (ies && ies_len) {
294 buf = kmalloc(ies_len, GFP_KERNEL);
295 if (buf == NULL)
296 return -ENOMEM;
297 pos = ies;
298
299 while (pos + 1 < ies + ies_len) {
300 if (pos + 2 + pos[1] > ies + ies_len)
301 break;
302 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
303 memcpy(buf + len, pos, 2 + pos[1]);
304 len += 2 + pos[1];
305 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700306
307 if (ath6kl_is_wps_ie(pos))
308 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
309
Kevin Fang6981ffd2011-10-07 08:51:19 +0800310 pos += 2 + pos[1];
311 }
312 }
313
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530314 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
315 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800316 kfree(buf);
317 return ret;
318}
319
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530320static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
321{
322 switch (type) {
323 case NL80211_IFTYPE_STATION:
324 *nw_type = INFRA_NETWORK;
325 break;
326 case NL80211_IFTYPE_ADHOC:
327 *nw_type = ADHOC_NETWORK;
328 break;
329 case NL80211_IFTYPE_AP:
330 *nw_type = AP_NETWORK;
331 break;
332 case NL80211_IFTYPE_P2P_CLIENT:
333 *nw_type = INFRA_NETWORK;
334 break;
335 case NL80211_IFTYPE_P2P_GO:
336 *nw_type = AP_NETWORK;
337 break;
338 default:
339 ath6kl_err("invalid interface type %u\n", type);
340 return -ENOTSUPP;
341 }
342
343 return 0;
344}
345
346static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
347 u8 *if_idx, u8 *nw_type)
348{
349 int i;
350
351 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
352 return false;
353
354 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
355 ar->num_vif))
356 return false;
357
358 if (type == NL80211_IFTYPE_STATION ||
359 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
360 for (i = 0; i < MAX_NUM_VIF; i++) {
361 if ((ar->avail_idx_map >> i) & BIT(0)) {
362 *if_idx = i;
363 return true;
364 }
365 }
366 }
367
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530368 if (type == NL80211_IFTYPE_P2P_CLIENT ||
369 type == NL80211_IFTYPE_P2P_GO) {
370 for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
371 if ((ar->avail_idx_map >> i) & BIT(0)) {
372 *if_idx = i;
373 return true;
374 }
375 }
376 }
377
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530378 return false;
379}
380
Kalle Valobdcd8172011-07-18 00:22:30 +0300381static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
382 struct cfg80211_connect_params *sme)
383{
384 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530385 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300386 int status;
387
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530388 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300389
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530390 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300391 return -EIO;
392
393 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
394 ath6kl_err("destroy in progress\n");
395 return -EBUSY;
396 }
397
398 if (test_bit(SKIP_SCAN, &ar->flag) &&
399 ((sme->channel && sme->channel->center_freq == 0) ||
400 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
401 ath6kl_err("SkipScan: channel or bssid invalid\n");
402 return -EINVAL;
403 }
404
405 if (down_interruptible(&ar->sem)) {
406 ath6kl_err("busy, couldn't get access\n");
407 return -ERESTARTSYS;
408 }
409
410 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
411 ath6kl_err("busy, destroy in progress\n");
412 up(&ar->sem);
413 return -EBUSY;
414 }
415
416 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
417 /*
418 * sleep until the command queue drains
419 */
420 wait_event_interruptible_timeout(ar->event_wq,
421 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
422 WMI_TIMEOUT);
423 if (signal_pending(current)) {
424 ath6kl_err("cmd queue drain timeout\n");
425 up(&ar->sem);
426 return -EINTR;
427 }
428 }
429
Kevin Fang6981ffd2011-10-07 08:51:19 +0800430 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530431 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800432 if (status)
433 return status;
434 }
435
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530436 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530437 vif->ssid_len == sme->ssid_len &&
438 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530439 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530440 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
441 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530442 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300443
444 up(&ar->sem);
445 if (status) {
446 ath6kl_err("wmi_reconnect_cmd failed\n");
447 return -EIO;
448 }
449 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530450 } else if (vif->ssid_len == sme->ssid_len &&
451 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530452 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300453 }
454
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530455 memset(vif->ssid, 0, sizeof(vif->ssid));
456 vif->ssid_len = sme->ssid_len;
457 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300458
459 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530460 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300461
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530462 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300463 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530464 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300465
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530466 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300467
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530468 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300469 if (status) {
470 up(&ar->sem);
471 return status;
472 }
473
474 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530475 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300476 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530477 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300478
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530479 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300480
481 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530482 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300483
484 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530485 (vif->auth_mode == NONE_AUTH) &&
486 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300487 struct ath6kl_key *key = NULL;
488
489 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
490 sme->key_idx > WMI_MAX_KEY_INDEX) {
491 ath6kl_err("key index %d out of bounds\n",
492 sme->key_idx);
493 up(&ar->sem);
494 return -ENOENT;
495 }
496
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530497 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300498 key->key_len = sme->key_len;
499 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530500 key->cipher = vif->prwise_crypto;
501 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300502
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530503 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530504 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300505 GROUP_USAGE | TX_USAGE,
506 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200507 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300508 key->key, KEY_OP_INIT_VAL, NULL,
509 NO_SYNC_WMIFLAG);
510 }
511
512 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530513 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530514 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
515 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300516 ath6kl_err("couldn't set bss filtering\n");
517 up(&ar->sem);
518 return -EIO;
519 }
520 }
521
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530522 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300523
524 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
525 "%s: connect called with authmode %d dot11 auth %d"
526 " PW crypto %d PW crypto len %d GRP crypto %d"
527 " GRP crypto len %d channel hint %u\n",
528 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530529 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
530 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530531 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300532
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530533 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530534 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530535 vif->dot11_auth_mode, vif->auth_mode,
536 vif->prwise_crypto,
537 vif->prwise_crypto_len,
538 vif->grp_crypto, vif->grp_crypto_len,
539 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530540 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300541 ar->connect_ctrl_flags);
542
543 up(&ar->sem);
544
545 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530546 memset(vif->ssid, 0, sizeof(vif->ssid));
547 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300548 ath6kl_err("invalid request\n");
549 return -ENOENT;
550 } else if (status) {
551 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
552 return -EIO;
553 }
554
555 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530556 ((vif->auth_mode == WPA_PSK_AUTH)
557 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530558 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300559 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
560 }
561
562 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530563 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300564
565 return 0;
566}
567
Raja Mani4eab6f42011-11-09 17:02:23 +0530568static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
569 enum network_type nw_type,
570 const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300571 struct ieee80211_channel *chan,
572 const u8 *beacon_ie, size_t beacon_ie_len)
573{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530574 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300575 struct cfg80211_bss *bss;
Raja Mani4eab6f42011-11-09 17:02:23 +0530576 u16 cap_mask, cap_val;
Jouni Malinen01cac472011-09-19 19:14:59 +0300577 u8 *ie;
578
Raja Mani4eab6f42011-11-09 17:02:23 +0530579 if (nw_type & ADHOC_NETWORK) {
580 cap_mask = WLAN_CAPABILITY_IBSS;
581 cap_val = WLAN_CAPABILITY_IBSS;
582 } else {
583 cap_mask = WLAN_CAPABILITY_ESS;
584 cap_val = WLAN_CAPABILITY_ESS;
585 }
586
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530587 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530588 vif->ssid, vif->ssid_len,
589 cap_mask, cap_val);
Jouni Malinen01cac472011-09-19 19:14:59 +0300590 if (bss == NULL) {
591 /*
592 * Since cfg80211 may not yet know about the BSS,
593 * generate a partial entry until the first BSS info
594 * event becomes available.
595 *
596 * Prepend SSID element since it is not included in the Beacon
597 * IEs from the target.
598 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530599 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300600 if (ie == NULL)
601 return -ENOMEM;
602 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530603 ie[1] = vif->ssid_len;
604 memcpy(ie + 2, vif->ssid, vif->ssid_len);
605 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530606 bss = cfg80211_inform_bss(ar->wiphy, chan,
Raja Mani4eab6f42011-11-09 17:02:23 +0530607 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530608 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300609 0, GFP_KERNEL);
610 if (bss)
Raja Mani4eab6f42011-11-09 17:02:23 +0530611 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
612 "cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300613 kfree(ie);
614 } else
615 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
616 "entry\n");
617
618 if (bss == NULL)
619 return -ENOMEM;
620
621 cfg80211_put_bss(bss);
622
623 return 0;
624}
625
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530626void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300627 u8 *bssid, u16 listen_intvl,
628 u16 beacon_intvl,
629 enum network_type nw_type,
630 u8 beacon_ie_len, u8 assoc_req_len,
631 u8 assoc_resp_len, u8 *assoc_info)
632{
Jouni Malinen01cac472011-09-19 19:14:59 +0300633 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530634 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300635
636 /* capinfo + listen interval */
637 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
638
639 /* capinfo + status code + associd */
640 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
641
642 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
643 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
644 assoc_resp_ie_offset;
645
646 assoc_req_len -= assoc_req_ie_offset;
647 assoc_resp_len -= assoc_resp_ie_offset;
648
Jouni Malinen32c10872011-09-19 19:15:07 +0300649 /*
650 * Store Beacon interval here; DTIM period will be available only once
651 * a Beacon frame from the AP is seen.
652 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530653 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530654 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300655
Kalle Valobdcd8172011-07-18 00:22:30 +0300656 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530657 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300658 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
659 "%s: ath6k not in ibss mode\n", __func__);
660 return;
661 }
662 }
663
664 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530665 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
666 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300667 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
668 "%s: ath6k not in station mode\n", __func__);
669 return;
670 }
671 }
672
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530673 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300674
Raja Mani4eab6f42011-11-09 17:02:23 +0530675 if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
676 beacon_ie_len) < 0) {
677 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300678 return;
679 }
680
Raja Mani4eab6f42011-11-09 17:02:23 +0530681 if (nw_type & ADHOC_NETWORK) {
682 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
683 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
684 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300685 return;
686 }
687
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530688 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300689 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530690 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530691 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300692 assoc_req_ie, assoc_req_len,
693 assoc_resp_ie, assoc_resp_len,
694 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530695 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300696 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530697 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300698 assoc_req_ie, assoc_req_len,
699 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
700 }
701}
702
703static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
704 struct net_device *dev, u16 reason_code)
705{
706 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530707 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300708
709 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
710 reason_code);
711
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530712 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300713 return -EIO;
714
715 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
716 ath6kl_err("busy, destroy in progress\n");
717 return -EBUSY;
718 }
719
720 if (down_interruptible(&ar->sem)) {
721 ath6kl_err("busy, couldn't get access\n");
722 return -ERESTARTSYS;
723 }
724
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530725 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530727 memset(vif->ssid, 0, sizeof(vif->ssid));
728 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300729
730 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530731 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300732
733 up(&ar->sem);
734
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530735 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530736
Kalle Valobdcd8172011-07-18 00:22:30 +0300737 return 0;
738}
739
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530740void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300741 u8 *bssid, u8 assoc_resp_len,
742 u8 *assoc_info, u16 proto_reason)
743{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530745
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530746 if (vif->scan_req) {
747 cfg80211_scan_done(vif->scan_req, true);
748 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300749 }
750
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530751 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530752 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300753 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
754 "%s: ath6k not in ibss mode\n", __func__);
755 return;
756 }
757 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530758 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300759 return;
760 }
761
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530762 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530763 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
764 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300765 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
766 "%s: ath6k not in station mode\n", __func__);
767 return;
768 }
769 }
770
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530771 /*
772 * Send a disconnect command to target when a disconnect event is
773 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
774 * request from host) to make the firmware stop trying to connect even
775 * after giving disconnect event. There will be one more disconnect
776 * event for this disconnect command with reason code DISCONNECT_CMD
777 * which will be notified to cfg80211.
778 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300779
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530780 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530781 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300782 return;
783 }
784
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530785 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300786
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530787 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530788 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530789 bssid, NULL, 0,
790 NULL, 0,
791 WLAN_STATUS_UNSPECIFIED_FAILURE,
792 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530793 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530794 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530795 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300796 }
797
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530798 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300799}
800
Kalle Valobdcd8172011-07-18 00:22:30 +0300801static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
802 struct cfg80211_scan_request *request)
803{
804 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530805 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300806 s8 n_channels = 0;
807 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300808 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530809 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300810
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530811 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300812 return -EIO;
813
814 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530815 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300816 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530817 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530818 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300819 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
820 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300821 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300822 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300823 }
824 }
825
826 if (request->n_ssids && request->ssids[0].ssid_len) {
827 u8 i;
828
829 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
830 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
831
832 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530833 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
834 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300835 request->ssids[i].ssid_len,
836 request->ssids[i].ssid);
837 }
838
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300839 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530840 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
841 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300842 request->ie, request->ie_len);
843 if (ret) {
844 ath6kl_err("failed to set Probe Request appie for "
845 "scan");
846 return ret;
847 }
848 }
849
Jouni Malinen11869be2011-09-02 20:07:06 +0300850 /*
851 * Scan only the requested channels if the request specifies a set of
852 * channels. If the list is longer than the target supports, do not
853 * configure the list and instead, scan all available channels.
854 */
855 if (request->n_channels > 0 &&
856 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300857 u8 i;
858
Jouni Malinen11869be2011-09-02 20:07:06 +0300859 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300860
861 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
862 if (channels == NULL) {
863 ath6kl_warn("failed to set scan channels, "
864 "scan all channels");
865 n_channels = 0;
866 }
867
868 for (i = 0; i < n_channels; i++)
869 channels[i] = request->channels[i]->center_freq;
870 }
871
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530872 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530873 force_fg_scan = 1;
874
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530875 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
876 force_fg_scan, false, 0, 0, n_channels,
877 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300878 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300879 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300880 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530881 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300882
Edward Lu1276c9e2011-08-30 21:58:00 +0300883 kfree(channels);
884
Kalle Valobdcd8172011-07-18 00:22:30 +0300885 return ret;
886}
887
Kalle Valo1c17d312011-11-01 08:43:56 +0200888void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300889{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530890 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300891 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300892
Kalle Valo1c17d312011-11-01 08:43:56 +0200893 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
894 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300895
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530896 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300897 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300898
Kalle Valo1c17d312011-11-01 08:43:56 +0200899 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300900 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300901
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530902 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
903 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530904 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
905 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300906 0, NULL);
907 }
908 }
909
910out:
Kalle Valocb938212011-10-27 18:47:46 +0300911 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530912 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300913}
914
915static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
916 u8 key_index, bool pairwise,
917 const u8 *mac_addr,
918 struct key_params *params)
919{
920 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530921 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300922 struct ath6kl_key *key = NULL;
923 u8 key_usage;
924 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300925
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530926 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300927 return -EIO;
928
Jouni Malinen837cb972011-10-11 17:31:57 +0300929 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
930 if (params->key_len != WMI_KRK_LEN)
931 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530932 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
933 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300934 }
935
Kalle Valobdcd8172011-07-18 00:22:30 +0300936 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
937 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
938 "%s: key index %d out of bounds\n", __func__,
939 key_index);
940 return -ENOENT;
941 }
942
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530943 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300944 memset(key, 0, sizeof(struct ath6kl_key));
945
946 if (pairwise)
947 key_usage = PAIRWISE_USAGE;
948 else
949 key_usage = GROUP_USAGE;
950
951 if (params) {
Dai Shuibing5e070212011-11-03 11:39:37 +0200952 int seq_len = params->seq_len;
953 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
954 seq_len > ATH6KL_KEY_SEQ_LEN) {
955 /* Only first half of the WPI PN is configured */
956 seq_len = ATH6KL_KEY_SEQ_LEN;
957 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300958 if (params->key_len > WLAN_MAX_KEY_LEN ||
Dai Shuibing5e070212011-11-03 11:39:37 +0200959 seq_len > sizeof(key->seq))
Kalle Valobdcd8172011-07-18 00:22:30 +0300960 return -EINVAL;
961
962 key->key_len = params->key_len;
963 memcpy(key->key, params->key, key->key_len);
Dai Shuibing5e070212011-11-03 11:39:37 +0200964 key->seq_len = seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300965 memcpy(key->seq, params->seq, key->seq_len);
966 key->cipher = params->cipher;
967 }
968
969 switch (key->cipher) {
970 case WLAN_CIPHER_SUITE_WEP40:
971 case WLAN_CIPHER_SUITE_WEP104:
972 key_type = WEP_CRYPT;
973 break;
974
975 case WLAN_CIPHER_SUITE_TKIP:
976 key_type = TKIP_CRYPT;
977 break;
978
979 case WLAN_CIPHER_SUITE_CCMP:
980 key_type = AES_CRYPT;
981 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200982 case WLAN_CIPHER_SUITE_SMS4:
983 key_type = WAPI_CRYPT;
984 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300985
986 default:
987 return -ENOTSUPP;
988 }
989
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530990 if (((vif->auth_mode == WPA_PSK_AUTH)
991 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300992 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530993 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300994
995 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
996 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
997 __func__, key_index, key->key_len, key_type,
998 key_usage, key->seq_len);
999
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301000 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001001
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301002 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001003 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
1004 ar->ap_mode_bkey.valid = true;
1005 ar->ap_mode_bkey.key_index = key_index;
1006 ar->ap_mode_bkey.key_type = key_type;
1007 ar->ap_mode_bkey.key_len = key->key_len;
1008 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301009 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001010 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1011 "key configuration until AP mode has been "
1012 "started\n");
1013 /*
1014 * The key will be set in ath6kl_connect_ap_mode() once
1015 * the connected event is received from the target.
1016 */
1017 return 0;
1018 }
1019 }
1020
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301021 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301022 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001023 /*
1024 * Store the key locally so that it can be re-configured after
1025 * the AP mode has properly started
1026 * (ath6kl_install_statioc_wep_keys).
1027 */
1028 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1029 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301030 vif->wep_key_list[key_index].key_len = key->key_len;
1031 memcpy(vif->wep_key_list[key_index].key, key->key,
1032 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001033 return 0;
1034 }
1035
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001036 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1037 vif->def_txkey_index,
1038 key_type, key_usage, key->key_len,
1039 key->seq, key->seq_len, key->key,
1040 KEY_OP_INIT_VAL,
1041 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001042}
1043
1044static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1045 u8 key_index, bool pairwise,
1046 const u8 *mac_addr)
1047{
1048 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301049 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001050
1051 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1052
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301053 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001054 return -EIO;
1055
1056 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1057 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1058 "%s: key index %d out of bounds\n", __func__,
1059 key_index);
1060 return -ENOENT;
1061 }
1062
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301063 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001064 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1065 "%s: index %d is empty\n", __func__, key_index);
1066 return 0;
1067 }
1068
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301069 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001070
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301071 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001072}
1073
1074static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1075 u8 key_index, bool pairwise,
1076 const u8 *mac_addr, void *cookie,
1077 void (*callback) (void *cookie,
1078 struct key_params *))
1079{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301080 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001081 struct ath6kl_key *key = NULL;
1082 struct key_params params;
1083
1084 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1085
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301086 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001087 return -EIO;
1088
1089 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1090 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1091 "%s: key index %d out of bounds\n", __func__,
1092 key_index);
1093 return -ENOENT;
1094 }
1095
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301096 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001097 memset(&params, 0, sizeof(params));
1098 params.cipher = key->cipher;
1099 params.key_len = key->key_len;
1100 params.seq_len = key->seq_len;
1101 params.seq = key->seq;
1102 params.key = key->key;
1103
1104 callback(cookie, &params);
1105
1106 return key->key_len ? 0 : -ENOENT;
1107}
1108
1109static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1110 struct net_device *ndev,
1111 u8 key_index, bool unicast,
1112 bool multicast)
1113{
1114 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301115 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001116 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001117 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001118 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001119
1120 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1121
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301122 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001123 return -EIO;
1124
1125 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1126 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1127 "%s: key index %d out of bounds\n",
1128 __func__, key_index);
1129 return -ENOENT;
1130 }
1131
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301132 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001133 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1134 __func__, key_index);
1135 return -EINVAL;
1136 }
1137
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301138 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301139 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001140 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301141 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001142 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001143 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301144 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001145 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301146 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001147
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301148 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001149 return 0; /* Delay until AP mode has been started */
1150
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001151 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1152 vif->def_txkey_index,
1153 key_type, key_usage,
1154 key->key_len, key->seq, key->seq_len,
1155 key->key,
1156 KEY_OP_INIT_VAL, NULL,
1157 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001158}
1159
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301160void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001161 bool ismcast)
1162{
1163 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1164 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1165
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301166 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001167 (ismcast ? NL80211_KEYTYPE_GROUP :
1168 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1169 GFP_KERNEL);
1170}
1171
1172static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1173{
1174 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301175 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001176 int ret;
1177
1178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1179 changed);
1180
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301181 vif = ath6kl_vif_first(ar);
1182 if (!vif)
1183 return -EIO;
1184
1185 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001186 return -EIO;
1187
1188 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1189 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1190 if (ret != 0) {
1191 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1192 return -EIO;
1193 }
1194 }
1195
1196 return 0;
1197}
1198
1199/*
1200 * The type nl80211_tx_power_setting replaces the following
1201 * data type from 2.6.36 onwards
1202*/
1203static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1204 enum nl80211_tx_power_setting type,
1205 int dbm)
1206{
1207 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301208 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001209 u8 ath6kl_dbm;
1210
1211 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1212 type, dbm);
1213
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301214 vif = ath6kl_vif_first(ar);
1215 if (!vif)
1216 return -EIO;
1217
1218 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001219 return -EIO;
1220
1221 switch (type) {
1222 case NL80211_TX_POWER_AUTOMATIC:
1223 return 0;
1224 case NL80211_TX_POWER_LIMITED:
1225 ar->tx_pwr = ath6kl_dbm = dbm;
1226 break;
1227 default:
1228 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1229 __func__, type);
1230 return -EOPNOTSUPP;
1231 }
1232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301233 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001234
1235 return 0;
1236}
1237
1238static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1239{
1240 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301241 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001242
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301243 vif = ath6kl_vif_first(ar);
1244 if (!vif)
1245 return -EIO;
1246
1247 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001248 return -EIO;
1249
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301250 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001251 ar->tx_pwr = 0;
1252
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301253 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001254 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1255 return -EIO;
1256 }
1257
1258 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1259 5 * HZ);
1260
1261 if (signal_pending(current)) {
1262 ath6kl_err("target did not respond\n");
1263 return -EINTR;
1264 }
1265 }
1266
1267 *dbm = ar->tx_pwr;
1268 return 0;
1269}
1270
1271static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1272 struct net_device *dev,
1273 bool pmgmt, int timeout)
1274{
1275 struct ath6kl *ar = ath6kl_priv(dev);
1276 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301277 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001278
1279 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1280 __func__, pmgmt, timeout);
1281
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301282 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001283 return -EIO;
1284
1285 if (pmgmt) {
1286 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1287 mode.pwr_mode = REC_POWER;
1288 } else {
1289 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1290 mode.pwr_mode = MAX_PERF_POWER;
1291 }
1292
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301293 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1294 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001295 ath6kl_err("wmi_powermode_cmd failed\n");
1296 return -EIO;
1297 }
1298
1299 return 0;
1300}
1301
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301302static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1303 char *name,
1304 enum nl80211_iftype type,
1305 u32 *flags,
1306 struct vif_params *params)
1307{
1308 struct ath6kl *ar = wiphy_priv(wiphy);
1309 struct net_device *ndev;
1310 u8 if_idx, nw_type;
1311
1312 if (ar->num_vif == MAX_NUM_VIF) {
1313 ath6kl_err("Reached maximum number of supported vif\n");
1314 return ERR_PTR(-EINVAL);
1315 }
1316
1317 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1318 ath6kl_err("Not a supported interface type\n");
1319 return ERR_PTR(-EINVAL);
1320 }
1321
1322 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1323 if (!ndev)
1324 return ERR_PTR(-ENOMEM);
1325
1326 ar->num_vif++;
1327
1328 return ndev;
1329}
1330
1331static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1332 struct net_device *ndev)
1333{
1334 struct ath6kl *ar = wiphy_priv(wiphy);
1335 struct ath6kl_vif *vif = netdev_priv(ndev);
1336
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301337 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301338 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301339 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301340
1341 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1342
1343 ath6kl_deinit_if_data(vif);
1344
1345 return 0;
1346}
1347
Kalle Valobdcd8172011-07-18 00:22:30 +03001348static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1349 struct net_device *ndev,
1350 enum nl80211_iftype type, u32 *flags,
1351 struct vif_params *params)
1352{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301353 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001354
1355 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1356
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301357 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001358 return -EIO;
1359
1360 switch (type) {
1361 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301362 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001363 break;
1364 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301365 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001366 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001367 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301368 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001369 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001370 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301371 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001372 break;
1373 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301374 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001375 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001376 default:
1377 ath6kl_err("invalid interface type %u\n", type);
1378 return -EOPNOTSUPP;
1379 }
1380
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301381 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001382
1383 return 0;
1384}
1385
1386static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1387 struct net_device *dev,
1388 struct cfg80211_ibss_params *ibss_param)
1389{
1390 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301391 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001392 int status;
1393
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301394 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001395 return -EIO;
1396
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301397 vif->ssid_len = ibss_param->ssid_len;
1398 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001399
1400 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301401 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001402
1403 if (ibss_param->channel_fixed) {
1404 /*
1405 * TODO: channel_fixed: The channel should be fixed, do not
1406 * search for IBSSs to join on other channels. Target
1407 * firmware does not support this feature, needs to be
1408 * updated.
1409 */
1410 return -EOPNOTSUPP;
1411 }
1412
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301413 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001414 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301415 memcpy(vif->req_bssid, ibss_param->bssid,
1416 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001417
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301418 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001419
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301420 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001421 if (status)
1422 return status;
1423
1424 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301425 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1426 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001427 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301428 ath6kl_set_cipher(vif, 0, true);
1429 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001430 }
1431
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301432 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001433
1434 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1435 "%s: connect called with authmode %d dot11 auth %d"
1436 " PW crypto %d PW crypto len %d GRP crypto %d"
1437 " GRP crypto len %d channel hint %u\n",
1438 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301439 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1440 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301441 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001442
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301443 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301444 vif->dot11_auth_mode, vif->auth_mode,
1445 vif->prwise_crypto,
1446 vif->prwise_crypto_len,
1447 vif->grp_crypto, vif->grp_crypto_len,
1448 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301449 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001450 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301451 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001452
1453 return 0;
1454}
1455
1456static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1457 struct net_device *dev)
1458{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301459 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001460
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301461 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001462 return -EIO;
1463
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301464 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301465 memset(vif->ssid, 0, sizeof(vif->ssid));
1466 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001467
1468 return 0;
1469}
1470
1471static const u32 cipher_suites[] = {
1472 WLAN_CIPHER_SUITE_WEP40,
1473 WLAN_CIPHER_SUITE_WEP104,
1474 WLAN_CIPHER_SUITE_TKIP,
1475 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001476 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001477 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001478};
1479
1480static bool is_rate_legacy(s32 rate)
1481{
1482 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1483 6000, 9000, 12000, 18000, 24000,
1484 36000, 48000, 54000
1485 };
1486 u8 i;
1487
1488 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1489 if (rate == legacy[i])
1490 return true;
1491
1492 return false;
1493}
1494
1495static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1496{
1497 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1498 52000, 58500, 65000, 72200
1499 };
1500 u8 i;
1501
1502 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1503 if (rate == ht20[i]) {
1504 if (i == ARRAY_SIZE(ht20) - 1)
1505 /* last rate uses sgi */
1506 *sgi = true;
1507 else
1508 *sgi = false;
1509
1510 *mcs = i;
1511 return true;
1512 }
1513 }
1514 return false;
1515}
1516
1517static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1518{
1519 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1520 81000, 108000, 121500, 135000,
1521 150000
1522 };
1523 u8 i;
1524
1525 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1526 if (rate == ht40[i]) {
1527 if (i == ARRAY_SIZE(ht40) - 1)
1528 /* last rate uses sgi */
1529 *sgi = true;
1530 else
1531 *sgi = false;
1532
1533 *mcs = i;
1534 return true;
1535 }
1536 }
1537
1538 return false;
1539}
1540
1541static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1542 u8 *mac, struct station_info *sinfo)
1543{
1544 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301545 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001546 long left;
1547 bool sgi;
1548 s32 rate;
1549 int ret;
1550 u8 mcs;
1551
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301552 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001553 return -ENOENT;
1554
1555 if (down_interruptible(&ar->sem))
1556 return -EBUSY;
1557
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301558 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001559
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301560 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001561
1562 if (ret != 0) {
1563 up(&ar->sem);
1564 return -EIO;
1565 }
1566
1567 left = wait_event_interruptible_timeout(ar->event_wq,
1568 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301569 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001570 WMI_TIMEOUT);
1571
1572 up(&ar->sem);
1573
1574 if (left == 0)
1575 return -ETIMEDOUT;
1576 else if (left < 0)
1577 return left;
1578
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301579 if (vif->target_stats.rx_byte) {
1580 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001581 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301582 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001583 sinfo->filled |= STATION_INFO_RX_PACKETS;
1584 }
1585
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301586 if (vif->target_stats.tx_byte) {
1587 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001588 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301589 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001590 sinfo->filled |= STATION_INFO_TX_PACKETS;
1591 }
1592
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301593 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001594 sinfo->filled |= STATION_INFO_SIGNAL;
1595
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301596 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001597
1598 if (is_rate_legacy(rate)) {
1599 sinfo->txrate.legacy = rate / 100;
1600 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1601 if (sgi) {
1602 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1603 sinfo->txrate.mcs = mcs - 1;
1604 } else {
1605 sinfo->txrate.mcs = mcs;
1606 }
1607
1608 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1609 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1610 if (sgi) {
1611 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1612 sinfo->txrate.mcs = mcs - 1;
1613 } else {
1614 sinfo->txrate.mcs = mcs;
1615 }
1616
1617 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1618 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1619 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001620 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1621 "invalid rate from stats: %d\n", rate);
1622 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001623 return 0;
1624 }
1625
1626 sinfo->filled |= STATION_INFO_TX_BITRATE;
1627
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301628 if (test_bit(CONNECTED, &vif->flags) &&
1629 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301630 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001631 sinfo->filled |= STATION_INFO_BSS_PARAM;
1632 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301633 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1634 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001635 }
1636
Kalle Valobdcd8172011-07-18 00:22:30 +03001637 return 0;
1638}
1639
1640static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1641 struct cfg80211_pmksa *pmksa)
1642{
1643 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301644 struct ath6kl_vif *vif = netdev_priv(netdev);
1645
1646 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001647 pmksa->pmkid, true);
1648}
1649
1650static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1651 struct cfg80211_pmksa *pmksa)
1652{
1653 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301654 struct ath6kl_vif *vif = netdev_priv(netdev);
1655
1656 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001657 pmksa->pmkid, false);
1658}
1659
1660static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1661{
1662 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301663 struct ath6kl_vif *vif = netdev_priv(netdev);
1664
1665 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301666 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1667 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001668 return 0;
1669}
1670
Raja Mani6cb3c712011-11-07 22:52:45 +02001671static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1672{
1673 struct ath6kl_vif *vif;
1674 int ret, pos, left;
1675 u32 filter = 0;
1676 u16 i;
1677 u8 mask[WOW_MASK_SIZE];
1678
1679 vif = ath6kl_vif_first(ar);
1680 if (!vif)
1681 return -EIO;
1682
1683 if (!ath6kl_cfg80211_ready(vif))
1684 return -EIO;
1685
1686 if (!test_bit(CONNECTED, &vif->flags))
1687 return -EINVAL;
1688
1689 /* Clear existing WOW patterns */
1690 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1691 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1692 WOW_LIST_ID, i);
1693 /* Configure new WOW patterns */
1694 for (i = 0; i < wow->n_patterns; i++) {
1695
1696 /*
1697 * Convert given nl80211 specific mask value to equivalent
1698 * driver specific mask value and send it to the chip along
1699 * with patterns. For example, If the mask value defined in
1700 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1701 * then equivalent driver specific mask value is
1702 * "0xFF 0x00 0xFF 0x00".
1703 */
1704 memset(&mask, 0, sizeof(mask));
1705 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1706 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1707 mask[pos] = 0xFF;
1708 }
1709 /*
1710 * Note: Pattern's offset is not passed as part of wowlan
1711 * parameter from CFG layer. So it's always passed as ZERO
1712 * to the firmware. It means, given WOW patterns are always
1713 * matched from the first byte of received pkt in the firmware.
1714 */
1715 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1716 vif->fw_vif_idx, WOW_LIST_ID,
1717 wow->patterns[i].pattern_len,
1718 0 /* pattern offset */,
1719 wow->patterns[i].pattern, mask);
1720 if (ret)
1721 return ret;
1722 }
1723
1724 if (wow->disconnect)
1725 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1726
1727 if (wow->magic_pkt)
1728 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1729
1730 if (wow->gtk_rekey_failure)
1731 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1732
1733 if (wow->eap_identity_req)
1734 filter |= WOW_FILTER_OPTION_EAP_REQ;
1735
1736 if (wow->four_way_handshake)
1737 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1738
1739 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1740 ATH6KL_WOW_MODE_ENABLE,
1741 filter,
1742 WOW_HOST_REQ_DELAY);
1743 if (ret)
1744 return ret;
1745
1746 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1747 ATH6KL_HOST_MODE_ASLEEP);
1748 if (ret)
1749 return ret;
1750
1751 if (ar->tx_pending[ar->ctrl_ep]) {
1752 left = wait_event_interruptible_timeout(ar->event_wq,
1753 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1754 if (left == 0) {
1755 ath6kl_warn("clear wmi ctrl data timeout\n");
1756 ret = -ETIMEDOUT;
1757 } else if (left < 0) {
1758 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1759 ret = left;
1760 }
1761 }
1762
1763 return ret;
1764}
1765
1766static int ath6kl_wow_resume(struct ath6kl *ar)
1767{
1768 struct ath6kl_vif *vif;
1769 int ret;
1770
1771 vif = ath6kl_vif_first(ar);
1772 if (!vif)
1773 return -EIO;
1774
1775 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1776 ATH6KL_HOST_MODE_AWAKE);
1777 return ret;
1778}
1779
Kalle Valo52d81a62011-11-01 08:44:21 +02001780int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001781 enum ath6kl_cfg_suspend_mode mode,
1782 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001783{
1784 int ret;
1785
Kalle Valo52d81a62011-11-01 08:44:21 +02001786 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001787 case ATH6KL_CFG_SUSPEND_WOW:
1788
1789 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1790
1791 /* Flush all non control pkts in TX path */
1792 ath6kl_tx_data_cleanup(ar);
1793
1794 ret = ath6kl_wow_suspend(ar, wow);
1795 if (ret) {
1796 ath6kl_err("wow suspend failed: %d\n", ret);
1797 return ret;
1798 }
1799 ar->state = ATH6KL_STATE_WOW;
1800 break;
1801
Kalle Valo52d81a62011-11-01 08:44:21 +02001802 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001803
1804 ath6kl_cfg80211_stop(ar);
1805
Kalle Valo52d81a62011-11-01 08:44:21 +02001806 /* save the current power mode before enabling power save */
1807 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1808
1809 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1810 if (ret) {
1811 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1812 ret);
1813 }
1814
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001815 ar->state = ATH6KL_STATE_DEEPSLEEP;
1816
Kalle Valo52d81a62011-11-01 08:44:21 +02001817 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001818
1819 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001820
1821 ath6kl_cfg80211_stop(ar);
1822
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001823 if (ar->state == ATH6KL_STATE_OFF) {
1824 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1825 "suspend hw off, no action for cutpower\n");
1826 break;
1827 }
1828
1829 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1830
1831 ret = ath6kl_init_hw_stop(ar);
1832 if (ret) {
1833 ath6kl_warn("failed to stop hw during suspend: %d\n",
1834 ret);
1835 }
1836
1837 ar->state = ATH6KL_STATE_CUTPOWER;
1838
1839 break;
1840
1841 default:
1842 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001843 }
1844
1845 return 0;
1846}
1847
1848int ath6kl_cfg80211_resume(struct ath6kl *ar)
1849{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001850 int ret;
1851
1852 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001853 case ATH6KL_STATE_WOW:
1854 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1855
1856 ret = ath6kl_wow_resume(ar);
1857 if (ret) {
1858 ath6kl_warn("wow mode resume failed: %d\n", ret);
1859 return ret;
1860 }
1861
1862 ar->state = ATH6KL_STATE_ON;
1863 break;
1864
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001865 case ATH6KL_STATE_DEEPSLEEP:
1866 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1867 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1868 ar->wmi->saved_pwr_mode);
1869 if (ret) {
1870 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1871 ret);
1872 }
1873 }
1874
1875 ar->state = ATH6KL_STATE_ON;
1876
1877 break;
1878
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001879 case ATH6KL_STATE_CUTPOWER:
1880 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1881
1882 ret = ath6kl_init_hw_start(ar);
1883 if (ret) {
1884 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1885 return ret;
1886 }
Raja Manid7c44e02011-11-07 22:52:46 +02001887 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001888
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001889 default:
1890 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001891 }
1892
1893 return 0;
1894}
1895
Kalle Valoabcb3442011-07-22 08:26:20 +03001896#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001897
1898/* hif layer decides what suspend mode to use */
1899static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001900 struct cfg80211_wowlan *wow)
1901{
1902 struct ath6kl *ar = wiphy_priv(wiphy);
1903
Raja Mani0f60e9f2011-11-07 22:52:45 +02001904 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001905}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001906
Kalle Valo52d81a62011-11-01 08:44:21 +02001907static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001908{
1909 struct ath6kl *ar = wiphy_priv(wiphy);
1910
1911 return ath6kl_hif_resume(ar);
1912}
Raja Mania918fb32011-11-07 22:52:46 +02001913
1914/*
1915 * FIXME: WOW suspend mode is selected if the host sdio controller supports
1916 * both sdio irq wake up and keep power. The target pulls sdio data line to
1917 * wake up the host when WOW pattern matches. This causes sdio irq handler
1918 * is being called in the host side which internally hits ath6kl's RX path.
1919 *
1920 * Since sdio interrupt is not disabled, RX path executes even before
1921 * the host executes the actual resume operation from PM module.
1922 *
1923 * In the current scenario, WOW resume should happen before start processing
1924 * any data from the target. So It's required to perform WOW resume in RX path.
1925 * Ideally we should perform WOW resume only in the actual platform
1926 * resume path. This area needs bit rework to avoid WOW resume in RX path.
1927 *
1928 * ath6kl_check_wow_status() is called from ath6kl_rx().
1929 */
1930void ath6kl_check_wow_status(struct ath6kl *ar)
1931{
1932 if (ar->state == ATH6KL_STATE_WOW)
1933 ath6kl_cfg80211_resume(ar);
1934}
1935
1936#else
1937
1938void ath6kl_check_wow_status(struct ath6kl *ar)
1939{
1940}
Kalle Valoabcb3442011-07-22 08:26:20 +03001941#endif
1942
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001943static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1944 struct ieee80211_channel *chan,
1945 enum nl80211_channel_type channel_type)
1946{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301947 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001948
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301949 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001950 return -EIO;
1951
1952 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1953 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301954 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001955
1956 return 0;
1957}
1958
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001959static bool ath6kl_is_p2p_ie(const u8 *pos)
1960{
1961 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1962 pos[2] == 0x50 && pos[3] == 0x6f &&
1963 pos[4] == 0x9a && pos[5] == 0x09;
1964}
1965
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301966static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1967 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001968{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301969 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001970 const u8 *pos;
1971 u8 *buf = NULL;
1972 size_t len = 0;
1973 int ret;
1974
1975 /*
1976 * Filter out P2P IE(s) since they will be included depending on
1977 * the Probe Request frame in ath6kl_send_go_probe_resp().
1978 */
1979
1980 if (ies && ies_len) {
1981 buf = kmalloc(ies_len, GFP_KERNEL);
1982 if (buf == NULL)
1983 return -ENOMEM;
1984 pos = ies;
1985 while (pos + 1 < ies + ies_len) {
1986 if (pos + 2 + pos[1] > ies + ies_len)
1987 break;
1988 if (!ath6kl_is_p2p_ie(pos)) {
1989 memcpy(buf + len, pos, 2 + pos[1]);
1990 len += 2 + pos[1];
1991 }
1992 pos += 2 + pos[1];
1993 }
1994 }
1995
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301996 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1997 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001998 kfree(buf);
1999 return ret;
2000}
2001
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002002static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2003 struct beacon_parameters *info, bool add)
2004{
2005 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302006 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002007 struct ieee80211_mgmt *mgmt;
2008 u8 *ies;
2009 int ies_len;
2010 struct wmi_connect_cmd p;
2011 int res;
2012 int i;
2013
2014 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2015
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302016 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002017 return -EIO;
2018
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302019 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002020 return -EOPNOTSUPP;
2021
2022 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302023 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2024 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002025 info->beacon_ies,
2026 info->beacon_ies_len);
2027 if (res)
2028 return res;
2029 }
2030 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302031 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002032 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002033 if (res)
2034 return res;
2035 }
2036 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302037 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2038 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002039 info->assocresp_ies,
2040 info->assocresp_ies_len);
2041 if (res)
2042 return res;
2043 }
2044
2045 if (!add)
2046 return 0;
2047
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002048 ar->ap_mode_bkey.valid = false;
2049
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002050 /* TODO:
2051 * info->interval
2052 * info->dtim_period
2053 */
2054
2055 if (info->head == NULL)
2056 return -EINVAL;
2057 mgmt = (struct ieee80211_mgmt *) info->head;
2058 ies = mgmt->u.beacon.variable;
2059 if (ies > info->head + info->head_len)
2060 return -EINVAL;
2061 ies_len = info->head + info->head_len - ies;
2062
2063 if (info->ssid == NULL)
2064 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302065 memcpy(vif->ssid, info->ssid, info->ssid_len);
2066 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002067 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2068 return -EOPNOTSUPP; /* TODO */
2069
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302070 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002071
2072 memset(&p, 0, sizeof(p));
2073
2074 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2075 switch (info->crypto.akm_suites[i]) {
2076 case WLAN_AKM_SUITE_8021X:
2077 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2078 p.auth_mode |= WPA_AUTH;
2079 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2080 p.auth_mode |= WPA2_AUTH;
2081 break;
2082 case WLAN_AKM_SUITE_PSK:
2083 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2084 p.auth_mode |= WPA_PSK_AUTH;
2085 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2086 p.auth_mode |= WPA2_PSK_AUTH;
2087 break;
2088 }
2089 }
2090 if (p.auth_mode == 0)
2091 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302092 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002093
2094 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2095 switch (info->crypto.ciphers_pairwise[i]) {
2096 case WLAN_CIPHER_SUITE_WEP40:
2097 case WLAN_CIPHER_SUITE_WEP104:
2098 p.prwise_crypto_type |= WEP_CRYPT;
2099 break;
2100 case WLAN_CIPHER_SUITE_TKIP:
2101 p.prwise_crypto_type |= TKIP_CRYPT;
2102 break;
2103 case WLAN_CIPHER_SUITE_CCMP:
2104 p.prwise_crypto_type |= AES_CRYPT;
2105 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002106 case WLAN_CIPHER_SUITE_SMS4:
2107 p.prwise_crypto_type |= WAPI_CRYPT;
2108 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002109 }
2110 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002111 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002112 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302113 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002114 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302115 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002116
2117 switch (info->crypto.cipher_group) {
2118 case WLAN_CIPHER_SUITE_WEP40:
2119 case WLAN_CIPHER_SUITE_WEP104:
2120 p.grp_crypto_type = WEP_CRYPT;
2121 break;
2122 case WLAN_CIPHER_SUITE_TKIP:
2123 p.grp_crypto_type = TKIP_CRYPT;
2124 break;
2125 case WLAN_CIPHER_SUITE_CCMP:
2126 p.grp_crypto_type = AES_CRYPT;
2127 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002128 case WLAN_CIPHER_SUITE_SMS4:
2129 p.grp_crypto_type = WAPI_CRYPT;
2130 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002131 default:
2132 p.grp_crypto_type = NONE_CRYPT;
2133 break;
2134 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302135 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002136
2137 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302138 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002139
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302140 p.ssid_len = vif->ssid_len;
2141 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2142 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302143 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002144
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302145 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002146 if (res < 0)
2147 return res;
2148
2149 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002150}
2151
2152static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2153 struct beacon_parameters *info)
2154{
2155 return ath6kl_ap_beacon(wiphy, dev, info, true);
2156}
2157
2158static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2159 struct beacon_parameters *info)
2160{
2161 return ath6kl_ap_beacon(wiphy, dev, info, false);
2162}
2163
2164static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2165{
2166 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302167 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002168
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302169 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002170 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302171 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002172 return -ENOTCONN;
2173
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302174 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302175 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002176
2177 return 0;
2178}
2179
Jouni Malinen23875132011-08-30 21:57:53 +03002180static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2181 u8 *mac, struct station_parameters *params)
2182{
2183 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302184 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002185
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302186 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002187 return -EOPNOTSUPP;
2188
2189 /* Use this only for authorizing/unauthorizing a station */
2190 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2191 return -EOPNOTSUPP;
2192
2193 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302194 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2195 WMI_AP_MLME_AUTHORIZE, mac, 0);
2196 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2197 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002198}
2199
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002200static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2201 struct net_device *dev,
2202 struct ieee80211_channel *chan,
2203 enum nl80211_channel_type channel_type,
2204 unsigned int duration,
2205 u64 *cookie)
2206{
2207 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302208 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002209 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002210
2211 /* TODO: if already pending or ongoing remain-on-channel,
2212 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002213 id = ++vif->last_roc_id;
2214 if (id == 0) {
2215 /* Do not use 0 as the cookie value */
2216 id = ++vif->last_roc_id;
2217 }
2218 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002219
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302220 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2221 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002222}
2223
2224static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2225 struct net_device *dev,
2226 u64 cookie)
2227{
2228 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302229 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002230
Jouni Malinen10522612011-10-27 16:00:13 +03002231 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002232 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002233 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002234
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302235 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002236}
2237
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302238static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2239 const u8 *buf, size_t len,
2240 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002241{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302242 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002243 const u8 *pos;
2244 u8 *p2p;
2245 int p2p_len;
2246 int ret;
2247 const struct ieee80211_mgmt *mgmt;
2248
2249 mgmt = (const struct ieee80211_mgmt *) buf;
2250
2251 /* Include P2P IE(s) from the frame generated in user space. */
2252
2253 p2p = kmalloc(len, GFP_KERNEL);
2254 if (p2p == NULL)
2255 return -ENOMEM;
2256 p2p_len = 0;
2257
2258 pos = mgmt->u.probe_resp.variable;
2259 while (pos + 1 < buf + len) {
2260 if (pos + 2 + pos[1] > buf + len)
2261 break;
2262 if (ath6kl_is_p2p_ie(pos)) {
2263 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2264 p2p_len += 2 + pos[1];
2265 }
2266 pos += 2 + pos[1];
2267 }
2268
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302269 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2270 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002271 kfree(p2p);
2272 return ret;
2273}
2274
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002275static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2276 struct ieee80211_channel *chan, bool offchan,
2277 enum nl80211_channel_type channel_type,
2278 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002279 const u8 *buf, size_t len, bool no_cck,
2280 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002281{
2282 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302283 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002284 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002285 const struct ieee80211_mgmt *mgmt;
2286
2287 mgmt = (const struct ieee80211_mgmt *) buf;
2288 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302289 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002290 ieee80211_is_probe_resp(mgmt->frame_control)) {
2291 /*
2292 * Send Probe Response frame in AP mode using a separate WMI
2293 * command to allow the target to fill in the generic IEs.
2294 */
2295 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302296 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002297 chan->center_freq);
2298 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002299
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302300 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002301 if (id == 0) {
2302 /*
2303 * 0 is a reserved value in the WMI command and shall not be
2304 * used for the command.
2305 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302306 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002307 }
2308
2309 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302310 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2311 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002312 buf, len);
2313}
2314
Jouni Malinenae32c302011-08-30 21:58:01 +03002315static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2316 struct net_device *dev,
2317 u16 frame_type, bool reg)
2318{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302319 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002320
2321 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2322 __func__, frame_type, reg);
2323 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2324 /*
2325 * Note: This notification callback is not allowed to sleep, so
2326 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2327 * hardcode target to report Probe Request frames all the time.
2328 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302329 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002330 }
2331}
2332
Jouni Malinenf80574a2011-08-30 21:58:04 +03002333static const struct ieee80211_txrx_stypes
2334ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2335 [NL80211_IFTYPE_STATION] = {
2336 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2337 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2338 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2339 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2340 },
2341 [NL80211_IFTYPE_P2P_CLIENT] = {
2342 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2343 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2344 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2345 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2346 },
2347 [NL80211_IFTYPE_P2P_GO] = {
2348 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2349 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2350 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2351 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2352 },
2353};
2354
Kalle Valobdcd8172011-07-18 00:22:30 +03002355static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302356 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2357 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002358 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2359 .scan = ath6kl_cfg80211_scan,
2360 .connect = ath6kl_cfg80211_connect,
2361 .disconnect = ath6kl_cfg80211_disconnect,
2362 .add_key = ath6kl_cfg80211_add_key,
2363 .get_key = ath6kl_cfg80211_get_key,
2364 .del_key = ath6kl_cfg80211_del_key,
2365 .set_default_key = ath6kl_cfg80211_set_default_key,
2366 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2367 .set_tx_power = ath6kl_cfg80211_set_txpower,
2368 .get_tx_power = ath6kl_cfg80211_get_txpower,
2369 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2370 .join_ibss = ath6kl_cfg80211_join_ibss,
2371 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2372 .get_station = ath6kl_get_station,
2373 .set_pmksa = ath6kl_set_pmksa,
2374 .del_pmksa = ath6kl_del_pmksa,
2375 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002376 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002377#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002378 .suspend = __ath6kl_cfg80211_suspend,
2379 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002380#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002381 .set_channel = ath6kl_set_channel,
2382 .add_beacon = ath6kl_add_beacon,
2383 .set_beacon = ath6kl_set_beacon,
2384 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002385 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002386 .remain_on_channel = ath6kl_remain_on_channel,
2387 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002388 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002389 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002390};
2391
Kalle Valoec4b7f62011-11-01 08:44:04 +02002392void ath6kl_cfg80211_stop(struct ath6kl *ar)
2393{
2394 struct ath6kl_vif *vif;
2395
2396 /* FIXME: for multi vif */
2397 vif = ath6kl_vif_first(ar);
2398 if (!vif) {
2399 /* save the current power mode before enabling power save */
2400 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2401
2402 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2403 ath6kl_warn("ath6kl_deep_sleep_enable: "
2404 "wmi_powermode_cmd failed\n");
2405 return;
2406 }
2407
2408 switch (vif->sme_state) {
2409 case SME_CONNECTING:
2410 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2411 NULL, 0,
2412 WLAN_STATUS_UNSPECIFIED_FAILURE,
2413 GFP_KERNEL);
2414 break;
2415 case SME_CONNECTED:
2416 default:
2417 /*
2418 * FIXME: oddly enough smeState is in DISCONNECTED during
2419 * suspend, why? Need to send disconnected event in that
2420 * state.
2421 */
2422 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2423 break;
2424 }
2425
2426 if (test_bit(CONNECTED, &vif->flags) ||
2427 test_bit(CONNECT_PEND, &vif->flags))
2428 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2429
2430 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002431 clear_bit(CONNECTED, &vif->flags);
2432 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002433
2434 /* disable scanning */
2435 if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
2436 0, 0, 0, 0, 0, 0, 0) != 0)
2437 printk(KERN_WARNING "ath6kl: failed to disable scan "
2438 "during suspend\n");
2439
2440 ath6kl_cfg80211_scan_complete_event(vif, true);
2441}
2442
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302443struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002444{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002445 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302446 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302447 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002448
2449 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302450 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302451
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302452 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002453 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002454 return NULL;
2455 }
2456
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302457 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302458 if (!multi_norm_if_support)
2459 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302460 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302461 ar->dev = dev;
2462
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302463 if (multi_norm_if_support)
2464 ar->max_norm_iface = 2;
2465 else
2466 ar->max_norm_iface = 1;
2467
2468 /* FIXME: Remove this once the multivif support is enabled */
2469 ar->max_norm_iface = 1;
2470
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302471 spin_lock_init(&ar->lock);
2472 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302473 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302474
2475 init_waitqueue_head(&ar->event_wq);
2476 sema_init(&ar->sem, 1);
2477
2478 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302479 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302480
2481 clear_bit(WMI_ENABLED, &ar->flag);
2482 clear_bit(SKIP_SCAN, &ar->flag);
2483 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2484
2485 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2486 ar->listen_intvl_b = 0;
2487 ar->tx_pwr = 0;
2488
2489 ar->intra_bss = 1;
2490 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2491 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2492 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2493 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2494
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002495 ar->state = ATH6KL_STATE_OFF;
2496
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302497 memset((u8 *)ar->sta_list, 0,
2498 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2499
2500 /* Init the PS queues */
2501 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2502 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2503 skb_queue_head_init(&ar->sta_list[ctr].psq);
2504 }
2505
2506 skb_queue_head_init(&ar->mcastpsq);
2507
2508 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2509
2510 return ar;
2511}
2512
2513int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2514{
2515 struct wiphy *wiphy = ar->wiphy;
2516 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002517
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302518 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002519
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302520 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002521
Kalle Valobdcd8172011-07-18 00:22:30 +03002522 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302523 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002524
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302525 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302526 BIT(NL80211_IFTYPE_ADHOC) |
2527 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002528 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302529 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302530 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002531 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302532
Kalle Valobdcd8172011-07-18 00:22:30 +03002533 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302534 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2535 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2536 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2537 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2538 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002539
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302540 wiphy->cipher_suites = cipher_suites;
2541 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002542
Raja Manieae9e062011-11-07 22:52:46 +02002543 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2544 WIPHY_WOWLAN_DISCONNECT |
2545 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2546 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2547 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2548 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2549 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2550 wiphy->wowlan.pattern_min_len = 1;
2551 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2552
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302553 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002554 if (ret < 0) {
2555 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302556 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002557 }
2558
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302559 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002560}
2561
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302562static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002563{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302564 vif->aggr_cntxt = aggr_init(vif->ndev);
2565 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302566 ath6kl_err("failed to initialize aggr\n");
2567 return -ENOMEM;
2568 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002569
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302570 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302571 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302572 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302573 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302574
2575 return 0;
2576}
2577
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302578void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302579{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302580 struct ath6kl *ar = vif->ar;
2581
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302582 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302583
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302584 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2585
2586 if (vif->nw_type == ADHOC_NETWORK)
2587 ar->ibss_if_active = false;
2588
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302589 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302590
2591 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302592}
2593
2594struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302595 enum nl80211_iftype type, u8 fw_vif_idx,
2596 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302597{
2598 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302599 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302600
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302601 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302602 if (!ndev)
2603 return NULL;
2604
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302605 vif = netdev_priv(ndev);
2606 ndev->ieee80211_ptr = &vif->wdev;
2607 vif->wdev.wiphy = ar->wiphy;
2608 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302609 vif->ndev = ndev;
2610 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2611 vif->wdev.netdev = ndev;
2612 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302613 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302614 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302615
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302616 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2617 if (fw_vif_idx != 0)
2618 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2619 0x2;
2620
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302621 init_netdev(ndev);
2622
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302623 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302624
2625 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302626 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302627 goto err;
2628
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302629 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302630 goto err;
2631
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302632 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302633 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302634 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302635 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302636 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302637
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302638 if (type == NL80211_IFTYPE_ADHOC)
2639 ar->ibss_if_active = true;
2640
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302641 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302642 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302643 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302644
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302645 return ndev;
2646
2647err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302648 aggr_module_destroy(vif->aggr_cntxt);
2649 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302650 return NULL;
2651}
2652
2653void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2654{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302655 wiphy_unregister(ar->wiphy);
2656 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002657}