blob: d2b23da8bdd69c039603458291a9806d5af6d9ed [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
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530568static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300569 struct ieee80211_channel *chan,
570 const u8 *beacon_ie, size_t beacon_ie_len)
571{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530572 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300573 struct cfg80211_bss *bss;
574 u8 *ie;
575
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530576 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530577 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300578 WLAN_CAPABILITY_ESS);
579 if (bss == NULL) {
580 /*
581 * Since cfg80211 may not yet know about the BSS,
582 * generate a partial entry until the first BSS info
583 * event becomes available.
584 *
585 * Prepend SSID element since it is not included in the Beacon
586 * IEs from the target.
587 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530588 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300589 if (ie == NULL)
590 return -ENOMEM;
591 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530592 ie[1] = vif->ssid_len;
593 memcpy(ie + 2, vif->ssid, vif->ssid_len);
594 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530595 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300596 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530597 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300598 0, GFP_KERNEL);
599 if (bss)
600 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
601 "%pM prior to indicating connect/roamed "
602 "event\n", bssid);
603 kfree(ie);
604 } else
605 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
606 "entry\n");
607
608 if (bss == NULL)
609 return -ENOMEM;
610
611 cfg80211_put_bss(bss);
612
613 return 0;
614}
615
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530616void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300617 u8 *bssid, u16 listen_intvl,
618 u16 beacon_intvl,
619 enum network_type nw_type,
620 u8 beacon_ie_len, u8 assoc_req_len,
621 u8 assoc_resp_len, u8 *assoc_info)
622{
Jouni Malinen01cac472011-09-19 19:14:59 +0300623 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530624 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300625
626 /* capinfo + listen interval */
627 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
628
629 /* capinfo + status code + associd */
630 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
631
632 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
633 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
634 assoc_resp_ie_offset;
635
636 assoc_req_len -= assoc_req_ie_offset;
637 assoc_resp_len -= assoc_resp_ie_offset;
638
Jouni Malinen32c10872011-09-19 19:15:07 +0300639 /*
640 * Store Beacon interval here; DTIM period will be available only once
641 * a Beacon frame from the AP is seen.
642 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530643 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530644 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300645
Kalle Valobdcd8172011-07-18 00:22:30 +0300646 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530647 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300648 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
649 "%s: ath6k not in ibss mode\n", __func__);
650 return;
651 }
652 }
653
654 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530655 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
656 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300657 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
658 "%s: ath6k not in station mode\n", __func__);
659 return;
660 }
661 }
662
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530663 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664
Kalle Valobdcd8172011-07-18 00:22:30 +0300665
666 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530667 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300668 return;
669 }
670
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530671 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300672 beacon_ie_len) < 0) {
673 ath6kl_err("could not add cfg80211 bss entry for "
674 "connect/roamed notification\n");
675 return;
676 }
677
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530678 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300679 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530680 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530681 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 assoc_req_ie, assoc_req_len,
683 assoc_resp_ie, assoc_resp_len,
684 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530685 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300686 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530687 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300688 assoc_req_ie, assoc_req_len,
689 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
690 }
691}
692
693static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
694 struct net_device *dev, u16 reason_code)
695{
696 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530697 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300698
699 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
700 reason_code);
701
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530702 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300703 return -EIO;
704
705 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
706 ath6kl_err("busy, destroy in progress\n");
707 return -EBUSY;
708 }
709
710 if (down_interruptible(&ar->sem)) {
711 ath6kl_err("busy, couldn't get access\n");
712 return -ERESTARTSYS;
713 }
714
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530715 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530716 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530717 memset(vif->ssid, 0, sizeof(vif->ssid));
718 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300719
720 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530721 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300722
723 up(&ar->sem);
724
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530725 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530726
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 return 0;
728}
729
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530730void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300731 u8 *bssid, u8 assoc_resp_len,
732 u8 *assoc_info, u16 proto_reason)
733{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530734 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530735
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530736 if (vif->scan_req) {
737 cfg80211_scan_done(vif->scan_req, true);
738 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300739 }
740
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530741 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530742 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300743 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
744 "%s: ath6k not in ibss mode\n", __func__);
745 return;
746 }
747 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530748 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300749 return;
750 }
751
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530752 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530753 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
754 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300755 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
756 "%s: ath6k not in station mode\n", __func__);
757 return;
758 }
759 }
760
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530761 /*
762 * Send a disconnect command to target when a disconnect event is
763 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
764 * request from host) to make the firmware stop trying to connect even
765 * after giving disconnect event. There will be one more disconnect
766 * event for this disconnect command with reason code DISCONNECT_CMD
767 * which will be notified to cfg80211.
768 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300769
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530770 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530771 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300772 return;
773 }
774
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530775 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300776
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530777 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530778 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530779 bssid, NULL, 0,
780 NULL, 0,
781 WLAN_STATUS_UNSPECIFIED_FAILURE,
782 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530783 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530784 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530785 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300786 }
787
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530788 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300789}
790
Kalle Valobdcd8172011-07-18 00:22:30 +0300791static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
792 struct cfg80211_scan_request *request)
793{
794 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530795 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300796 s8 n_channels = 0;
797 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300798 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530799 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300800
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530801 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300802 return -EIO;
803
804 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530805 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300806 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530807 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530808 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300809 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
810 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300811 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300812 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300813 }
814 }
815
816 if (request->n_ssids && request->ssids[0].ssid_len) {
817 u8 i;
818
819 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
820 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
821
822 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530823 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
824 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300825 request->ssids[i].ssid_len,
826 request->ssids[i].ssid);
827 }
828
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300829 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530830 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
831 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300832 request->ie, request->ie_len);
833 if (ret) {
834 ath6kl_err("failed to set Probe Request appie for "
835 "scan");
836 return ret;
837 }
838 }
839
Jouni Malinen11869be2011-09-02 20:07:06 +0300840 /*
841 * Scan only the requested channels if the request specifies a set of
842 * channels. If the list is longer than the target supports, do not
843 * configure the list and instead, scan all available channels.
844 */
845 if (request->n_channels > 0 &&
846 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300847 u8 i;
848
Jouni Malinen11869be2011-09-02 20:07:06 +0300849 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300850
851 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
852 if (channels == NULL) {
853 ath6kl_warn("failed to set scan channels, "
854 "scan all channels");
855 n_channels = 0;
856 }
857
858 for (i = 0; i < n_channels; i++)
859 channels[i] = request->channels[i]->center_freq;
860 }
861
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530862 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530863 force_fg_scan = 1;
864
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530865 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
866 force_fg_scan, false, 0, 0, n_channels,
867 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300868 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300869 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300870 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530871 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300872
Edward Lu1276c9e2011-08-30 21:58:00 +0300873 kfree(channels);
874
Kalle Valobdcd8172011-07-18 00:22:30 +0300875 return ret;
876}
877
Kalle Valo1c17d312011-11-01 08:43:56 +0200878void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300879{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530880 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300881 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300882
Kalle Valo1c17d312011-11-01 08:43:56 +0200883 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
884 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300885
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530886 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300887 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300888
Kalle Valo1c17d312011-11-01 08:43:56 +0200889 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300890 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300891
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530892 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
893 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530894 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
895 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300896 0, NULL);
897 }
898 }
899
900out:
Kalle Valocb938212011-10-27 18:47:46 +0300901 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530902 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300903}
904
905static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
906 u8 key_index, bool pairwise,
907 const u8 *mac_addr,
908 struct key_params *params)
909{
910 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530911 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300912 struct ath6kl_key *key = NULL;
913 u8 key_usage;
914 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300915
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530916 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300917 return -EIO;
918
Jouni Malinen837cb972011-10-11 17:31:57 +0300919 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
920 if (params->key_len != WMI_KRK_LEN)
921 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530922 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
923 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300924 }
925
Kalle Valobdcd8172011-07-18 00:22:30 +0300926 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
927 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
928 "%s: key index %d out of bounds\n", __func__,
929 key_index);
930 return -ENOENT;
931 }
932
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530933 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300934 memset(key, 0, sizeof(struct ath6kl_key));
935
936 if (pairwise)
937 key_usage = PAIRWISE_USAGE;
938 else
939 key_usage = GROUP_USAGE;
940
941 if (params) {
Dai Shuibing5e070212011-11-03 11:39:37 +0200942 int seq_len = params->seq_len;
943 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
944 seq_len > ATH6KL_KEY_SEQ_LEN) {
945 /* Only first half of the WPI PN is configured */
946 seq_len = ATH6KL_KEY_SEQ_LEN;
947 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300948 if (params->key_len > WLAN_MAX_KEY_LEN ||
Dai Shuibing5e070212011-11-03 11:39:37 +0200949 seq_len > sizeof(key->seq))
Kalle Valobdcd8172011-07-18 00:22:30 +0300950 return -EINVAL;
951
952 key->key_len = params->key_len;
953 memcpy(key->key, params->key, key->key_len);
Dai Shuibing5e070212011-11-03 11:39:37 +0200954 key->seq_len = seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300955 memcpy(key->seq, params->seq, key->seq_len);
956 key->cipher = params->cipher;
957 }
958
959 switch (key->cipher) {
960 case WLAN_CIPHER_SUITE_WEP40:
961 case WLAN_CIPHER_SUITE_WEP104:
962 key_type = WEP_CRYPT;
963 break;
964
965 case WLAN_CIPHER_SUITE_TKIP:
966 key_type = TKIP_CRYPT;
967 break;
968
969 case WLAN_CIPHER_SUITE_CCMP:
970 key_type = AES_CRYPT;
971 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200972 case WLAN_CIPHER_SUITE_SMS4:
973 key_type = WAPI_CRYPT;
974 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300975
976 default:
977 return -ENOTSUPP;
978 }
979
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530980 if (((vif->auth_mode == WPA_PSK_AUTH)
981 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300982 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530983 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300984
985 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
986 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
987 __func__, key_index, key->key_len, key_type,
988 key_usage, key->seq_len);
989
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530990 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300991
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530992 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300993 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
994 ar->ap_mode_bkey.valid = true;
995 ar->ap_mode_bkey.key_index = key_index;
996 ar->ap_mode_bkey.key_type = key_type;
997 ar->ap_mode_bkey.key_len = key->key_len;
998 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530999 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001000 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1001 "key configuration until AP mode has been "
1002 "started\n");
1003 /*
1004 * The key will be set in ath6kl_connect_ap_mode() once
1005 * the connected event is received from the target.
1006 */
1007 return 0;
1008 }
1009 }
1010
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301011 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301012 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001013 /*
1014 * Store the key locally so that it can be re-configured after
1015 * the AP mode has properly started
1016 * (ath6kl_install_statioc_wep_keys).
1017 */
1018 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1019 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301020 vif->wep_key_list[key_index].key_len = key->key_len;
1021 memcpy(vif->wep_key_list[key_index].key, key->key,
1022 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001023 return 0;
1024 }
1025
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001026 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1027 vif->def_txkey_index,
1028 key_type, key_usage, key->key_len,
1029 key->seq, key->seq_len, key->key,
1030 KEY_OP_INIT_VAL,
1031 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001032}
1033
1034static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1035 u8 key_index, bool pairwise,
1036 const u8 *mac_addr)
1037{
1038 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301039 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001040
1041 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1042
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301043 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001044 return -EIO;
1045
1046 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1047 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1048 "%s: key index %d out of bounds\n", __func__,
1049 key_index);
1050 return -ENOENT;
1051 }
1052
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301053 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001054 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1055 "%s: index %d is empty\n", __func__, key_index);
1056 return 0;
1057 }
1058
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301059 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001060
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301061 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001062}
1063
1064static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1065 u8 key_index, bool pairwise,
1066 const u8 *mac_addr, void *cookie,
1067 void (*callback) (void *cookie,
1068 struct key_params *))
1069{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301070 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001071 struct ath6kl_key *key = NULL;
1072 struct key_params params;
1073
1074 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1075
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301076 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001077 return -EIO;
1078
1079 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1080 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1081 "%s: key index %d out of bounds\n", __func__,
1082 key_index);
1083 return -ENOENT;
1084 }
1085
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301086 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001087 memset(&params, 0, sizeof(params));
1088 params.cipher = key->cipher;
1089 params.key_len = key->key_len;
1090 params.seq_len = key->seq_len;
1091 params.seq = key->seq;
1092 params.key = key->key;
1093
1094 callback(cookie, &params);
1095
1096 return key->key_len ? 0 : -ENOENT;
1097}
1098
1099static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1100 struct net_device *ndev,
1101 u8 key_index, bool unicast,
1102 bool multicast)
1103{
1104 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301105 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001106 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001107 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001108 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001109
1110 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1111
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301112 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001113 return -EIO;
1114
1115 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1116 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1117 "%s: key index %d out of bounds\n",
1118 __func__, key_index);
1119 return -ENOENT;
1120 }
1121
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301122 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001123 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1124 __func__, key_index);
1125 return -EINVAL;
1126 }
1127
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301128 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301129 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001130 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301131 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001132 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001133 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301134 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001135 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301136 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001137
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301138 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001139 return 0; /* Delay until AP mode has been started */
1140
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001141 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1142 vif->def_txkey_index,
1143 key_type, key_usage,
1144 key->key_len, key->seq, key->seq_len,
1145 key->key,
1146 KEY_OP_INIT_VAL, NULL,
1147 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001148}
1149
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301150void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001151 bool ismcast)
1152{
1153 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1154 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1155
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301156 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001157 (ismcast ? NL80211_KEYTYPE_GROUP :
1158 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1159 GFP_KERNEL);
1160}
1161
1162static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1163{
1164 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301165 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001166 int ret;
1167
1168 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1169 changed);
1170
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301171 vif = ath6kl_vif_first(ar);
1172 if (!vif)
1173 return -EIO;
1174
1175 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001176 return -EIO;
1177
1178 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1179 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1180 if (ret != 0) {
1181 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1182 return -EIO;
1183 }
1184 }
1185
1186 return 0;
1187}
1188
1189/*
1190 * The type nl80211_tx_power_setting replaces the following
1191 * data type from 2.6.36 onwards
1192*/
1193static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1194 enum nl80211_tx_power_setting type,
1195 int dbm)
1196{
1197 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301198 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001199 u8 ath6kl_dbm;
1200
1201 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1202 type, dbm);
1203
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301204 vif = ath6kl_vif_first(ar);
1205 if (!vif)
1206 return -EIO;
1207
1208 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001209 return -EIO;
1210
1211 switch (type) {
1212 case NL80211_TX_POWER_AUTOMATIC:
1213 return 0;
1214 case NL80211_TX_POWER_LIMITED:
1215 ar->tx_pwr = ath6kl_dbm = dbm;
1216 break;
1217 default:
1218 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1219 __func__, type);
1220 return -EOPNOTSUPP;
1221 }
1222
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301223 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001224
1225 return 0;
1226}
1227
1228static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1229{
1230 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301231 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301233 vif = ath6kl_vif_first(ar);
1234 if (!vif)
1235 return -EIO;
1236
1237 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001238 return -EIO;
1239
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301240 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001241 ar->tx_pwr = 0;
1242
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301243 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001244 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1245 return -EIO;
1246 }
1247
1248 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1249 5 * HZ);
1250
1251 if (signal_pending(current)) {
1252 ath6kl_err("target did not respond\n");
1253 return -EINTR;
1254 }
1255 }
1256
1257 *dbm = ar->tx_pwr;
1258 return 0;
1259}
1260
1261static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1262 struct net_device *dev,
1263 bool pmgmt, int timeout)
1264{
1265 struct ath6kl *ar = ath6kl_priv(dev);
1266 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301267 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001268
1269 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1270 __func__, pmgmt, timeout);
1271
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301272 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001273 return -EIO;
1274
1275 if (pmgmt) {
1276 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1277 mode.pwr_mode = REC_POWER;
1278 } else {
1279 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1280 mode.pwr_mode = MAX_PERF_POWER;
1281 }
1282
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301283 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1284 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001285 ath6kl_err("wmi_powermode_cmd failed\n");
1286 return -EIO;
1287 }
1288
1289 return 0;
1290}
1291
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301292static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1293 char *name,
1294 enum nl80211_iftype type,
1295 u32 *flags,
1296 struct vif_params *params)
1297{
1298 struct ath6kl *ar = wiphy_priv(wiphy);
1299 struct net_device *ndev;
1300 u8 if_idx, nw_type;
1301
1302 if (ar->num_vif == MAX_NUM_VIF) {
1303 ath6kl_err("Reached maximum number of supported vif\n");
1304 return ERR_PTR(-EINVAL);
1305 }
1306
1307 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1308 ath6kl_err("Not a supported interface type\n");
1309 return ERR_PTR(-EINVAL);
1310 }
1311
1312 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1313 if (!ndev)
1314 return ERR_PTR(-ENOMEM);
1315
1316 ar->num_vif++;
1317
1318 return ndev;
1319}
1320
1321static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1322 struct net_device *ndev)
1323{
1324 struct ath6kl *ar = wiphy_priv(wiphy);
1325 struct ath6kl_vif *vif = netdev_priv(ndev);
1326
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301327 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301328 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301329 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301330
1331 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1332
1333 ath6kl_deinit_if_data(vif);
1334
1335 return 0;
1336}
1337
Kalle Valobdcd8172011-07-18 00:22:30 +03001338static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1339 struct net_device *ndev,
1340 enum nl80211_iftype type, u32 *flags,
1341 struct vif_params *params)
1342{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301343 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001344
1345 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1346
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301347 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001348 return -EIO;
1349
1350 switch (type) {
1351 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301352 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001353 break;
1354 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301355 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001356 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001357 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301358 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001359 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001360 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301361 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001362 break;
1363 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301364 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001365 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001366 default:
1367 ath6kl_err("invalid interface type %u\n", type);
1368 return -EOPNOTSUPP;
1369 }
1370
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301371 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001372
1373 return 0;
1374}
1375
1376static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1377 struct net_device *dev,
1378 struct cfg80211_ibss_params *ibss_param)
1379{
1380 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301381 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001382 int status;
1383
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301384 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001385 return -EIO;
1386
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301387 vif->ssid_len = ibss_param->ssid_len;
1388 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001389
1390 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301391 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001392
1393 if (ibss_param->channel_fixed) {
1394 /*
1395 * TODO: channel_fixed: The channel should be fixed, do not
1396 * search for IBSSs to join on other channels. Target
1397 * firmware does not support this feature, needs to be
1398 * updated.
1399 */
1400 return -EOPNOTSUPP;
1401 }
1402
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301403 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001404 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301405 memcpy(vif->req_bssid, ibss_param->bssid,
1406 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001407
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301408 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001409
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301410 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001411 if (status)
1412 return status;
1413
1414 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301415 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1416 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001417 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301418 ath6kl_set_cipher(vif, 0, true);
1419 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001420 }
1421
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301422 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001423
1424 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1425 "%s: connect called with authmode %d dot11 auth %d"
1426 " PW crypto %d PW crypto len %d GRP crypto %d"
1427 " GRP crypto len %d channel hint %u\n",
1428 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301429 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1430 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301431 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001432
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301433 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301434 vif->dot11_auth_mode, vif->auth_mode,
1435 vif->prwise_crypto,
1436 vif->prwise_crypto_len,
1437 vif->grp_crypto, vif->grp_crypto_len,
1438 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301439 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001440 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301441 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001442
1443 return 0;
1444}
1445
1446static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1447 struct net_device *dev)
1448{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301449 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001450
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301451 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001452 return -EIO;
1453
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301454 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301455 memset(vif->ssid, 0, sizeof(vif->ssid));
1456 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001457
1458 return 0;
1459}
1460
1461static const u32 cipher_suites[] = {
1462 WLAN_CIPHER_SUITE_WEP40,
1463 WLAN_CIPHER_SUITE_WEP104,
1464 WLAN_CIPHER_SUITE_TKIP,
1465 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001466 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001467 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001468};
1469
1470static bool is_rate_legacy(s32 rate)
1471{
1472 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1473 6000, 9000, 12000, 18000, 24000,
1474 36000, 48000, 54000
1475 };
1476 u8 i;
1477
1478 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1479 if (rate == legacy[i])
1480 return true;
1481
1482 return false;
1483}
1484
1485static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1486{
1487 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1488 52000, 58500, 65000, 72200
1489 };
1490 u8 i;
1491
1492 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1493 if (rate == ht20[i]) {
1494 if (i == ARRAY_SIZE(ht20) - 1)
1495 /* last rate uses sgi */
1496 *sgi = true;
1497 else
1498 *sgi = false;
1499
1500 *mcs = i;
1501 return true;
1502 }
1503 }
1504 return false;
1505}
1506
1507static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1508{
1509 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1510 81000, 108000, 121500, 135000,
1511 150000
1512 };
1513 u8 i;
1514
1515 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1516 if (rate == ht40[i]) {
1517 if (i == ARRAY_SIZE(ht40) - 1)
1518 /* last rate uses sgi */
1519 *sgi = true;
1520 else
1521 *sgi = false;
1522
1523 *mcs = i;
1524 return true;
1525 }
1526 }
1527
1528 return false;
1529}
1530
1531static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1532 u8 *mac, struct station_info *sinfo)
1533{
1534 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301535 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001536 long left;
1537 bool sgi;
1538 s32 rate;
1539 int ret;
1540 u8 mcs;
1541
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301542 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001543 return -ENOENT;
1544
1545 if (down_interruptible(&ar->sem))
1546 return -EBUSY;
1547
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301548 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001549
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301550 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001551
1552 if (ret != 0) {
1553 up(&ar->sem);
1554 return -EIO;
1555 }
1556
1557 left = wait_event_interruptible_timeout(ar->event_wq,
1558 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301559 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001560 WMI_TIMEOUT);
1561
1562 up(&ar->sem);
1563
1564 if (left == 0)
1565 return -ETIMEDOUT;
1566 else if (left < 0)
1567 return left;
1568
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301569 if (vif->target_stats.rx_byte) {
1570 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001571 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301572 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001573 sinfo->filled |= STATION_INFO_RX_PACKETS;
1574 }
1575
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301576 if (vif->target_stats.tx_byte) {
1577 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001578 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301579 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001580 sinfo->filled |= STATION_INFO_TX_PACKETS;
1581 }
1582
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301583 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001584 sinfo->filled |= STATION_INFO_SIGNAL;
1585
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301586 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001587
1588 if (is_rate_legacy(rate)) {
1589 sinfo->txrate.legacy = rate / 100;
1590 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1591 if (sgi) {
1592 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1593 sinfo->txrate.mcs = mcs - 1;
1594 } else {
1595 sinfo->txrate.mcs = mcs;
1596 }
1597
1598 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1599 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1600 if (sgi) {
1601 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1602 sinfo->txrate.mcs = mcs - 1;
1603 } else {
1604 sinfo->txrate.mcs = mcs;
1605 }
1606
1607 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1608 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1609 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001610 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1611 "invalid rate from stats: %d\n", rate);
1612 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001613 return 0;
1614 }
1615
1616 sinfo->filled |= STATION_INFO_TX_BITRATE;
1617
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301618 if (test_bit(CONNECTED, &vif->flags) &&
1619 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301620 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001621 sinfo->filled |= STATION_INFO_BSS_PARAM;
1622 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301623 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1624 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001625 }
1626
Kalle Valobdcd8172011-07-18 00:22:30 +03001627 return 0;
1628}
1629
1630static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1631 struct cfg80211_pmksa *pmksa)
1632{
1633 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301634 struct ath6kl_vif *vif = netdev_priv(netdev);
1635
1636 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001637 pmksa->pmkid, true);
1638}
1639
1640static int ath6kl_del_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, false);
1648}
1649
1650static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1651{
1652 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301653 struct ath6kl_vif *vif = netdev_priv(netdev);
1654
1655 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301656 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1657 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001658 return 0;
1659}
1660
Raja Mani6cb3c712011-11-07 22:52:45 +02001661static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1662{
1663 struct ath6kl_vif *vif;
1664 int ret, pos, left;
1665 u32 filter = 0;
1666 u16 i;
1667 u8 mask[WOW_MASK_SIZE];
1668
1669 vif = ath6kl_vif_first(ar);
1670 if (!vif)
1671 return -EIO;
1672
1673 if (!ath6kl_cfg80211_ready(vif))
1674 return -EIO;
1675
1676 if (!test_bit(CONNECTED, &vif->flags))
1677 return -EINVAL;
1678
1679 /* Clear existing WOW patterns */
1680 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1681 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1682 WOW_LIST_ID, i);
1683 /* Configure new WOW patterns */
1684 for (i = 0; i < wow->n_patterns; i++) {
1685
1686 /*
1687 * Convert given nl80211 specific mask value to equivalent
1688 * driver specific mask value and send it to the chip along
1689 * with patterns. For example, If the mask value defined in
1690 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1691 * then equivalent driver specific mask value is
1692 * "0xFF 0x00 0xFF 0x00".
1693 */
1694 memset(&mask, 0, sizeof(mask));
1695 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1696 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1697 mask[pos] = 0xFF;
1698 }
1699 /*
1700 * Note: Pattern's offset is not passed as part of wowlan
1701 * parameter from CFG layer. So it's always passed as ZERO
1702 * to the firmware. It means, given WOW patterns are always
1703 * matched from the first byte of received pkt in the firmware.
1704 */
1705 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1706 vif->fw_vif_idx, WOW_LIST_ID,
1707 wow->patterns[i].pattern_len,
1708 0 /* pattern offset */,
1709 wow->patterns[i].pattern, mask);
1710 if (ret)
1711 return ret;
1712 }
1713
1714 if (wow->disconnect)
1715 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1716
1717 if (wow->magic_pkt)
1718 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1719
1720 if (wow->gtk_rekey_failure)
1721 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1722
1723 if (wow->eap_identity_req)
1724 filter |= WOW_FILTER_OPTION_EAP_REQ;
1725
1726 if (wow->four_way_handshake)
1727 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1728
1729 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1730 ATH6KL_WOW_MODE_ENABLE,
1731 filter,
1732 WOW_HOST_REQ_DELAY);
1733 if (ret)
1734 return ret;
1735
1736 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1737 ATH6KL_HOST_MODE_ASLEEP);
1738 if (ret)
1739 return ret;
1740
1741 if (ar->tx_pending[ar->ctrl_ep]) {
1742 left = wait_event_interruptible_timeout(ar->event_wq,
1743 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1744 if (left == 0) {
1745 ath6kl_warn("clear wmi ctrl data timeout\n");
1746 ret = -ETIMEDOUT;
1747 } else if (left < 0) {
1748 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1749 ret = left;
1750 }
1751 }
1752
1753 return ret;
1754}
1755
1756static int ath6kl_wow_resume(struct ath6kl *ar)
1757{
1758 struct ath6kl_vif *vif;
1759 int ret;
1760
1761 vif = ath6kl_vif_first(ar);
1762 if (!vif)
1763 return -EIO;
1764
1765 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1766 ATH6KL_HOST_MODE_AWAKE);
1767 return ret;
1768}
1769
Kalle Valo52d81a62011-11-01 08:44:21 +02001770int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001771 enum ath6kl_cfg_suspend_mode mode,
1772 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001773{
1774 int ret;
1775
Kalle Valo52d81a62011-11-01 08:44:21 +02001776 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001777 case ATH6KL_CFG_SUSPEND_WOW:
1778
1779 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1780
1781 /* Flush all non control pkts in TX path */
1782 ath6kl_tx_data_cleanup(ar);
1783
1784 ret = ath6kl_wow_suspend(ar, wow);
1785 if (ret) {
1786 ath6kl_err("wow suspend failed: %d\n", ret);
1787 return ret;
1788 }
1789 ar->state = ATH6KL_STATE_WOW;
1790 break;
1791
Kalle Valo52d81a62011-11-01 08:44:21 +02001792 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001793
1794 ath6kl_cfg80211_stop(ar);
1795
Kalle Valo52d81a62011-11-01 08:44:21 +02001796 /* save the current power mode before enabling power save */
1797 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1798
1799 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1800 if (ret) {
1801 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1802 ret);
1803 }
1804
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001805 ar->state = ATH6KL_STATE_DEEPSLEEP;
1806
Kalle Valo52d81a62011-11-01 08:44:21 +02001807 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001808
1809 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001810
1811 ath6kl_cfg80211_stop(ar);
1812
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001813 if (ar->state == ATH6KL_STATE_OFF) {
1814 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1815 "suspend hw off, no action for cutpower\n");
1816 break;
1817 }
1818
1819 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1820
1821 ret = ath6kl_init_hw_stop(ar);
1822 if (ret) {
1823 ath6kl_warn("failed to stop hw during suspend: %d\n",
1824 ret);
1825 }
1826
1827 ar->state = ATH6KL_STATE_CUTPOWER;
1828
1829 break;
1830
1831 default:
1832 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001833 }
1834
1835 return 0;
1836}
1837
1838int ath6kl_cfg80211_resume(struct ath6kl *ar)
1839{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001840 int ret;
1841
1842 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001843 case ATH6KL_STATE_WOW:
1844 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1845
1846 ret = ath6kl_wow_resume(ar);
1847 if (ret) {
1848 ath6kl_warn("wow mode resume failed: %d\n", ret);
1849 return ret;
1850 }
1851
1852 ar->state = ATH6KL_STATE_ON;
1853 break;
1854
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001855 case ATH6KL_STATE_DEEPSLEEP:
1856 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1857 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1858 ar->wmi->saved_pwr_mode);
1859 if (ret) {
1860 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1861 ret);
1862 }
1863 }
1864
1865 ar->state = ATH6KL_STATE_ON;
1866
1867 break;
1868
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001869 case ATH6KL_STATE_CUTPOWER:
1870 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1871
1872 ret = ath6kl_init_hw_start(ar);
1873 if (ret) {
1874 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1875 return ret;
1876 }
Raja Manid7c44e02011-11-07 22:52:46 +02001877 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001878
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001879 default:
1880 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001881 }
1882
1883 return 0;
1884}
1885
Kalle Valoabcb3442011-07-22 08:26:20 +03001886#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001887
1888/* hif layer decides what suspend mode to use */
1889static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001890 struct cfg80211_wowlan *wow)
1891{
1892 struct ath6kl *ar = wiphy_priv(wiphy);
1893
Raja Mani0f60e9f2011-11-07 22:52:45 +02001894 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001895}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001896
Kalle Valo52d81a62011-11-01 08:44:21 +02001897static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001898{
1899 struct ath6kl *ar = wiphy_priv(wiphy);
1900
1901 return ath6kl_hif_resume(ar);
1902}
Raja Mania918fb32011-11-07 22:52:46 +02001903
1904/*
1905 * FIXME: WOW suspend mode is selected if the host sdio controller supports
1906 * both sdio irq wake up and keep power. The target pulls sdio data line to
1907 * wake up the host when WOW pattern matches. This causes sdio irq handler
1908 * is being called in the host side which internally hits ath6kl's RX path.
1909 *
1910 * Since sdio interrupt is not disabled, RX path executes even before
1911 * the host executes the actual resume operation from PM module.
1912 *
1913 * In the current scenario, WOW resume should happen before start processing
1914 * any data from the target. So It's required to perform WOW resume in RX path.
1915 * Ideally we should perform WOW resume only in the actual platform
1916 * resume path. This area needs bit rework to avoid WOW resume in RX path.
1917 *
1918 * ath6kl_check_wow_status() is called from ath6kl_rx().
1919 */
1920void ath6kl_check_wow_status(struct ath6kl *ar)
1921{
1922 if (ar->state == ATH6KL_STATE_WOW)
1923 ath6kl_cfg80211_resume(ar);
1924}
1925
1926#else
1927
1928void ath6kl_check_wow_status(struct ath6kl *ar)
1929{
1930}
Kalle Valoabcb3442011-07-22 08:26:20 +03001931#endif
1932
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001933static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1934 struct ieee80211_channel *chan,
1935 enum nl80211_channel_type channel_type)
1936{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301937 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001938
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301939 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001940 return -EIO;
1941
1942 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1943 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301944 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001945
1946 return 0;
1947}
1948
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001949static bool ath6kl_is_p2p_ie(const u8 *pos)
1950{
1951 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1952 pos[2] == 0x50 && pos[3] == 0x6f &&
1953 pos[4] == 0x9a && pos[5] == 0x09;
1954}
1955
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301956static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1957 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001958{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301959 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001960 const u8 *pos;
1961 u8 *buf = NULL;
1962 size_t len = 0;
1963 int ret;
1964
1965 /*
1966 * Filter out P2P IE(s) since they will be included depending on
1967 * the Probe Request frame in ath6kl_send_go_probe_resp().
1968 */
1969
1970 if (ies && ies_len) {
1971 buf = kmalloc(ies_len, GFP_KERNEL);
1972 if (buf == NULL)
1973 return -ENOMEM;
1974 pos = ies;
1975 while (pos + 1 < ies + ies_len) {
1976 if (pos + 2 + pos[1] > ies + ies_len)
1977 break;
1978 if (!ath6kl_is_p2p_ie(pos)) {
1979 memcpy(buf + len, pos, 2 + pos[1]);
1980 len += 2 + pos[1];
1981 }
1982 pos += 2 + pos[1];
1983 }
1984 }
1985
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301986 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1987 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001988 kfree(buf);
1989 return ret;
1990}
1991
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001992static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1993 struct beacon_parameters *info, bool add)
1994{
1995 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301996 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001997 struct ieee80211_mgmt *mgmt;
1998 u8 *ies;
1999 int ies_len;
2000 struct wmi_connect_cmd p;
2001 int res;
2002 int i;
2003
2004 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2005
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302006 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002007 return -EIO;
2008
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302009 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002010 return -EOPNOTSUPP;
2011
2012 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302013 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2014 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002015 info->beacon_ies,
2016 info->beacon_ies_len);
2017 if (res)
2018 return res;
2019 }
2020 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302021 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002022 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002023 if (res)
2024 return res;
2025 }
2026 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302027 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2028 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002029 info->assocresp_ies,
2030 info->assocresp_ies_len);
2031 if (res)
2032 return res;
2033 }
2034
2035 if (!add)
2036 return 0;
2037
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002038 ar->ap_mode_bkey.valid = false;
2039
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002040 /* TODO:
2041 * info->interval
2042 * info->dtim_period
2043 */
2044
2045 if (info->head == NULL)
2046 return -EINVAL;
2047 mgmt = (struct ieee80211_mgmt *) info->head;
2048 ies = mgmt->u.beacon.variable;
2049 if (ies > info->head + info->head_len)
2050 return -EINVAL;
2051 ies_len = info->head + info->head_len - ies;
2052
2053 if (info->ssid == NULL)
2054 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302055 memcpy(vif->ssid, info->ssid, info->ssid_len);
2056 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002057 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2058 return -EOPNOTSUPP; /* TODO */
2059
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302060 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002061
2062 memset(&p, 0, sizeof(p));
2063
2064 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2065 switch (info->crypto.akm_suites[i]) {
2066 case WLAN_AKM_SUITE_8021X:
2067 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2068 p.auth_mode |= WPA_AUTH;
2069 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2070 p.auth_mode |= WPA2_AUTH;
2071 break;
2072 case WLAN_AKM_SUITE_PSK:
2073 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2074 p.auth_mode |= WPA_PSK_AUTH;
2075 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2076 p.auth_mode |= WPA2_PSK_AUTH;
2077 break;
2078 }
2079 }
2080 if (p.auth_mode == 0)
2081 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302082 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002083
2084 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2085 switch (info->crypto.ciphers_pairwise[i]) {
2086 case WLAN_CIPHER_SUITE_WEP40:
2087 case WLAN_CIPHER_SUITE_WEP104:
2088 p.prwise_crypto_type |= WEP_CRYPT;
2089 break;
2090 case WLAN_CIPHER_SUITE_TKIP:
2091 p.prwise_crypto_type |= TKIP_CRYPT;
2092 break;
2093 case WLAN_CIPHER_SUITE_CCMP:
2094 p.prwise_crypto_type |= AES_CRYPT;
2095 break;
2096 }
2097 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002098 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002099 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302100 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002101 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302102 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002103
2104 switch (info->crypto.cipher_group) {
2105 case WLAN_CIPHER_SUITE_WEP40:
2106 case WLAN_CIPHER_SUITE_WEP104:
2107 p.grp_crypto_type = WEP_CRYPT;
2108 break;
2109 case WLAN_CIPHER_SUITE_TKIP:
2110 p.grp_crypto_type = TKIP_CRYPT;
2111 break;
2112 case WLAN_CIPHER_SUITE_CCMP:
2113 p.grp_crypto_type = AES_CRYPT;
2114 break;
2115 default:
2116 p.grp_crypto_type = NONE_CRYPT;
2117 break;
2118 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302119 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002120
2121 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302122 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002123
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302124 p.ssid_len = vif->ssid_len;
2125 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2126 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302127 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002128
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302129 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002130 if (res < 0)
2131 return res;
2132
2133 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002134}
2135
2136static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2137 struct beacon_parameters *info)
2138{
2139 return ath6kl_ap_beacon(wiphy, dev, info, true);
2140}
2141
2142static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2143 struct beacon_parameters *info)
2144{
2145 return ath6kl_ap_beacon(wiphy, dev, info, false);
2146}
2147
2148static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2149{
2150 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302151 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002152
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302153 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002154 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302155 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002156 return -ENOTCONN;
2157
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302158 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302159 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002160
2161 return 0;
2162}
2163
Jouni Malinen23875132011-08-30 21:57:53 +03002164static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2165 u8 *mac, struct station_parameters *params)
2166{
2167 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302168 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002169
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302170 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002171 return -EOPNOTSUPP;
2172
2173 /* Use this only for authorizing/unauthorizing a station */
2174 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2175 return -EOPNOTSUPP;
2176
2177 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302178 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2179 WMI_AP_MLME_AUTHORIZE, mac, 0);
2180 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2181 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002182}
2183
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002184static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2185 struct net_device *dev,
2186 struct ieee80211_channel *chan,
2187 enum nl80211_channel_type channel_type,
2188 unsigned int duration,
2189 u64 *cookie)
2190{
2191 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302192 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002193 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002194
2195 /* TODO: if already pending or ongoing remain-on-channel,
2196 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002197 id = ++vif->last_roc_id;
2198 if (id == 0) {
2199 /* Do not use 0 as the cookie value */
2200 id = ++vif->last_roc_id;
2201 }
2202 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002203
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302204 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2205 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002206}
2207
2208static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2209 struct net_device *dev,
2210 u64 cookie)
2211{
2212 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302213 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002214
Jouni Malinen10522612011-10-27 16:00:13 +03002215 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002216 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002217 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002218
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302219 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002220}
2221
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302222static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2223 const u8 *buf, size_t len,
2224 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002225{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302226 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002227 const u8 *pos;
2228 u8 *p2p;
2229 int p2p_len;
2230 int ret;
2231 const struct ieee80211_mgmt *mgmt;
2232
2233 mgmt = (const struct ieee80211_mgmt *) buf;
2234
2235 /* Include P2P IE(s) from the frame generated in user space. */
2236
2237 p2p = kmalloc(len, GFP_KERNEL);
2238 if (p2p == NULL)
2239 return -ENOMEM;
2240 p2p_len = 0;
2241
2242 pos = mgmt->u.probe_resp.variable;
2243 while (pos + 1 < buf + len) {
2244 if (pos + 2 + pos[1] > buf + len)
2245 break;
2246 if (ath6kl_is_p2p_ie(pos)) {
2247 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2248 p2p_len += 2 + pos[1];
2249 }
2250 pos += 2 + pos[1];
2251 }
2252
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302253 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2254 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002255 kfree(p2p);
2256 return ret;
2257}
2258
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002259static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2260 struct ieee80211_channel *chan, bool offchan,
2261 enum nl80211_channel_type channel_type,
2262 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002263 const u8 *buf, size_t len, bool no_cck,
2264 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002265{
2266 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302267 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002268 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002269 const struct ieee80211_mgmt *mgmt;
2270
2271 mgmt = (const struct ieee80211_mgmt *) buf;
2272 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302273 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002274 ieee80211_is_probe_resp(mgmt->frame_control)) {
2275 /*
2276 * Send Probe Response frame in AP mode using a separate WMI
2277 * command to allow the target to fill in the generic IEs.
2278 */
2279 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302280 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002281 chan->center_freq);
2282 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002283
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302284 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002285 if (id == 0) {
2286 /*
2287 * 0 is a reserved value in the WMI command and shall not be
2288 * used for the command.
2289 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302290 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002291 }
2292
2293 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302294 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2295 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002296 buf, len);
2297}
2298
Jouni Malinenae32c302011-08-30 21:58:01 +03002299static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2300 struct net_device *dev,
2301 u16 frame_type, bool reg)
2302{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302303 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002304
2305 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2306 __func__, frame_type, reg);
2307 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2308 /*
2309 * Note: This notification callback is not allowed to sleep, so
2310 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2311 * hardcode target to report Probe Request frames all the time.
2312 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302313 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002314 }
2315}
2316
Jouni Malinenf80574a2011-08-30 21:58:04 +03002317static const struct ieee80211_txrx_stypes
2318ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2319 [NL80211_IFTYPE_STATION] = {
2320 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2321 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2322 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2323 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2324 },
2325 [NL80211_IFTYPE_P2P_CLIENT] = {
2326 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2327 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2328 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2329 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2330 },
2331 [NL80211_IFTYPE_P2P_GO] = {
2332 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2333 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2334 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2335 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2336 },
2337};
2338
Kalle Valobdcd8172011-07-18 00:22:30 +03002339static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302340 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2341 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002342 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2343 .scan = ath6kl_cfg80211_scan,
2344 .connect = ath6kl_cfg80211_connect,
2345 .disconnect = ath6kl_cfg80211_disconnect,
2346 .add_key = ath6kl_cfg80211_add_key,
2347 .get_key = ath6kl_cfg80211_get_key,
2348 .del_key = ath6kl_cfg80211_del_key,
2349 .set_default_key = ath6kl_cfg80211_set_default_key,
2350 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2351 .set_tx_power = ath6kl_cfg80211_set_txpower,
2352 .get_tx_power = ath6kl_cfg80211_get_txpower,
2353 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2354 .join_ibss = ath6kl_cfg80211_join_ibss,
2355 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2356 .get_station = ath6kl_get_station,
2357 .set_pmksa = ath6kl_set_pmksa,
2358 .del_pmksa = ath6kl_del_pmksa,
2359 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002360 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002361#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002362 .suspend = __ath6kl_cfg80211_suspend,
2363 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002364#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002365 .set_channel = ath6kl_set_channel,
2366 .add_beacon = ath6kl_add_beacon,
2367 .set_beacon = ath6kl_set_beacon,
2368 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002369 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002370 .remain_on_channel = ath6kl_remain_on_channel,
2371 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002372 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002373 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002374};
2375
Kalle Valoec4b7f62011-11-01 08:44:04 +02002376void ath6kl_cfg80211_stop(struct ath6kl *ar)
2377{
2378 struct ath6kl_vif *vif;
2379
2380 /* FIXME: for multi vif */
2381 vif = ath6kl_vif_first(ar);
2382 if (!vif) {
2383 /* save the current power mode before enabling power save */
2384 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2385
2386 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2387 ath6kl_warn("ath6kl_deep_sleep_enable: "
2388 "wmi_powermode_cmd failed\n");
2389 return;
2390 }
2391
2392 switch (vif->sme_state) {
2393 case SME_CONNECTING:
2394 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2395 NULL, 0,
2396 WLAN_STATUS_UNSPECIFIED_FAILURE,
2397 GFP_KERNEL);
2398 break;
2399 case SME_CONNECTED:
2400 default:
2401 /*
2402 * FIXME: oddly enough smeState is in DISCONNECTED during
2403 * suspend, why? Need to send disconnected event in that
2404 * state.
2405 */
2406 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2407 break;
2408 }
2409
2410 if (test_bit(CONNECTED, &vif->flags) ||
2411 test_bit(CONNECT_PEND, &vif->flags))
2412 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2413
2414 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002415 clear_bit(CONNECTED, &vif->flags);
2416 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002417
2418 /* disable scanning */
2419 if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
2420 0, 0, 0, 0, 0, 0, 0) != 0)
2421 printk(KERN_WARNING "ath6kl: failed to disable scan "
2422 "during suspend\n");
2423
2424 ath6kl_cfg80211_scan_complete_event(vif, true);
2425}
2426
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302427struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002428{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002429 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302430 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302431 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002432
2433 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302434 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302435
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302436 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002437 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002438 return NULL;
2439 }
2440
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302441 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302442 if (!multi_norm_if_support)
2443 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302444 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302445 ar->dev = dev;
2446
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302447 if (multi_norm_if_support)
2448 ar->max_norm_iface = 2;
2449 else
2450 ar->max_norm_iface = 1;
2451
2452 /* FIXME: Remove this once the multivif support is enabled */
2453 ar->max_norm_iface = 1;
2454
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302455 spin_lock_init(&ar->lock);
2456 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302457 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302458
2459 init_waitqueue_head(&ar->event_wq);
2460 sema_init(&ar->sem, 1);
2461
2462 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302463 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302464
2465 clear_bit(WMI_ENABLED, &ar->flag);
2466 clear_bit(SKIP_SCAN, &ar->flag);
2467 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2468
2469 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2470 ar->listen_intvl_b = 0;
2471 ar->tx_pwr = 0;
2472
2473 ar->intra_bss = 1;
2474 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2475 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2476 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2477 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2478
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002479 ar->state = ATH6KL_STATE_OFF;
2480
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302481 memset((u8 *)ar->sta_list, 0,
2482 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2483
2484 /* Init the PS queues */
2485 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2486 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2487 skb_queue_head_init(&ar->sta_list[ctr].psq);
2488 }
2489
2490 skb_queue_head_init(&ar->mcastpsq);
2491
2492 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2493
2494 return ar;
2495}
2496
2497int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2498{
2499 struct wiphy *wiphy = ar->wiphy;
2500 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002501
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302502 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002503
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302504 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002505
Kalle Valobdcd8172011-07-18 00:22:30 +03002506 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302507 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002508
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302509 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302510 BIT(NL80211_IFTYPE_ADHOC) |
2511 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002512 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302513 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302514 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002515 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302516
Kalle Valobdcd8172011-07-18 00:22:30 +03002517 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302518 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2519 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2520 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2521 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2522 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002523
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302524 wiphy->cipher_suites = cipher_suites;
2525 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002526
Raja Manieae9e062011-11-07 22:52:46 +02002527 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2528 WIPHY_WOWLAN_DISCONNECT |
2529 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2530 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2531 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2532 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2533 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2534 wiphy->wowlan.pattern_min_len = 1;
2535 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2536
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302537 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002538 if (ret < 0) {
2539 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302540 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002541 }
2542
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302543 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002544}
2545
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302546static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002547{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302548 vif->aggr_cntxt = aggr_init(vif->ndev);
2549 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302550 ath6kl_err("failed to initialize aggr\n");
2551 return -ENOMEM;
2552 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002553
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302554 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302555 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302556 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302557 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302558
2559 return 0;
2560}
2561
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302562void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302563{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302564 struct ath6kl *ar = vif->ar;
2565
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302566 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302567
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302568 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2569
2570 if (vif->nw_type == ADHOC_NETWORK)
2571 ar->ibss_if_active = false;
2572
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302573 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302574
2575 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302576}
2577
2578struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302579 enum nl80211_iftype type, u8 fw_vif_idx,
2580 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302581{
2582 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302583 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302584
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302585 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302586 if (!ndev)
2587 return NULL;
2588
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302589 vif = netdev_priv(ndev);
2590 ndev->ieee80211_ptr = &vif->wdev;
2591 vif->wdev.wiphy = ar->wiphy;
2592 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302593 vif->ndev = ndev;
2594 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2595 vif->wdev.netdev = ndev;
2596 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302597 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302598 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302599
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302600 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2601 if (fw_vif_idx != 0)
2602 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2603 0x2;
2604
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302605 init_netdev(ndev);
2606
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302607 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302608
2609 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302610 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302611 goto err;
2612
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302613 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302614 goto err;
2615
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302616 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302617 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302618 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302619 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302620 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302621
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302622 if (type == NL80211_IFTYPE_ADHOC)
2623 ar->ibss_if_active = true;
2624
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302625 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302626 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302627 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302628
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302629 return ndev;
2630
2631err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302632 aggr_module_destroy(vif->aggr_cntxt);
2633 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302634 return NULL;
2635}
2636
2637void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2638{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302639 wiphy_unregister(ar->wiphy);
2640 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002641}