blob: a563fdf891da169e110c39514b14621ffd99d799 [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 Valo6fd1eac2011-07-21 10:22:50 +0300877 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300878
879 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
880
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530881 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300882 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300883
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300884 if ((status == -ECANCELED) || (status == -EBUSY)) {
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530885 cfg80211_scan_done(vif->scan_req, true);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300886 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300887 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300888
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530889 cfg80211_scan_done(vif->scan_req, false);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300890
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530891 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
892 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530893 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
894 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300895 0, NULL);
896 }
897 }
898
899out:
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530900 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300901}
902
903static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
904 u8 key_index, bool pairwise,
905 const u8 *mac_addr,
906 struct key_params *params)
907{
908 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530909 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300910 struct ath6kl_key *key = NULL;
911 u8 key_usage;
912 u8 key_type;
913 int status = 0;
914
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530915 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300916 return -EIO;
917
Jouni Malinen837cb972011-10-11 17:31:57 +0300918 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
919 if (params->key_len != WMI_KRK_LEN)
920 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530921 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
922 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300923 }
924
Kalle Valobdcd8172011-07-18 00:22:30 +0300925 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
926 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
927 "%s: key index %d out of bounds\n", __func__,
928 key_index);
929 return -ENOENT;
930 }
931
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530932 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300933 memset(key, 0, sizeof(struct ath6kl_key));
934
935 if (pairwise)
936 key_usage = PAIRWISE_USAGE;
937 else
938 key_usage = GROUP_USAGE;
939
940 if (params) {
941 if (params->key_len > WLAN_MAX_KEY_LEN ||
942 params->seq_len > sizeof(key->seq))
943 return -EINVAL;
944
945 key->key_len = params->key_len;
946 memcpy(key->key, params->key, key->key_len);
947 key->seq_len = params->seq_len;
948 memcpy(key->seq, params->seq, key->seq_len);
949 key->cipher = params->cipher;
950 }
951
952 switch (key->cipher) {
953 case WLAN_CIPHER_SUITE_WEP40:
954 case WLAN_CIPHER_SUITE_WEP104:
955 key_type = WEP_CRYPT;
956 break;
957
958 case WLAN_CIPHER_SUITE_TKIP:
959 key_type = TKIP_CRYPT;
960 break;
961
962 case WLAN_CIPHER_SUITE_CCMP:
963 key_type = AES_CRYPT;
964 break;
965
966 default:
967 return -ENOTSUPP;
968 }
969
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530970 if (((vif->auth_mode == WPA_PSK_AUTH)
971 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300972 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530973 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300974
975 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
976 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
977 __func__, key_index, key->key_len, key_type,
978 key_usage, key->seq_len);
979
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530980 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300981
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530982 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300983 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
984 ar->ap_mode_bkey.valid = true;
985 ar->ap_mode_bkey.key_index = key_index;
986 ar->ap_mode_bkey.key_type = key_type;
987 ar->ap_mode_bkey.key_len = key->key_len;
988 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530989 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300990 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
991 "key configuration until AP mode has been "
992 "started\n");
993 /*
994 * The key will be set in ath6kl_connect_ap_mode() once
995 * the connected event is received from the target.
996 */
997 return 0;
998 }
999 }
1000
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301001 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301002 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001003 /*
1004 * Store the key locally so that it can be re-configured after
1005 * the AP mode has properly started
1006 * (ath6kl_install_statioc_wep_keys).
1007 */
1008 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1009 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301010 vif->wep_key_list[key_index].key_len = key->key_len;
1011 memcpy(vif->wep_key_list[key_index].key, key->key,
1012 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001013 return 0;
1014 }
1015
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301016 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1017 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +03001018 key_type, key_usage, key->key_len,
1019 key->seq, key->key, KEY_OP_INIT_VAL,
1020 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
1021
1022 if (status)
1023 return -EIO;
1024
1025 return 0;
1026}
1027
1028static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1029 u8 key_index, bool pairwise,
1030 const u8 *mac_addr)
1031{
1032 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301033 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001034
1035 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1036
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301037 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001038 return -EIO;
1039
1040 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1041 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1042 "%s: key index %d out of bounds\n", __func__,
1043 key_index);
1044 return -ENOENT;
1045 }
1046
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301047 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001048 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1049 "%s: index %d is empty\n", __func__, key_index);
1050 return 0;
1051 }
1052
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301053 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001054
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301055 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001056}
1057
1058static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1059 u8 key_index, bool pairwise,
1060 const u8 *mac_addr, void *cookie,
1061 void (*callback) (void *cookie,
1062 struct key_params *))
1063{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301064 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001065 struct ath6kl_key *key = NULL;
1066 struct key_params params;
1067
1068 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1069
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301070 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001071 return -EIO;
1072
1073 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1074 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1075 "%s: key index %d out of bounds\n", __func__,
1076 key_index);
1077 return -ENOENT;
1078 }
1079
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301080 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001081 memset(&params, 0, sizeof(params));
1082 params.cipher = key->cipher;
1083 params.key_len = key->key_len;
1084 params.seq_len = key->seq_len;
1085 params.seq = key->seq;
1086 params.key = key->key;
1087
1088 callback(cookie, &params);
1089
1090 return key->key_len ? 0 : -ENOENT;
1091}
1092
1093static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1094 struct net_device *ndev,
1095 u8 key_index, bool unicast,
1096 bool multicast)
1097{
1098 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301099 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001100 struct ath6kl_key *key = NULL;
1101 int status = 0;
1102 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001103 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001104
1105 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1106
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301107 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001108 return -EIO;
1109
1110 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1111 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1112 "%s: key index %d out of bounds\n",
1113 __func__, key_index);
1114 return -ENOENT;
1115 }
1116
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301117 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001118 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1119 __func__, key_index);
1120 return -EINVAL;
1121 }
1122
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301123 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301124 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001125 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301126 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001127 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001128 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301129 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001130 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301131 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001132
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301133 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001134 return 0; /* Delay until AP mode has been started */
1135
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301136 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1137 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001138 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001139 key->key_len, key->seq, key->key,
1140 KEY_OP_INIT_VAL, NULL,
1141 SYNC_BOTH_WMIFLAG);
1142 if (status)
1143 return -EIO;
1144
1145 return 0;
1146}
1147
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301148void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001149 bool ismcast)
1150{
1151 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1152 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1153
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301154 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001155 (ismcast ? NL80211_KEYTYPE_GROUP :
1156 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1157 GFP_KERNEL);
1158}
1159
1160static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1161{
1162 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301163 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001164 int ret;
1165
1166 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1167 changed);
1168
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301169 vif = ath6kl_vif_first(ar);
1170 if (!vif)
1171 return -EIO;
1172
1173 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001174 return -EIO;
1175
1176 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1177 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1178 if (ret != 0) {
1179 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1180 return -EIO;
1181 }
1182 }
1183
1184 return 0;
1185}
1186
1187/*
1188 * The type nl80211_tx_power_setting replaces the following
1189 * data type from 2.6.36 onwards
1190*/
1191static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1192 enum nl80211_tx_power_setting type,
1193 int dbm)
1194{
1195 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301196 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001197 u8 ath6kl_dbm;
1198
1199 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1200 type, dbm);
1201
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301202 vif = ath6kl_vif_first(ar);
1203 if (!vif)
1204 return -EIO;
1205
1206 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001207 return -EIO;
1208
1209 switch (type) {
1210 case NL80211_TX_POWER_AUTOMATIC:
1211 return 0;
1212 case NL80211_TX_POWER_LIMITED:
1213 ar->tx_pwr = ath6kl_dbm = dbm;
1214 break;
1215 default:
1216 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1217 __func__, type);
1218 return -EOPNOTSUPP;
1219 }
1220
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301221 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001222
1223 return 0;
1224}
1225
1226static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1227{
1228 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301229 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001230
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301231 vif = ath6kl_vif_first(ar);
1232 if (!vif)
1233 return -EIO;
1234
1235 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001236 return -EIO;
1237
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301238 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001239 ar->tx_pwr = 0;
1240
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301241 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001242 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1243 return -EIO;
1244 }
1245
1246 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1247 5 * HZ);
1248
1249 if (signal_pending(current)) {
1250 ath6kl_err("target did not respond\n");
1251 return -EINTR;
1252 }
1253 }
1254
1255 *dbm = ar->tx_pwr;
1256 return 0;
1257}
1258
1259static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1260 struct net_device *dev,
1261 bool pmgmt, int timeout)
1262{
1263 struct ath6kl *ar = ath6kl_priv(dev);
1264 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301265 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001266
1267 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1268 __func__, pmgmt, timeout);
1269
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301270 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001271 return -EIO;
1272
1273 if (pmgmt) {
1274 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1275 mode.pwr_mode = REC_POWER;
1276 } else {
1277 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1278 mode.pwr_mode = MAX_PERF_POWER;
1279 }
1280
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301281 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1282 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001283 ath6kl_err("wmi_powermode_cmd failed\n");
1284 return -EIO;
1285 }
1286
1287 return 0;
1288}
1289
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301290static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1291 char *name,
1292 enum nl80211_iftype type,
1293 u32 *flags,
1294 struct vif_params *params)
1295{
1296 struct ath6kl *ar = wiphy_priv(wiphy);
1297 struct net_device *ndev;
1298 u8 if_idx, nw_type;
1299
1300 if (ar->num_vif == MAX_NUM_VIF) {
1301 ath6kl_err("Reached maximum number of supported vif\n");
1302 return ERR_PTR(-EINVAL);
1303 }
1304
1305 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1306 ath6kl_err("Not a supported interface type\n");
1307 return ERR_PTR(-EINVAL);
1308 }
1309
1310 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1311 if (!ndev)
1312 return ERR_PTR(-ENOMEM);
1313
1314 ar->num_vif++;
1315
1316 return ndev;
1317}
1318
1319static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1320 struct net_device *ndev)
1321{
1322 struct ath6kl *ar = wiphy_priv(wiphy);
1323 struct ath6kl_vif *vif = netdev_priv(ndev);
1324
1325 spin_lock(&ar->list_lock);
1326 list_del(&vif->list);
1327 spin_unlock(&ar->list_lock);
1328
1329 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1330
1331 ath6kl_deinit_if_data(vif);
1332
1333 return 0;
1334}
1335
Kalle Valobdcd8172011-07-18 00:22:30 +03001336static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1337 struct net_device *ndev,
1338 enum nl80211_iftype type, u32 *flags,
1339 struct vif_params *params)
1340{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301341 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001342
1343 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1344
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301345 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001346 return -EIO;
1347
1348 switch (type) {
1349 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301350 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001351 break;
1352 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301353 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001354 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001355 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301356 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001357 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001358 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301359 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001360 break;
1361 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301362 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001363 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001364 default:
1365 ath6kl_err("invalid interface type %u\n", type);
1366 return -EOPNOTSUPP;
1367 }
1368
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301369 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001370
1371 return 0;
1372}
1373
1374static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1375 struct net_device *dev,
1376 struct cfg80211_ibss_params *ibss_param)
1377{
1378 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301379 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001380 int status;
1381
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301382 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001383 return -EIO;
1384
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301385 vif->ssid_len = ibss_param->ssid_len;
1386 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001387
1388 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301389 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001390
1391 if (ibss_param->channel_fixed) {
1392 /*
1393 * TODO: channel_fixed: The channel should be fixed, do not
1394 * search for IBSSs to join on other channels. Target
1395 * firmware does not support this feature, needs to be
1396 * updated.
1397 */
1398 return -EOPNOTSUPP;
1399 }
1400
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301401 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001402 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301403 memcpy(vif->req_bssid, ibss_param->bssid,
1404 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001405
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301406 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001407
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301408 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001409 if (status)
1410 return status;
1411
1412 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301413 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1414 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001415 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301416 ath6kl_set_cipher(vif, 0, true);
1417 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001418 }
1419
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301420 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001421
1422 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1423 "%s: connect called with authmode %d dot11 auth %d"
1424 " PW crypto %d PW crypto len %d GRP crypto %d"
1425 " GRP crypto len %d channel hint %u\n",
1426 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301427 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1428 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301429 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001430
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301431 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301432 vif->dot11_auth_mode, vif->auth_mode,
1433 vif->prwise_crypto,
1434 vif->prwise_crypto_len,
1435 vif->grp_crypto, vif->grp_crypto_len,
1436 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301437 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001438 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301439 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001440
1441 return 0;
1442}
1443
1444static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1445 struct net_device *dev)
1446{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301447 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001448
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301449 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001450 return -EIO;
1451
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301452 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301453 memset(vif->ssid, 0, sizeof(vif->ssid));
1454 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001455
1456 return 0;
1457}
1458
1459static const u32 cipher_suites[] = {
1460 WLAN_CIPHER_SUITE_WEP40,
1461 WLAN_CIPHER_SUITE_WEP104,
1462 WLAN_CIPHER_SUITE_TKIP,
1463 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001464 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001465};
1466
1467static bool is_rate_legacy(s32 rate)
1468{
1469 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1470 6000, 9000, 12000, 18000, 24000,
1471 36000, 48000, 54000
1472 };
1473 u8 i;
1474
1475 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1476 if (rate == legacy[i])
1477 return true;
1478
1479 return false;
1480}
1481
1482static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1483{
1484 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1485 52000, 58500, 65000, 72200
1486 };
1487 u8 i;
1488
1489 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1490 if (rate == ht20[i]) {
1491 if (i == ARRAY_SIZE(ht20) - 1)
1492 /* last rate uses sgi */
1493 *sgi = true;
1494 else
1495 *sgi = false;
1496
1497 *mcs = i;
1498 return true;
1499 }
1500 }
1501 return false;
1502}
1503
1504static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1505{
1506 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1507 81000, 108000, 121500, 135000,
1508 150000
1509 };
1510 u8 i;
1511
1512 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1513 if (rate == ht40[i]) {
1514 if (i == ARRAY_SIZE(ht40) - 1)
1515 /* last rate uses sgi */
1516 *sgi = true;
1517 else
1518 *sgi = false;
1519
1520 *mcs = i;
1521 return true;
1522 }
1523 }
1524
1525 return false;
1526}
1527
1528static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1529 u8 *mac, struct station_info *sinfo)
1530{
1531 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301532 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001533 long left;
1534 bool sgi;
1535 s32 rate;
1536 int ret;
1537 u8 mcs;
1538
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301539 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001540 return -ENOENT;
1541
1542 if (down_interruptible(&ar->sem))
1543 return -EBUSY;
1544
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301545 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001546
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301547 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001548
1549 if (ret != 0) {
1550 up(&ar->sem);
1551 return -EIO;
1552 }
1553
1554 left = wait_event_interruptible_timeout(ar->event_wq,
1555 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301556 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001557 WMI_TIMEOUT);
1558
1559 up(&ar->sem);
1560
1561 if (left == 0)
1562 return -ETIMEDOUT;
1563 else if (left < 0)
1564 return left;
1565
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301566 if (vif->target_stats.rx_byte) {
1567 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001568 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301569 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001570 sinfo->filled |= STATION_INFO_RX_PACKETS;
1571 }
1572
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301573 if (vif->target_stats.tx_byte) {
1574 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001575 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301576 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001577 sinfo->filled |= STATION_INFO_TX_PACKETS;
1578 }
1579
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301580 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001581 sinfo->filled |= STATION_INFO_SIGNAL;
1582
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301583 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001584
1585 if (is_rate_legacy(rate)) {
1586 sinfo->txrate.legacy = rate / 100;
1587 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1588 if (sgi) {
1589 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1590 sinfo->txrate.mcs = mcs - 1;
1591 } else {
1592 sinfo->txrate.mcs = mcs;
1593 }
1594
1595 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1596 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1597 if (sgi) {
1598 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1599 sinfo->txrate.mcs = mcs - 1;
1600 } else {
1601 sinfo->txrate.mcs = mcs;
1602 }
1603
1604 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1605 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1606 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001607 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1608 "invalid rate from stats: %d\n", rate);
1609 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001610 return 0;
1611 }
1612
1613 sinfo->filled |= STATION_INFO_TX_BITRATE;
1614
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301615 if (test_bit(CONNECTED, &vif->flags) &&
1616 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301617 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001618 sinfo->filled |= STATION_INFO_BSS_PARAM;
1619 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301620 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1621 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001622 }
1623
Kalle Valobdcd8172011-07-18 00:22:30 +03001624 return 0;
1625}
1626
1627static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1628 struct cfg80211_pmksa *pmksa)
1629{
1630 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301631 struct ath6kl_vif *vif = netdev_priv(netdev);
1632
1633 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001634 pmksa->pmkid, true);
1635}
1636
1637static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1638 struct cfg80211_pmksa *pmksa)
1639{
1640 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301641 struct ath6kl_vif *vif = netdev_priv(netdev);
1642
1643 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001644 pmksa->pmkid, false);
1645}
1646
1647static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1648{
1649 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301650 struct ath6kl_vif *vif = netdev_priv(netdev);
1651
1652 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301653 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1654 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001655 return 0;
1656}
1657
Kalle Valoabcb3442011-07-22 08:26:20 +03001658#ifdef CONFIG_PM
1659static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1660 struct cfg80211_wowlan *wow)
1661{
1662 struct ath6kl *ar = wiphy_priv(wiphy);
1663
1664 return ath6kl_hif_suspend(ar);
1665}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001666
1667static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1668{
1669 struct ath6kl *ar = wiphy_priv(wiphy);
1670
1671 return ath6kl_hif_resume(ar);
1672}
Kalle Valoabcb3442011-07-22 08:26:20 +03001673#endif
1674
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001675static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1676 struct ieee80211_channel *chan,
1677 enum nl80211_channel_type channel_type)
1678{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301679 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001680
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301681 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001682 return -EIO;
1683
1684 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1685 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301686 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001687
1688 return 0;
1689}
1690
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001691static bool ath6kl_is_p2p_ie(const u8 *pos)
1692{
1693 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1694 pos[2] == 0x50 && pos[3] == 0x6f &&
1695 pos[4] == 0x9a && pos[5] == 0x09;
1696}
1697
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301698static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1699 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001700{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301701 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001702 const u8 *pos;
1703 u8 *buf = NULL;
1704 size_t len = 0;
1705 int ret;
1706
1707 /*
1708 * Filter out P2P IE(s) since they will be included depending on
1709 * the Probe Request frame in ath6kl_send_go_probe_resp().
1710 */
1711
1712 if (ies && ies_len) {
1713 buf = kmalloc(ies_len, GFP_KERNEL);
1714 if (buf == NULL)
1715 return -ENOMEM;
1716 pos = ies;
1717 while (pos + 1 < ies + ies_len) {
1718 if (pos + 2 + pos[1] > ies + ies_len)
1719 break;
1720 if (!ath6kl_is_p2p_ie(pos)) {
1721 memcpy(buf + len, pos, 2 + pos[1]);
1722 len += 2 + pos[1];
1723 }
1724 pos += 2 + pos[1];
1725 }
1726 }
1727
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301728 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1729 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001730 kfree(buf);
1731 return ret;
1732}
1733
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001734static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1735 struct beacon_parameters *info, bool add)
1736{
1737 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301738 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001739 struct ieee80211_mgmt *mgmt;
1740 u8 *ies;
1741 int ies_len;
1742 struct wmi_connect_cmd p;
1743 int res;
1744 int i;
1745
1746 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1747
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301748 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001749 return -EIO;
1750
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301751 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001752 return -EOPNOTSUPP;
1753
1754 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301755 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1756 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001757 info->beacon_ies,
1758 info->beacon_ies_len);
1759 if (res)
1760 return res;
1761 }
1762 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301763 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001764 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001765 if (res)
1766 return res;
1767 }
1768 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301769 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1770 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001771 info->assocresp_ies,
1772 info->assocresp_ies_len);
1773 if (res)
1774 return res;
1775 }
1776
1777 if (!add)
1778 return 0;
1779
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001780 ar->ap_mode_bkey.valid = false;
1781
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001782 /* TODO:
1783 * info->interval
1784 * info->dtim_period
1785 */
1786
1787 if (info->head == NULL)
1788 return -EINVAL;
1789 mgmt = (struct ieee80211_mgmt *) info->head;
1790 ies = mgmt->u.beacon.variable;
1791 if (ies > info->head + info->head_len)
1792 return -EINVAL;
1793 ies_len = info->head + info->head_len - ies;
1794
1795 if (info->ssid == NULL)
1796 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301797 memcpy(vif->ssid, info->ssid, info->ssid_len);
1798 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001799 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1800 return -EOPNOTSUPP; /* TODO */
1801
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301802 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001803
1804 memset(&p, 0, sizeof(p));
1805
1806 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1807 switch (info->crypto.akm_suites[i]) {
1808 case WLAN_AKM_SUITE_8021X:
1809 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1810 p.auth_mode |= WPA_AUTH;
1811 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1812 p.auth_mode |= WPA2_AUTH;
1813 break;
1814 case WLAN_AKM_SUITE_PSK:
1815 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1816 p.auth_mode |= WPA_PSK_AUTH;
1817 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1818 p.auth_mode |= WPA2_PSK_AUTH;
1819 break;
1820 }
1821 }
1822 if (p.auth_mode == 0)
1823 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301824 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001825
1826 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1827 switch (info->crypto.ciphers_pairwise[i]) {
1828 case WLAN_CIPHER_SUITE_WEP40:
1829 case WLAN_CIPHER_SUITE_WEP104:
1830 p.prwise_crypto_type |= WEP_CRYPT;
1831 break;
1832 case WLAN_CIPHER_SUITE_TKIP:
1833 p.prwise_crypto_type |= TKIP_CRYPT;
1834 break;
1835 case WLAN_CIPHER_SUITE_CCMP:
1836 p.prwise_crypto_type |= AES_CRYPT;
1837 break;
1838 }
1839 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001840 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001841 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301842 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001843 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301844 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001845
1846 switch (info->crypto.cipher_group) {
1847 case WLAN_CIPHER_SUITE_WEP40:
1848 case WLAN_CIPHER_SUITE_WEP104:
1849 p.grp_crypto_type = WEP_CRYPT;
1850 break;
1851 case WLAN_CIPHER_SUITE_TKIP:
1852 p.grp_crypto_type = TKIP_CRYPT;
1853 break;
1854 case WLAN_CIPHER_SUITE_CCMP:
1855 p.grp_crypto_type = AES_CRYPT;
1856 break;
1857 default:
1858 p.grp_crypto_type = NONE_CRYPT;
1859 break;
1860 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301861 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001862
1863 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301864 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001865
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301866 p.ssid_len = vif->ssid_len;
1867 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1868 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301869 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001870
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301871 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001872 if (res < 0)
1873 return res;
1874
1875 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001876}
1877
1878static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1879 struct beacon_parameters *info)
1880{
1881 return ath6kl_ap_beacon(wiphy, dev, info, true);
1882}
1883
1884static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1885 struct beacon_parameters *info)
1886{
1887 return ath6kl_ap_beacon(wiphy, dev, info, false);
1888}
1889
1890static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1891{
1892 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301893 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001894
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301895 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001896 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301897 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001898 return -ENOTCONN;
1899
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301900 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301901 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001902
1903 return 0;
1904}
1905
Jouni Malinen23875132011-08-30 21:57:53 +03001906static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1907 u8 *mac, struct station_parameters *params)
1908{
1909 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301910 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001911
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301912 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001913 return -EOPNOTSUPP;
1914
1915 /* Use this only for authorizing/unauthorizing a station */
1916 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1917 return -EOPNOTSUPP;
1918
1919 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301920 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1921 WMI_AP_MLME_AUTHORIZE, mac, 0);
1922 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1923 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03001924}
1925
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001926static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1927 struct net_device *dev,
1928 struct ieee80211_channel *chan,
1929 enum nl80211_channel_type channel_type,
1930 unsigned int duration,
1931 u64 *cookie)
1932{
1933 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301934 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001935
1936 /* TODO: if already pending or ongoing remain-on-channel,
1937 * return -EBUSY */
1938 *cookie = 1; /* only a single pending request is supported */
1939
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301940 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
1941 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001942}
1943
1944static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1945 struct net_device *dev,
1946 u64 cookie)
1947{
1948 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301949 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001950
1951 if (cookie != 1)
1952 return -ENOENT;
1953
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301954 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001955}
1956
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301957static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
1958 const u8 *buf, size_t len,
1959 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001960{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301961 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001962 const u8 *pos;
1963 u8 *p2p;
1964 int p2p_len;
1965 int ret;
1966 const struct ieee80211_mgmt *mgmt;
1967
1968 mgmt = (const struct ieee80211_mgmt *) buf;
1969
1970 /* Include P2P IE(s) from the frame generated in user space. */
1971
1972 p2p = kmalloc(len, GFP_KERNEL);
1973 if (p2p == NULL)
1974 return -ENOMEM;
1975 p2p_len = 0;
1976
1977 pos = mgmt->u.probe_resp.variable;
1978 while (pos + 1 < buf + len) {
1979 if (pos + 2 + pos[1] > buf + len)
1980 break;
1981 if (ath6kl_is_p2p_ie(pos)) {
1982 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1983 p2p_len += 2 + pos[1];
1984 }
1985 pos += 2 + pos[1];
1986 }
1987
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301988 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
1989 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001990 kfree(p2p);
1991 return ret;
1992}
1993
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001994static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1995 struct ieee80211_channel *chan, bool offchan,
1996 enum nl80211_channel_type channel_type,
1997 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001998 const u8 *buf, size_t len, bool no_cck,
1999 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002000{
2001 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302002 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002003 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002004 const struct ieee80211_mgmt *mgmt;
2005
2006 mgmt = (const struct ieee80211_mgmt *) buf;
2007 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302008 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002009 ieee80211_is_probe_resp(mgmt->frame_control)) {
2010 /*
2011 * Send Probe Response frame in AP mode using a separate WMI
2012 * command to allow the target to fill in the generic IEs.
2013 */
2014 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302015 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002016 chan->center_freq);
2017 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002018
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302019 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002020 if (id == 0) {
2021 /*
2022 * 0 is a reserved value in the WMI command and shall not be
2023 * used for the command.
2024 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302025 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002026 }
2027
2028 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302029 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2030 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002031 buf, len);
2032}
2033
Jouni Malinenae32c302011-08-30 21:58:01 +03002034static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2035 struct net_device *dev,
2036 u16 frame_type, bool reg)
2037{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302038 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002039
2040 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2041 __func__, frame_type, reg);
2042 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2043 /*
2044 * Note: This notification callback is not allowed to sleep, so
2045 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2046 * hardcode target to report Probe Request frames all the time.
2047 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302048 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002049 }
2050}
2051
Jouni Malinenf80574a2011-08-30 21:58:04 +03002052static const struct ieee80211_txrx_stypes
2053ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2054 [NL80211_IFTYPE_STATION] = {
2055 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2056 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2057 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2058 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2059 },
2060 [NL80211_IFTYPE_P2P_CLIENT] = {
2061 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2062 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2063 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2064 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2065 },
2066 [NL80211_IFTYPE_P2P_GO] = {
2067 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2068 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2069 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2070 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2071 },
2072};
2073
Kalle Valobdcd8172011-07-18 00:22:30 +03002074static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302075 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2076 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002077 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2078 .scan = ath6kl_cfg80211_scan,
2079 .connect = ath6kl_cfg80211_connect,
2080 .disconnect = ath6kl_cfg80211_disconnect,
2081 .add_key = ath6kl_cfg80211_add_key,
2082 .get_key = ath6kl_cfg80211_get_key,
2083 .del_key = ath6kl_cfg80211_del_key,
2084 .set_default_key = ath6kl_cfg80211_set_default_key,
2085 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2086 .set_tx_power = ath6kl_cfg80211_set_txpower,
2087 .get_tx_power = ath6kl_cfg80211_get_txpower,
2088 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2089 .join_ibss = ath6kl_cfg80211_join_ibss,
2090 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2091 .get_station = ath6kl_get_station,
2092 .set_pmksa = ath6kl_set_pmksa,
2093 .del_pmksa = ath6kl_del_pmksa,
2094 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002095 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002096#ifdef CONFIG_PM
2097 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002098 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002099#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002100 .set_channel = ath6kl_set_channel,
2101 .add_beacon = ath6kl_add_beacon,
2102 .set_beacon = ath6kl_set_beacon,
2103 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002104 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002105 .remain_on_channel = ath6kl_remain_on_channel,
2106 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002107 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002108 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002109};
2110
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302111struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002112{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002113 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302114 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302115 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002116
2117 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302118 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302119
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302120 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002121 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002122 return NULL;
2123 }
2124
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302125 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302126 if (!multi_norm_if_support)
2127 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302128 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302129 ar->dev = dev;
2130
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302131 if (multi_norm_if_support)
2132 ar->max_norm_iface = 2;
2133 else
2134 ar->max_norm_iface = 1;
2135
2136 /* FIXME: Remove this once the multivif support is enabled */
2137 ar->max_norm_iface = 1;
2138
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302139 spin_lock_init(&ar->lock);
2140 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302141 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302142
2143 init_waitqueue_head(&ar->event_wq);
2144 sema_init(&ar->sem, 1);
2145
2146 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302147 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302148
2149 clear_bit(WMI_ENABLED, &ar->flag);
2150 clear_bit(SKIP_SCAN, &ar->flag);
2151 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2152
2153 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2154 ar->listen_intvl_b = 0;
2155 ar->tx_pwr = 0;
2156
2157 ar->intra_bss = 1;
2158 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2159 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2160 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2161 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2162
2163 memset((u8 *)ar->sta_list, 0,
2164 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2165
2166 /* Init the PS queues */
2167 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2168 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2169 skb_queue_head_init(&ar->sta_list[ctr].psq);
2170 }
2171
2172 skb_queue_head_init(&ar->mcastpsq);
2173
2174 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2175
2176 return ar;
2177}
2178
2179int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2180{
2181 struct wiphy *wiphy = ar->wiphy;
2182 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002183
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302184 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002185
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302186 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002187
Kalle Valobdcd8172011-07-18 00:22:30 +03002188 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302189 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002190
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302191 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302192 BIT(NL80211_IFTYPE_ADHOC) |
2193 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002194 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302195 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302196 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002197 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302198
Kalle Valobdcd8172011-07-18 00:22:30 +03002199 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302200 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2201 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2202 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2203 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2204 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002205
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302206 wiphy->cipher_suites = cipher_suites;
2207 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002208
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302209 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002210 if (ret < 0) {
2211 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302212 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002213 }
2214
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302215 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002216}
2217
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302218static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002219{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302220 vif->aggr_cntxt = aggr_init(vif->ndev);
2221 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302222 ath6kl_err("failed to initialize aggr\n");
2223 return -ENOMEM;
2224 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002225
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302226 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302227 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302228 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302229 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302230
2231 return 0;
2232}
2233
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302234void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302235{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302236 struct ath6kl *ar = vif->ar;
2237
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302238 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302239
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302240 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2241
2242 if (vif->nw_type == ADHOC_NETWORK)
2243 ar->ibss_if_active = false;
2244
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302245 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302246
2247 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302248}
2249
2250struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302251 enum nl80211_iftype type, u8 fw_vif_idx,
2252 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302253{
2254 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302255 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302256
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302257 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302258 if (!ndev)
2259 return NULL;
2260
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302261 vif = netdev_priv(ndev);
2262 ndev->ieee80211_ptr = &vif->wdev;
2263 vif->wdev.wiphy = ar->wiphy;
2264 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302265 vif->ndev = ndev;
2266 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2267 vif->wdev.netdev = ndev;
2268 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302269 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302270 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302271
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302272 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2273 if (fw_vif_idx != 0)
2274 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2275 0x2;
2276
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302277 init_netdev(ndev);
2278
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302279 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302280
2281 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302282 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302283 goto err;
2284
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302285 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302286 goto err;
2287
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302288 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302289 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302290 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302291 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302292 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302293
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302294 if (type == NL80211_IFTYPE_ADHOC)
2295 ar->ibss_if_active = true;
2296
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302297 spin_lock(&ar->list_lock);
2298 list_add_tail(&vif->list, &ar->vif_list);
2299 spin_unlock(&ar->list_lock);
2300
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302301 return ndev;
2302
2303err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302304 aggr_module_destroy(vif->aggr_cntxt);
2305 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302306 return NULL;
2307}
2308
2309void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2310{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302311 wiphy_unregister(ar->wiphy);
2312 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002313}