blob: 01bb9ede471b3e8a88d01cad08108e5eb5bd2be3 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053024static unsigned int multi_norm_if_support;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030025
26module_param(ath6kl_p2p, uint, 0644);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053027module_param(multi_norm_if_support, uint, 0644);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030028
Kalle Valobdcd8172011-07-18 00:22:30 +030029#define RATETAB_ENT(_rate, _rateid, _flags) { \
30 .bitrate = (_rate), \
31 .flags = (_flags), \
32 .hw_value = (_rateid), \
33}
34
35#define CHAN2G(_channel, _freq, _flags) { \
36 .band = IEEE80211_BAND_2GHZ, \
37 .hw_value = (_channel), \
38 .center_freq = (_freq), \
39 .flags = (_flags), \
40 .max_antenna_gain = 0, \
41 .max_power = 30, \
42}
43
44#define CHAN5G(_channel, _flags) { \
45 .band = IEEE80211_BAND_5GHZ, \
46 .hw_value = (_channel), \
47 .center_freq = 5000 + (5 * (_channel)), \
48 .flags = (_flags), \
49 .max_antenna_gain = 0, \
50 .max_power = 30, \
51}
52
53static struct ieee80211_rate ath6kl_rates[] = {
54 RATETAB_ENT(10, 0x1, 0),
55 RATETAB_ENT(20, 0x2, 0),
56 RATETAB_ENT(55, 0x4, 0),
57 RATETAB_ENT(110, 0x8, 0),
58 RATETAB_ENT(60, 0x10, 0),
59 RATETAB_ENT(90, 0x20, 0),
60 RATETAB_ENT(120, 0x40, 0),
61 RATETAB_ENT(180, 0x80, 0),
62 RATETAB_ENT(240, 0x100, 0),
63 RATETAB_ENT(360, 0x200, 0),
64 RATETAB_ENT(480, 0x400, 0),
65 RATETAB_ENT(540, 0x800, 0),
66};
67
68#define ath6kl_a_rates (ath6kl_rates + 4)
69#define ath6kl_a_rates_size 8
70#define ath6kl_g_rates (ath6kl_rates + 0)
71#define ath6kl_g_rates_size 12
72
73static struct ieee80211_channel ath6kl_2ghz_channels[] = {
74 CHAN2G(1, 2412, 0),
75 CHAN2G(2, 2417, 0),
76 CHAN2G(3, 2422, 0),
77 CHAN2G(4, 2427, 0),
78 CHAN2G(5, 2432, 0),
79 CHAN2G(6, 2437, 0),
80 CHAN2G(7, 2442, 0),
81 CHAN2G(8, 2447, 0),
82 CHAN2G(9, 2452, 0),
83 CHAN2G(10, 2457, 0),
84 CHAN2G(11, 2462, 0),
85 CHAN2G(12, 2467, 0),
86 CHAN2G(13, 2472, 0),
87 CHAN2G(14, 2484, 0),
88};
89
90static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
91 CHAN5G(34, 0), CHAN5G(36, 0),
92 CHAN5G(38, 0), CHAN5G(40, 0),
93 CHAN5G(42, 0), CHAN5G(44, 0),
94 CHAN5G(46, 0), CHAN5G(48, 0),
95 CHAN5G(52, 0), CHAN5G(56, 0),
96 CHAN5G(60, 0), CHAN5G(64, 0),
97 CHAN5G(100, 0), CHAN5G(104, 0),
98 CHAN5G(108, 0), CHAN5G(112, 0),
99 CHAN5G(116, 0), CHAN5G(120, 0),
100 CHAN5G(124, 0), CHAN5G(128, 0),
101 CHAN5G(132, 0), CHAN5G(136, 0),
102 CHAN5G(140, 0), CHAN5G(149, 0),
103 CHAN5G(153, 0), CHAN5G(157, 0),
104 CHAN5G(161, 0), CHAN5G(165, 0),
105 CHAN5G(184, 0), CHAN5G(188, 0),
106 CHAN5G(192, 0), CHAN5G(196, 0),
107 CHAN5G(200, 0), CHAN5G(204, 0),
108 CHAN5G(208, 0), CHAN5G(212, 0),
109 CHAN5G(216, 0),
110};
111
112static struct ieee80211_supported_band ath6kl_band_2ghz = {
113 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
114 .channels = ath6kl_2ghz_channels,
115 .n_bitrates = ath6kl_g_rates_size,
116 .bitrates = ath6kl_g_rates,
117};
118
119static struct ieee80211_supported_band ath6kl_band_5ghz = {
120 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
121 .channels = ath6kl_5ghz_a_channels,
122 .n_bitrates = ath6kl_a_rates_size,
123 .bitrates = ath6kl_a_rates,
124};
125
Jouni Malinen837cb972011-10-11 17:31:57 +0300126#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
127
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530128static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300129 enum nl80211_wpa_versions wpa_version)
130{
131 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
132
133 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530134 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300135 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530136 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300137 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530138 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300139 } else {
140 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
141 return -ENOTSUPP;
142 }
143
144 return 0;
145}
146
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530147static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300148 enum nl80211_auth_type auth_type)
149{
Kalle Valobdcd8172011-07-18 00:22:30 +0300150 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
151
152 switch (auth_type) {
153 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530154 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300155 break;
156 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530157 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300158 break;
159 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530160 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300161 break;
162
163 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530164 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 break;
166
167 default:
168 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
169 return -ENOTSUPP;
170 }
171
172 return 0;
173}
174
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530175static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300176{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530177 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
178 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
179 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300180
181 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
182 __func__, cipher, ucast);
183
184 switch (cipher) {
185 case 0:
186 /* our own hack to use value 0 as no crypto used */
187 *ar_cipher = NONE_CRYPT;
188 *ar_cipher_len = 0;
189 break;
190 case WLAN_CIPHER_SUITE_WEP40:
191 *ar_cipher = WEP_CRYPT;
192 *ar_cipher_len = 5;
193 break;
194 case WLAN_CIPHER_SUITE_WEP104:
195 *ar_cipher = WEP_CRYPT;
196 *ar_cipher_len = 13;
197 break;
198 case WLAN_CIPHER_SUITE_TKIP:
199 *ar_cipher = TKIP_CRYPT;
200 *ar_cipher_len = 0;
201 break;
202 case WLAN_CIPHER_SUITE_CCMP:
203 *ar_cipher = AES_CRYPT;
204 *ar_cipher_len = 0;
205 break;
206 default:
207 ath6kl_err("cipher 0x%x not supported\n", cipher);
208 return -ENOTSUPP;
209 }
210
211 return 0;
212}
213
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530214static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300215{
216 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
217
218 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530219 if (vif->auth_mode == WPA_AUTH)
220 vif->auth_mode = WPA_PSK_AUTH;
221 else if (vif->auth_mode == WPA2_AUTH)
222 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300223 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530224 if (vif->auth_mode == WPA_AUTH)
225 vif->auth_mode = WPA_AUTH_CCKM;
226 else if (vif->auth_mode == WPA2_AUTH)
227 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300228 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530229 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300230 }
231}
232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530233static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300234{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530235 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530236
Kalle Valobdcd8172011-07-18 00:22:30 +0300237 if (!test_bit(WMI_READY, &ar->flag)) {
238 ath6kl_err("wmi is not ready\n");
239 return false;
240 }
241
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530242 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300243 ath6kl_err("wlan disabled\n");
244 return false;
245 }
246
247 return true;
248}
249
Kevin Fang6981ffd2011-10-07 08:51:19 +0800250static bool ath6kl_is_wpa_ie(const u8 *pos)
251{
252 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
253 pos[2] == 0x00 && pos[3] == 0x50 &&
254 pos[4] == 0xf2 && pos[5] == 0x01;
255}
256
257static bool ath6kl_is_rsn_ie(const u8 *pos)
258{
259 return pos[0] == WLAN_EID_RSN;
260}
261
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700262static bool ath6kl_is_wps_ie(const u8 *pos)
263{
264 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
265 pos[1] >= 4 &&
266 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
267 pos[5] == 0x04);
268}
269
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530270static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
271 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800272{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530273 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800274 const u8 *pos;
275 u8 *buf = NULL;
276 size_t len = 0;
277 int ret;
278
279 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700280 * Clear previously set flag
281 */
282
283 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
284
285 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800286 * Filter out RSN/WPA IE(s)
287 */
288
289 if (ies && ies_len) {
290 buf = kmalloc(ies_len, GFP_KERNEL);
291 if (buf == NULL)
292 return -ENOMEM;
293 pos = ies;
294
295 while (pos + 1 < ies + ies_len) {
296 if (pos + 2 + pos[1] > ies + ies_len)
297 break;
298 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
299 memcpy(buf + len, pos, 2 + pos[1]);
300 len += 2 + pos[1];
301 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700302
303 if (ath6kl_is_wps_ie(pos))
304 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
305
Kevin Fang6981ffd2011-10-07 08:51:19 +0800306 pos += 2 + pos[1];
307 }
308 }
309
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530310 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
311 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800312 kfree(buf);
313 return ret;
314}
315
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530316static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
317{
318 switch (type) {
319 case NL80211_IFTYPE_STATION:
320 *nw_type = INFRA_NETWORK;
321 break;
322 case NL80211_IFTYPE_ADHOC:
323 *nw_type = ADHOC_NETWORK;
324 break;
325 case NL80211_IFTYPE_AP:
326 *nw_type = AP_NETWORK;
327 break;
328 case NL80211_IFTYPE_P2P_CLIENT:
329 *nw_type = INFRA_NETWORK;
330 break;
331 case NL80211_IFTYPE_P2P_GO:
332 *nw_type = AP_NETWORK;
333 break;
334 default:
335 ath6kl_err("invalid interface type %u\n", type);
336 return -ENOTSUPP;
337 }
338
339 return 0;
340}
341
342static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
343 u8 *if_idx, u8 *nw_type)
344{
345 int i;
346
347 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
348 return false;
349
350 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
351 ar->num_vif))
352 return false;
353
354 if (type == NL80211_IFTYPE_STATION ||
355 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
356 for (i = 0; i < MAX_NUM_VIF; i++) {
357 if ((ar->avail_idx_map >> i) & BIT(0)) {
358 *if_idx = i;
359 return true;
360 }
361 }
362 }
363
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530364 if (type == NL80211_IFTYPE_P2P_CLIENT ||
365 type == NL80211_IFTYPE_P2P_GO) {
366 for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
367 if ((ar->avail_idx_map >> i) & BIT(0)) {
368 *if_idx = i;
369 return true;
370 }
371 }
372 }
373
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530374 return false;
375}
376
Kalle Valobdcd8172011-07-18 00:22:30 +0300377static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
378 struct cfg80211_connect_params *sme)
379{
380 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530381 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300382 int status;
383
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530384 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300385
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530386 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300387 return -EIO;
388
389 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
390 ath6kl_err("destroy in progress\n");
391 return -EBUSY;
392 }
393
394 if (test_bit(SKIP_SCAN, &ar->flag) &&
395 ((sme->channel && sme->channel->center_freq == 0) ||
396 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
397 ath6kl_err("SkipScan: channel or bssid invalid\n");
398 return -EINVAL;
399 }
400
401 if (down_interruptible(&ar->sem)) {
402 ath6kl_err("busy, couldn't get access\n");
403 return -ERESTARTSYS;
404 }
405
406 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
407 ath6kl_err("busy, destroy in progress\n");
408 up(&ar->sem);
409 return -EBUSY;
410 }
411
412 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
413 /*
414 * sleep until the command queue drains
415 */
416 wait_event_interruptible_timeout(ar->event_wq,
417 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
418 WMI_TIMEOUT);
419 if (signal_pending(current)) {
420 ath6kl_err("cmd queue drain timeout\n");
421 up(&ar->sem);
422 return -EINTR;
423 }
424 }
425
Kevin Fang6981ffd2011-10-07 08:51:19 +0800426 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530427 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800428 if (status)
429 return status;
430 }
431
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530432 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530433 vif->ssid_len == sme->ssid_len &&
434 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530435 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530436 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
437 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530438 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300439
440 up(&ar->sem);
441 if (status) {
442 ath6kl_err("wmi_reconnect_cmd failed\n");
443 return -EIO;
444 }
445 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530446 } else if (vif->ssid_len == sme->ssid_len &&
447 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530448 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300449 }
450
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530451 memset(vif->ssid, 0, sizeof(vif->ssid));
452 vif->ssid_len = sme->ssid_len;
453 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300454
455 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530456 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300457
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530458 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300459 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530460 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300461
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530462 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300463
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530464 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 if (status) {
466 up(&ar->sem);
467 return status;
468 }
469
470 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530471 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300472 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530473 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300474
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530475 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300476
477 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530478 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300479
480 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530481 (vif->auth_mode == NONE_AUTH) &&
482 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300483 struct ath6kl_key *key = NULL;
484
485 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
486 sme->key_idx > WMI_MAX_KEY_INDEX) {
487 ath6kl_err("key index %d out of bounds\n",
488 sme->key_idx);
489 up(&ar->sem);
490 return -ENOENT;
491 }
492
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530493 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300494 key->key_len = sme->key_len;
495 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530496 key->cipher = vif->prwise_crypto;
497 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300498
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530499 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530500 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300501 GROUP_USAGE | TX_USAGE,
502 key->key_len,
503 NULL,
504 key->key, KEY_OP_INIT_VAL, NULL,
505 NO_SYNC_WMIFLAG);
506 }
507
508 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530509 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530510 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
511 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300512 ath6kl_err("couldn't set bss filtering\n");
513 up(&ar->sem);
514 return -EIO;
515 }
516 }
517
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530518 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300519
520 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
521 "%s: connect called with authmode %d dot11 auth %d"
522 " PW crypto %d PW crypto len %d GRP crypto %d"
523 " GRP crypto len %d channel hint %u\n",
524 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530525 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
526 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530527 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300528
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530529 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530530 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530531 vif->dot11_auth_mode, vif->auth_mode,
532 vif->prwise_crypto,
533 vif->prwise_crypto_len,
534 vif->grp_crypto, vif->grp_crypto_len,
535 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530536 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300537 ar->connect_ctrl_flags);
538
539 up(&ar->sem);
540
541 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530542 memset(vif->ssid, 0, sizeof(vif->ssid));
543 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300544 ath6kl_err("invalid request\n");
545 return -ENOENT;
546 } else if (status) {
547 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
548 return -EIO;
549 }
550
551 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530552 ((vif->auth_mode == WPA_PSK_AUTH)
553 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530554 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300555 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
556 }
557
558 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530559 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300560
561 return 0;
562}
563
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530564static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300565 struct ieee80211_channel *chan,
566 const u8 *beacon_ie, size_t beacon_ie_len)
567{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530568 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300569 struct cfg80211_bss *bss;
570 u8 *ie;
571
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530572 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530573 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300574 WLAN_CAPABILITY_ESS);
575 if (bss == NULL) {
576 /*
577 * Since cfg80211 may not yet know about the BSS,
578 * generate a partial entry until the first BSS info
579 * event becomes available.
580 *
581 * Prepend SSID element since it is not included in the Beacon
582 * IEs from the target.
583 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300585 if (ie == NULL)
586 return -ENOMEM;
587 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530588 ie[1] = vif->ssid_len;
589 memcpy(ie + 2, vif->ssid, vif->ssid_len);
590 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530591 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300592 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530593 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300594 0, GFP_KERNEL);
595 if (bss)
596 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
597 "%pM prior to indicating connect/roamed "
598 "event\n", bssid);
599 kfree(ie);
600 } else
601 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
602 "entry\n");
603
604 if (bss == NULL)
605 return -ENOMEM;
606
607 cfg80211_put_bss(bss);
608
609 return 0;
610}
611
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530612void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300613 u8 *bssid, u16 listen_intvl,
614 u16 beacon_intvl,
615 enum network_type nw_type,
616 u8 beacon_ie_len, u8 assoc_req_len,
617 u8 assoc_resp_len, u8 *assoc_info)
618{
Jouni Malinen01cac472011-09-19 19:14:59 +0300619 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530620 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300621
622 /* capinfo + listen interval */
623 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
624
625 /* capinfo + status code + associd */
626 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
627
628 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
629 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
630 assoc_resp_ie_offset;
631
632 assoc_req_len -= assoc_req_ie_offset;
633 assoc_resp_len -= assoc_resp_ie_offset;
634
Jouni Malinen32c10872011-09-19 19:15:07 +0300635 /*
636 * Store Beacon interval here; DTIM period will be available only once
637 * a Beacon frame from the AP is seen.
638 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530639 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530640 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300641
Kalle Valobdcd8172011-07-18 00:22:30 +0300642 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530643 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300644 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
645 "%s: ath6k not in ibss mode\n", __func__);
646 return;
647 }
648 }
649
650 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530651 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
652 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
654 "%s: ath6k not in station mode\n", __func__);
655 return;
656 }
657 }
658
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530659 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300660
Kalle Valobdcd8172011-07-18 00:22:30 +0300661
662 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530663 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 return;
665 }
666
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530667 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300668 beacon_ie_len) < 0) {
669 ath6kl_err("could not add cfg80211 bss entry for "
670 "connect/roamed notification\n");
671 return;
672 }
673
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530674 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300675 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530676 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530677 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300678 assoc_req_ie, assoc_req_len,
679 assoc_resp_ie, assoc_resp_len,
680 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530681 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530683 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300684 assoc_req_ie, assoc_req_len,
685 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
686 }
687}
688
689static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
690 struct net_device *dev, u16 reason_code)
691{
692 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530693 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300694
695 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
696 reason_code);
697
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530698 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300699 return -EIO;
700
701 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
702 ath6kl_err("busy, destroy in progress\n");
703 return -EBUSY;
704 }
705
706 if (down_interruptible(&ar->sem)) {
707 ath6kl_err("busy, couldn't get access\n");
708 return -ERESTARTSYS;
709 }
710
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530711 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530712 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530713 memset(vif->ssid, 0, sizeof(vif->ssid));
714 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300715
716 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530717 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300718
719 up(&ar->sem);
720
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530721 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530722
Kalle Valobdcd8172011-07-18 00:22:30 +0300723 return 0;
724}
725
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 u8 *bssid, u8 assoc_resp_len,
728 u8 *assoc_info, u16 proto_reason)
729{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530730 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530731
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530732 if (vif->scan_req) {
733 cfg80211_scan_done(vif->scan_req, true);
734 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300735 }
736
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530737 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530738 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300739 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
740 "%s: ath6k not in ibss mode\n", __func__);
741 return;
742 }
743 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300745 return;
746 }
747
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530748 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530749 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
750 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300751 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
752 "%s: ath6k not in station mode\n", __func__);
753 return;
754 }
755 }
756
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530757 /*
758 * Send a disconnect command to target when a disconnect event is
759 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
760 * request from host) to make the firmware stop trying to connect even
761 * after giving disconnect event. There will be one more disconnect
762 * event for this disconnect command with reason code DISCONNECT_CMD
763 * which will be notified to cfg80211.
764 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300765
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530766 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530767 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 return;
769 }
770
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530771 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300772
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530773 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530774 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530775 bssid, NULL, 0,
776 NULL, 0,
777 WLAN_STATUS_UNSPECIFIED_FAILURE,
778 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530779 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530780 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530781 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300782 }
783
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530784 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300785}
786
Kalle Valobdcd8172011-07-18 00:22:30 +0300787static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
788 struct cfg80211_scan_request *request)
789{
790 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530791 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300792 s8 n_channels = 0;
793 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530795 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300796
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530797 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300798 return -EIO;
799
800 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530801 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300802 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530803 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530804 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300805 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
806 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300807 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300808 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300809 }
810 }
811
812 if (request->n_ssids && request->ssids[0].ssid_len) {
813 u8 i;
814
815 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
816 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
817
818 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530819 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
820 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300821 request->ssids[i].ssid_len,
822 request->ssids[i].ssid);
823 }
824
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300825 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530826 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
827 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300828 request->ie, request->ie_len);
829 if (ret) {
830 ath6kl_err("failed to set Probe Request appie for "
831 "scan");
832 return ret;
833 }
834 }
835
Jouni Malinen11869be2011-09-02 20:07:06 +0300836 /*
837 * Scan only the requested channels if the request specifies a set of
838 * channels. If the list is longer than the target supports, do not
839 * configure the list and instead, scan all available channels.
840 */
841 if (request->n_channels > 0 &&
842 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300843 u8 i;
844
Jouni Malinen11869be2011-09-02 20:07:06 +0300845 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300846
847 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
848 if (channels == NULL) {
849 ath6kl_warn("failed to set scan channels, "
850 "scan all channels");
851 n_channels = 0;
852 }
853
854 for (i = 0; i < n_channels; i++)
855 channels[i] = request->channels[i]->center_freq;
856 }
857
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530858 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530859 force_fg_scan = 1;
860
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530861 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
862 force_fg_scan, false, 0, 0, n_channels,
863 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300864 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300865 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300866 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530867 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300868
Edward Lu1276c9e2011-08-30 21:58:00 +0300869 kfree(channels);
870
Kalle Valobdcd8172011-07-18 00:22:30 +0300871 return ret;
872}
873
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530874void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, int status)
Kalle Valobdcd8172011-07-18 00:22:30 +0300875{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530876 struct ath6kl *ar = vif->ar;
Kalle Valocb938212011-10-27 18:47:46 +0300877 bool aborted;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300878 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300879
880 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
881
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530882 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300883 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300884
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300885 if ((status == -ECANCELED) || (status == -EBUSY)) {
Kalle Valocb938212011-10-27 18:47:46 +0300886 aborted = true;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300887 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300888 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300889
Kalle Valocb938212011-10-27 18:47:46 +0300890 aborted = false;
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;
915 int status = 0;
916
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530917 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300918 return -EIO;
919
Jouni Malinen837cb972011-10-11 17:31:57 +0300920 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
921 if (params->key_len != WMI_KRK_LEN)
922 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530923 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
924 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300925 }
926
Kalle Valobdcd8172011-07-18 00:22:30 +0300927 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
928 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
929 "%s: key index %d out of bounds\n", __func__,
930 key_index);
931 return -ENOENT;
932 }
933
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530934 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300935 memset(key, 0, sizeof(struct ath6kl_key));
936
937 if (pairwise)
938 key_usage = PAIRWISE_USAGE;
939 else
940 key_usage = GROUP_USAGE;
941
942 if (params) {
943 if (params->key_len > WLAN_MAX_KEY_LEN ||
944 params->seq_len > sizeof(key->seq))
945 return -EINVAL;
946
947 key->key_len = params->key_len;
948 memcpy(key->key, params->key, key->key_len);
949 key->seq_len = params->seq_len;
950 memcpy(key->seq, params->seq, key->seq_len);
951 key->cipher = params->cipher;
952 }
953
954 switch (key->cipher) {
955 case WLAN_CIPHER_SUITE_WEP40:
956 case WLAN_CIPHER_SUITE_WEP104:
957 key_type = WEP_CRYPT;
958 break;
959
960 case WLAN_CIPHER_SUITE_TKIP:
961 key_type = TKIP_CRYPT;
962 break;
963
964 case WLAN_CIPHER_SUITE_CCMP:
965 key_type = AES_CRYPT;
966 break;
967
968 default:
969 return -ENOTSUPP;
970 }
971
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530972 if (((vif->auth_mode == WPA_PSK_AUTH)
973 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300974 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530975 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300976
977 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
978 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
979 __func__, key_index, key->key_len, key_type,
980 key_usage, key->seq_len);
981
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530982 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300983
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530984 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300985 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
986 ar->ap_mode_bkey.valid = true;
987 ar->ap_mode_bkey.key_index = key_index;
988 ar->ap_mode_bkey.key_type = key_type;
989 ar->ap_mode_bkey.key_len = key->key_len;
990 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530991 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300992 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
993 "key configuration until AP mode has been "
994 "started\n");
995 /*
996 * The key will be set in ath6kl_connect_ap_mode() once
997 * the connected event is received from the target.
998 */
999 return 0;
1000 }
1001 }
1002
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301003 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301004 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001005 /*
1006 * Store the key locally so that it can be re-configured after
1007 * the AP mode has properly started
1008 * (ath6kl_install_statioc_wep_keys).
1009 */
1010 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1011 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301012 vif->wep_key_list[key_index].key_len = key->key_len;
1013 memcpy(vif->wep_key_list[key_index].key, key->key,
1014 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001015 return 0;
1016 }
1017
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301018 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1019 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +03001020 key_type, key_usage, key->key_len,
1021 key->seq, key->key, KEY_OP_INIT_VAL,
1022 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
1023
1024 if (status)
1025 return -EIO;
1026
1027 return 0;
1028}
1029
1030static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1031 u8 key_index, bool pairwise,
1032 const u8 *mac_addr)
1033{
1034 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301035 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001036
1037 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1038
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301039 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001040 return -EIO;
1041
1042 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1043 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1044 "%s: key index %d out of bounds\n", __func__,
1045 key_index);
1046 return -ENOENT;
1047 }
1048
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301049 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001050 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1051 "%s: index %d is empty\n", __func__, key_index);
1052 return 0;
1053 }
1054
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301055 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001056
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301057 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001058}
1059
1060static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1061 u8 key_index, bool pairwise,
1062 const u8 *mac_addr, void *cookie,
1063 void (*callback) (void *cookie,
1064 struct key_params *))
1065{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301066 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001067 struct ath6kl_key *key = NULL;
1068 struct key_params params;
1069
1070 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1071
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301072 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001073 return -EIO;
1074
1075 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1076 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1077 "%s: key index %d out of bounds\n", __func__,
1078 key_index);
1079 return -ENOENT;
1080 }
1081
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301082 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001083 memset(&params, 0, sizeof(params));
1084 params.cipher = key->cipher;
1085 params.key_len = key->key_len;
1086 params.seq_len = key->seq_len;
1087 params.seq = key->seq;
1088 params.key = key->key;
1089
1090 callback(cookie, &params);
1091
1092 return key->key_len ? 0 : -ENOENT;
1093}
1094
1095static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1096 struct net_device *ndev,
1097 u8 key_index, bool unicast,
1098 bool multicast)
1099{
1100 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301101 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001102 struct ath6kl_key *key = NULL;
1103 int status = 0;
1104 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001105 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001106
1107 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1108
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301109 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001110 return -EIO;
1111
1112 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1113 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1114 "%s: key index %d out of bounds\n",
1115 __func__, key_index);
1116 return -ENOENT;
1117 }
1118
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301119 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001120 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1121 __func__, key_index);
1122 return -EINVAL;
1123 }
1124
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301125 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301126 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001127 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301128 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001129 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001130 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301131 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001132 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301133 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001134
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301135 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001136 return 0; /* Delay until AP mode has been started */
1137
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301138 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1139 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001140 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001141 key->key_len, key->seq, key->key,
1142 KEY_OP_INIT_VAL, NULL,
1143 SYNC_BOTH_WMIFLAG);
1144 if (status)
1145 return -EIO;
1146
1147 return 0;
1148}
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
1327 spin_lock(&ar->list_lock);
1328 list_del(&vif->list);
1329 spin_unlock(&ar->list_lock);
1330
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,
Kalle Valobdcd8172011-07-18 00:22:30 +03001467};
1468
1469static bool is_rate_legacy(s32 rate)
1470{
1471 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1472 6000, 9000, 12000, 18000, 24000,
1473 36000, 48000, 54000
1474 };
1475 u8 i;
1476
1477 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1478 if (rate == legacy[i])
1479 return true;
1480
1481 return false;
1482}
1483
1484static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1485{
1486 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1487 52000, 58500, 65000, 72200
1488 };
1489 u8 i;
1490
1491 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1492 if (rate == ht20[i]) {
1493 if (i == ARRAY_SIZE(ht20) - 1)
1494 /* last rate uses sgi */
1495 *sgi = true;
1496 else
1497 *sgi = false;
1498
1499 *mcs = i;
1500 return true;
1501 }
1502 }
1503 return false;
1504}
1505
1506static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1507{
1508 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1509 81000, 108000, 121500, 135000,
1510 150000
1511 };
1512 u8 i;
1513
1514 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1515 if (rate == ht40[i]) {
1516 if (i == ARRAY_SIZE(ht40) - 1)
1517 /* last rate uses sgi */
1518 *sgi = true;
1519 else
1520 *sgi = false;
1521
1522 *mcs = i;
1523 return true;
1524 }
1525 }
1526
1527 return false;
1528}
1529
1530static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1531 u8 *mac, struct station_info *sinfo)
1532{
1533 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301534 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001535 long left;
1536 bool sgi;
1537 s32 rate;
1538 int ret;
1539 u8 mcs;
1540
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301541 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001542 return -ENOENT;
1543
1544 if (down_interruptible(&ar->sem))
1545 return -EBUSY;
1546
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301547 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001548
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301549 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001550
1551 if (ret != 0) {
1552 up(&ar->sem);
1553 return -EIO;
1554 }
1555
1556 left = wait_event_interruptible_timeout(ar->event_wq,
1557 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301558 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001559 WMI_TIMEOUT);
1560
1561 up(&ar->sem);
1562
1563 if (left == 0)
1564 return -ETIMEDOUT;
1565 else if (left < 0)
1566 return left;
1567
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301568 if (vif->target_stats.rx_byte) {
1569 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001570 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301571 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001572 sinfo->filled |= STATION_INFO_RX_PACKETS;
1573 }
1574
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301575 if (vif->target_stats.tx_byte) {
1576 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001577 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301578 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001579 sinfo->filled |= STATION_INFO_TX_PACKETS;
1580 }
1581
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301582 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001583 sinfo->filled |= STATION_INFO_SIGNAL;
1584
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301585 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001586
1587 if (is_rate_legacy(rate)) {
1588 sinfo->txrate.legacy = rate / 100;
1589 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1590 if (sgi) {
1591 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1592 sinfo->txrate.mcs = mcs - 1;
1593 } else {
1594 sinfo->txrate.mcs = mcs;
1595 }
1596
1597 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1598 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1599 if (sgi) {
1600 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1601 sinfo->txrate.mcs = mcs - 1;
1602 } else {
1603 sinfo->txrate.mcs = mcs;
1604 }
1605
1606 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1607 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1608 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001609 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1610 "invalid rate from stats: %d\n", rate);
1611 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001612 return 0;
1613 }
1614
1615 sinfo->filled |= STATION_INFO_TX_BITRATE;
1616
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301617 if (test_bit(CONNECTED, &vif->flags) &&
1618 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301619 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001620 sinfo->filled |= STATION_INFO_BSS_PARAM;
1621 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301622 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1623 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001624 }
1625
Kalle Valobdcd8172011-07-18 00:22:30 +03001626 return 0;
1627}
1628
1629static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1630 struct cfg80211_pmksa *pmksa)
1631{
1632 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301633 struct ath6kl_vif *vif = netdev_priv(netdev);
1634
1635 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001636 pmksa->pmkid, true);
1637}
1638
1639static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1640 struct cfg80211_pmksa *pmksa)
1641{
1642 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301643 struct ath6kl_vif *vif = netdev_priv(netdev);
1644
1645 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001646 pmksa->pmkid, false);
1647}
1648
1649static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1650{
1651 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301652 struct ath6kl_vif *vif = netdev_priv(netdev);
1653
1654 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301655 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1656 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001657 return 0;
1658}
1659
Kalle Valoabcb3442011-07-22 08:26:20 +03001660#ifdef CONFIG_PM
1661static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1662 struct cfg80211_wowlan *wow)
1663{
1664 struct ath6kl *ar = wiphy_priv(wiphy);
1665
1666 return ath6kl_hif_suspend(ar);
1667}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001668
1669static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1670{
1671 struct ath6kl *ar = wiphy_priv(wiphy);
1672
1673 return ath6kl_hif_resume(ar);
1674}
Kalle Valoabcb3442011-07-22 08:26:20 +03001675#endif
1676
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001677static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1678 struct ieee80211_channel *chan,
1679 enum nl80211_channel_type channel_type)
1680{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301681 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001682
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301683 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001684 return -EIO;
1685
1686 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1687 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301688 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001689
1690 return 0;
1691}
1692
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001693static bool ath6kl_is_p2p_ie(const u8 *pos)
1694{
1695 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1696 pos[2] == 0x50 && pos[3] == 0x6f &&
1697 pos[4] == 0x9a && pos[5] == 0x09;
1698}
1699
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301700static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1701 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001702{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301703 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001704 const u8 *pos;
1705 u8 *buf = NULL;
1706 size_t len = 0;
1707 int ret;
1708
1709 /*
1710 * Filter out P2P IE(s) since they will be included depending on
1711 * the Probe Request frame in ath6kl_send_go_probe_resp().
1712 */
1713
1714 if (ies && ies_len) {
1715 buf = kmalloc(ies_len, GFP_KERNEL);
1716 if (buf == NULL)
1717 return -ENOMEM;
1718 pos = ies;
1719 while (pos + 1 < ies + ies_len) {
1720 if (pos + 2 + pos[1] > ies + ies_len)
1721 break;
1722 if (!ath6kl_is_p2p_ie(pos)) {
1723 memcpy(buf + len, pos, 2 + pos[1]);
1724 len += 2 + pos[1];
1725 }
1726 pos += 2 + pos[1];
1727 }
1728 }
1729
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301730 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1731 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001732 kfree(buf);
1733 return ret;
1734}
1735
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001736static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1737 struct beacon_parameters *info, bool add)
1738{
1739 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301740 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001741 struct ieee80211_mgmt *mgmt;
1742 u8 *ies;
1743 int ies_len;
1744 struct wmi_connect_cmd p;
1745 int res;
1746 int i;
1747
1748 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1749
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301750 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001751 return -EIO;
1752
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301753 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001754 return -EOPNOTSUPP;
1755
1756 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301757 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1758 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001759 info->beacon_ies,
1760 info->beacon_ies_len);
1761 if (res)
1762 return res;
1763 }
1764 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301765 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001766 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001767 if (res)
1768 return res;
1769 }
1770 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301771 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1772 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001773 info->assocresp_ies,
1774 info->assocresp_ies_len);
1775 if (res)
1776 return res;
1777 }
1778
1779 if (!add)
1780 return 0;
1781
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001782 ar->ap_mode_bkey.valid = false;
1783
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001784 /* TODO:
1785 * info->interval
1786 * info->dtim_period
1787 */
1788
1789 if (info->head == NULL)
1790 return -EINVAL;
1791 mgmt = (struct ieee80211_mgmt *) info->head;
1792 ies = mgmt->u.beacon.variable;
1793 if (ies > info->head + info->head_len)
1794 return -EINVAL;
1795 ies_len = info->head + info->head_len - ies;
1796
1797 if (info->ssid == NULL)
1798 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301799 memcpy(vif->ssid, info->ssid, info->ssid_len);
1800 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001801 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1802 return -EOPNOTSUPP; /* TODO */
1803
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301804 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001805
1806 memset(&p, 0, sizeof(p));
1807
1808 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1809 switch (info->crypto.akm_suites[i]) {
1810 case WLAN_AKM_SUITE_8021X:
1811 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1812 p.auth_mode |= WPA_AUTH;
1813 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1814 p.auth_mode |= WPA2_AUTH;
1815 break;
1816 case WLAN_AKM_SUITE_PSK:
1817 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1818 p.auth_mode |= WPA_PSK_AUTH;
1819 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1820 p.auth_mode |= WPA2_PSK_AUTH;
1821 break;
1822 }
1823 }
1824 if (p.auth_mode == 0)
1825 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301826 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001827
1828 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1829 switch (info->crypto.ciphers_pairwise[i]) {
1830 case WLAN_CIPHER_SUITE_WEP40:
1831 case WLAN_CIPHER_SUITE_WEP104:
1832 p.prwise_crypto_type |= WEP_CRYPT;
1833 break;
1834 case WLAN_CIPHER_SUITE_TKIP:
1835 p.prwise_crypto_type |= TKIP_CRYPT;
1836 break;
1837 case WLAN_CIPHER_SUITE_CCMP:
1838 p.prwise_crypto_type |= AES_CRYPT;
1839 break;
1840 }
1841 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001842 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001843 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301844 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001845 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301846 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001847
1848 switch (info->crypto.cipher_group) {
1849 case WLAN_CIPHER_SUITE_WEP40:
1850 case WLAN_CIPHER_SUITE_WEP104:
1851 p.grp_crypto_type = WEP_CRYPT;
1852 break;
1853 case WLAN_CIPHER_SUITE_TKIP:
1854 p.grp_crypto_type = TKIP_CRYPT;
1855 break;
1856 case WLAN_CIPHER_SUITE_CCMP:
1857 p.grp_crypto_type = AES_CRYPT;
1858 break;
1859 default:
1860 p.grp_crypto_type = NONE_CRYPT;
1861 break;
1862 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301863 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001864
1865 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301866 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001867
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301868 p.ssid_len = vif->ssid_len;
1869 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1870 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301871 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001872
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301873 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001874 if (res < 0)
1875 return res;
1876
1877 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001878}
1879
1880static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1881 struct beacon_parameters *info)
1882{
1883 return ath6kl_ap_beacon(wiphy, dev, info, true);
1884}
1885
1886static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1887 struct beacon_parameters *info)
1888{
1889 return ath6kl_ap_beacon(wiphy, dev, info, false);
1890}
1891
1892static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1893{
1894 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301895 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001896
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301897 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001898 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301899 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001900 return -ENOTCONN;
1901
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301902 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301903 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001904
1905 return 0;
1906}
1907
Jouni Malinen23875132011-08-30 21:57:53 +03001908static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1909 u8 *mac, struct station_parameters *params)
1910{
1911 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301912 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001913
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301914 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001915 return -EOPNOTSUPP;
1916
1917 /* Use this only for authorizing/unauthorizing a station */
1918 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1919 return -EOPNOTSUPP;
1920
1921 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301922 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1923 WMI_AP_MLME_AUTHORIZE, mac, 0);
1924 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1925 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03001926}
1927
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001928static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1929 struct net_device *dev,
1930 struct ieee80211_channel *chan,
1931 enum nl80211_channel_type channel_type,
1932 unsigned int duration,
1933 u64 *cookie)
1934{
1935 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301936 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03001937 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001938
1939 /* TODO: if already pending or ongoing remain-on-channel,
1940 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03001941 id = ++vif->last_roc_id;
1942 if (id == 0) {
1943 /* Do not use 0 as the cookie value */
1944 id = ++vif->last_roc_id;
1945 }
1946 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001947
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301948 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
1949 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001950}
1951
1952static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1953 struct net_device *dev,
1954 u64 cookie)
1955{
1956 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301957 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001958
Jouni Malinen10522612011-10-27 16:00:13 +03001959 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001960 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03001961 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001962
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301963 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001964}
1965
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301966static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
1967 const u8 *buf, size_t len,
1968 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001969{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301970 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001971 const u8 *pos;
1972 u8 *p2p;
1973 int p2p_len;
1974 int ret;
1975 const struct ieee80211_mgmt *mgmt;
1976
1977 mgmt = (const struct ieee80211_mgmt *) buf;
1978
1979 /* Include P2P IE(s) from the frame generated in user space. */
1980
1981 p2p = kmalloc(len, GFP_KERNEL);
1982 if (p2p == NULL)
1983 return -ENOMEM;
1984 p2p_len = 0;
1985
1986 pos = mgmt->u.probe_resp.variable;
1987 while (pos + 1 < buf + len) {
1988 if (pos + 2 + pos[1] > buf + len)
1989 break;
1990 if (ath6kl_is_p2p_ie(pos)) {
1991 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1992 p2p_len += 2 + pos[1];
1993 }
1994 pos += 2 + pos[1];
1995 }
1996
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301997 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
1998 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001999 kfree(p2p);
2000 return ret;
2001}
2002
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002003static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2004 struct ieee80211_channel *chan, bool offchan,
2005 enum nl80211_channel_type channel_type,
2006 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002007 const u8 *buf, size_t len, bool no_cck,
2008 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002009{
2010 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302011 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002012 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002013 const struct ieee80211_mgmt *mgmt;
2014
2015 mgmt = (const struct ieee80211_mgmt *) buf;
2016 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302017 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002018 ieee80211_is_probe_resp(mgmt->frame_control)) {
2019 /*
2020 * Send Probe Response frame in AP mode using a separate WMI
2021 * command to allow the target to fill in the generic IEs.
2022 */
2023 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302024 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002025 chan->center_freq);
2026 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002027
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302028 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002029 if (id == 0) {
2030 /*
2031 * 0 is a reserved value in the WMI command and shall not be
2032 * used for the command.
2033 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302034 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002035 }
2036
2037 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302038 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2039 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002040 buf, len);
2041}
2042
Jouni Malinenae32c302011-08-30 21:58:01 +03002043static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2044 struct net_device *dev,
2045 u16 frame_type, bool reg)
2046{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302047 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002048
2049 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2050 __func__, frame_type, reg);
2051 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2052 /*
2053 * Note: This notification callback is not allowed to sleep, so
2054 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2055 * hardcode target to report Probe Request frames all the time.
2056 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302057 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002058 }
2059}
2060
Jouni Malinenf80574a2011-08-30 21:58:04 +03002061static const struct ieee80211_txrx_stypes
2062ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2063 [NL80211_IFTYPE_STATION] = {
2064 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2065 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2066 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2067 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2068 },
2069 [NL80211_IFTYPE_P2P_CLIENT] = {
2070 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2071 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2072 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2073 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2074 },
2075 [NL80211_IFTYPE_P2P_GO] = {
2076 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2077 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2078 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2079 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2080 },
2081};
2082
Kalle Valobdcd8172011-07-18 00:22:30 +03002083static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302084 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2085 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002086 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2087 .scan = ath6kl_cfg80211_scan,
2088 .connect = ath6kl_cfg80211_connect,
2089 .disconnect = ath6kl_cfg80211_disconnect,
2090 .add_key = ath6kl_cfg80211_add_key,
2091 .get_key = ath6kl_cfg80211_get_key,
2092 .del_key = ath6kl_cfg80211_del_key,
2093 .set_default_key = ath6kl_cfg80211_set_default_key,
2094 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2095 .set_tx_power = ath6kl_cfg80211_set_txpower,
2096 .get_tx_power = ath6kl_cfg80211_get_txpower,
2097 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2098 .join_ibss = ath6kl_cfg80211_join_ibss,
2099 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2100 .get_station = ath6kl_get_station,
2101 .set_pmksa = ath6kl_set_pmksa,
2102 .del_pmksa = ath6kl_del_pmksa,
2103 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002104 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002105#ifdef CONFIG_PM
2106 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002107 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002108#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002109 .set_channel = ath6kl_set_channel,
2110 .add_beacon = ath6kl_add_beacon,
2111 .set_beacon = ath6kl_set_beacon,
2112 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002113 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002114 .remain_on_channel = ath6kl_remain_on_channel,
2115 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002116 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002117 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002118};
2119
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302120struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002121{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002122 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302123 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302124 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002125
2126 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302127 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302128
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302129 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002130 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002131 return NULL;
2132 }
2133
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302134 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302135 if (!multi_norm_if_support)
2136 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302137 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302138 ar->dev = dev;
2139
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302140 if (multi_norm_if_support)
2141 ar->max_norm_iface = 2;
2142 else
2143 ar->max_norm_iface = 1;
2144
2145 /* FIXME: Remove this once the multivif support is enabled */
2146 ar->max_norm_iface = 1;
2147
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302148 spin_lock_init(&ar->lock);
2149 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302150 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302151
2152 init_waitqueue_head(&ar->event_wq);
2153 sema_init(&ar->sem, 1);
2154
2155 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302156 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302157
2158 clear_bit(WMI_ENABLED, &ar->flag);
2159 clear_bit(SKIP_SCAN, &ar->flag);
2160 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2161
2162 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2163 ar->listen_intvl_b = 0;
2164 ar->tx_pwr = 0;
2165
2166 ar->intra_bss = 1;
2167 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2168 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2169 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2170 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2171
2172 memset((u8 *)ar->sta_list, 0,
2173 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2174
2175 /* Init the PS queues */
2176 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2177 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2178 skb_queue_head_init(&ar->sta_list[ctr].psq);
2179 }
2180
2181 skb_queue_head_init(&ar->mcastpsq);
2182
2183 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2184
2185 return ar;
2186}
2187
2188int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2189{
2190 struct wiphy *wiphy = ar->wiphy;
2191 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002192
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302193 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002194
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302195 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002196
Kalle Valobdcd8172011-07-18 00:22:30 +03002197 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302198 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002199
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302200 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302201 BIT(NL80211_IFTYPE_ADHOC) |
2202 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002203 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302204 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302205 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002206 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302207
Kalle Valobdcd8172011-07-18 00:22:30 +03002208 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302209 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2210 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2211 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2212 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2213 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002214
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302215 wiphy->cipher_suites = cipher_suites;
2216 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002217
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302218 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002219 if (ret < 0) {
2220 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302221 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002222 }
2223
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302224 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002225}
2226
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302227static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002228{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302229 vif->aggr_cntxt = aggr_init(vif->ndev);
2230 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302231 ath6kl_err("failed to initialize aggr\n");
2232 return -ENOMEM;
2233 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002234
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302235 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302236 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302237 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302238 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302239
2240 return 0;
2241}
2242
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302243void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302244{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302245 struct ath6kl *ar = vif->ar;
2246
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302247 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302248
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302249 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2250
2251 if (vif->nw_type == ADHOC_NETWORK)
2252 ar->ibss_if_active = false;
2253
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302254 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302255
2256 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302257}
2258
2259struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302260 enum nl80211_iftype type, u8 fw_vif_idx,
2261 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302262{
2263 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302264 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302265
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302266 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302267 if (!ndev)
2268 return NULL;
2269
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302270 vif = netdev_priv(ndev);
2271 ndev->ieee80211_ptr = &vif->wdev;
2272 vif->wdev.wiphy = ar->wiphy;
2273 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302274 vif->ndev = ndev;
2275 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2276 vif->wdev.netdev = ndev;
2277 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302278 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302279 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302280
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302281 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2282 if (fw_vif_idx != 0)
2283 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2284 0x2;
2285
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302286 init_netdev(ndev);
2287
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302288 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302289
2290 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302291 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302292 goto err;
2293
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302294 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302295 goto err;
2296
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302297 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302298 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302299 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302300 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302301 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302302
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302303 if (type == NL80211_IFTYPE_ADHOC)
2304 ar->ibss_if_active = true;
2305
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302306 spin_lock(&ar->list_lock);
2307 list_add_tail(&vif->list, &ar->vif_list);
2308 spin_unlock(&ar->list_lock);
2309
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302310 return ndev;
2311
2312err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302313 aggr_module_destroy(vif->aggr_cntxt);
2314 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302315 return NULL;
2316}
2317
2318void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2319{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302320 wiphy_unregister(ar->wiphy);
2321 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002322}