blob: 3380dd9ce7d67084f03a4ff71bd8ba0a76f2cecf [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
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530262static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
263 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800264{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530265 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800266 const u8 *pos;
267 u8 *buf = NULL;
268 size_t len = 0;
269 int ret;
270
271 /*
272 * Filter out RSN/WPA IE(s)
273 */
274
275 if (ies && ies_len) {
276 buf = kmalloc(ies_len, GFP_KERNEL);
277 if (buf == NULL)
278 return -ENOMEM;
279 pos = ies;
280
281 while (pos + 1 < ies + ies_len) {
282 if (pos + 2 + pos[1] > ies + ies_len)
283 break;
284 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
285 memcpy(buf + len, pos, 2 + pos[1]);
286 len += 2 + pos[1];
287 }
288 pos += 2 + pos[1];
289 }
290 }
291
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530292 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
293 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800294 kfree(buf);
295 return ret;
296}
297
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530298static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
299{
300 switch (type) {
301 case NL80211_IFTYPE_STATION:
302 *nw_type = INFRA_NETWORK;
303 break;
304 case NL80211_IFTYPE_ADHOC:
305 *nw_type = ADHOC_NETWORK;
306 break;
307 case NL80211_IFTYPE_AP:
308 *nw_type = AP_NETWORK;
309 break;
310 case NL80211_IFTYPE_P2P_CLIENT:
311 *nw_type = INFRA_NETWORK;
312 break;
313 case NL80211_IFTYPE_P2P_GO:
314 *nw_type = AP_NETWORK;
315 break;
316 default:
317 ath6kl_err("invalid interface type %u\n", type);
318 return -ENOTSUPP;
319 }
320
321 return 0;
322}
323
324static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
325 u8 *if_idx, u8 *nw_type)
326{
327 int i;
328
329 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
330 return false;
331
332 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
333 ar->num_vif))
334 return false;
335
336 if (type == NL80211_IFTYPE_STATION ||
337 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
338 for (i = 0; i < MAX_NUM_VIF; i++) {
339 if ((ar->avail_idx_map >> i) & BIT(0)) {
340 *if_idx = i;
341 return true;
342 }
343 }
344 }
345
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530346 if (type == NL80211_IFTYPE_P2P_CLIENT ||
347 type == NL80211_IFTYPE_P2P_GO) {
348 for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
349 if ((ar->avail_idx_map >> i) & BIT(0)) {
350 *if_idx = i;
351 return true;
352 }
353 }
354 }
355
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530356 return false;
357}
358
Kalle Valobdcd8172011-07-18 00:22:30 +0300359static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
360 struct cfg80211_connect_params *sme)
361{
362 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530363 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300364 int status;
365
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530366 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300367
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530368 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300369 return -EIO;
370
371 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
372 ath6kl_err("destroy in progress\n");
373 return -EBUSY;
374 }
375
376 if (test_bit(SKIP_SCAN, &ar->flag) &&
377 ((sme->channel && sme->channel->center_freq == 0) ||
378 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
379 ath6kl_err("SkipScan: channel or bssid invalid\n");
380 return -EINVAL;
381 }
382
383 if (down_interruptible(&ar->sem)) {
384 ath6kl_err("busy, couldn't get access\n");
385 return -ERESTARTSYS;
386 }
387
388 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
389 ath6kl_err("busy, destroy in progress\n");
390 up(&ar->sem);
391 return -EBUSY;
392 }
393
394 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
395 /*
396 * sleep until the command queue drains
397 */
398 wait_event_interruptible_timeout(ar->event_wq,
399 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
400 WMI_TIMEOUT);
401 if (signal_pending(current)) {
402 ath6kl_err("cmd queue drain timeout\n");
403 up(&ar->sem);
404 return -EINTR;
405 }
406 }
407
Kevin Fang6981ffd2011-10-07 08:51:19 +0800408 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530409 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800410 if (status)
411 return status;
412 }
413
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530414 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530415 vif->ssid_len == sme->ssid_len &&
416 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530417 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530418 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
419 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530420 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300421
422 up(&ar->sem);
423 if (status) {
424 ath6kl_err("wmi_reconnect_cmd failed\n");
425 return -EIO;
426 }
427 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530428 } else if (vif->ssid_len == sme->ssid_len &&
429 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530430 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300431 }
432
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530433 memset(vif->ssid, 0, sizeof(vif->ssid));
434 vif->ssid_len = sme->ssid_len;
435 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300436
437 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530438 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300439
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530440 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300441 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530442 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300443
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530444 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300445
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530446 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300447 if (status) {
448 up(&ar->sem);
449 return status;
450 }
451
452 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530453 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300454 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530455 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300456
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530457 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300458
459 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530460 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300461
462 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530463 (vif->auth_mode == NONE_AUTH) &&
464 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 struct ath6kl_key *key = NULL;
466
467 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
468 sme->key_idx > WMI_MAX_KEY_INDEX) {
469 ath6kl_err("key index %d out of bounds\n",
470 sme->key_idx);
471 up(&ar->sem);
472 return -ENOENT;
473 }
474
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530475 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300476 key->key_len = sme->key_len;
477 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530478 key->cipher = vif->prwise_crypto;
479 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300480
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530481 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530482 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300483 GROUP_USAGE | TX_USAGE,
484 key->key_len,
485 NULL,
486 key->key, KEY_OP_INIT_VAL, NULL,
487 NO_SYNC_WMIFLAG);
488 }
489
490 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530491 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530492 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
493 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300494 ath6kl_err("couldn't set bss filtering\n");
495 up(&ar->sem);
496 return -EIO;
497 }
498 }
499
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530500 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300501
502 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
503 "%s: connect called with authmode %d dot11 auth %d"
504 " PW crypto %d PW crypto len %d GRP crypto %d"
505 " GRP crypto len %d channel hint %u\n",
506 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530507 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
508 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530509 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300510
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530511 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530512 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530513 vif->dot11_auth_mode, vif->auth_mode,
514 vif->prwise_crypto,
515 vif->prwise_crypto_len,
516 vif->grp_crypto, vif->grp_crypto_len,
517 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530518 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300519 ar->connect_ctrl_flags);
520
521 up(&ar->sem);
522
523 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530524 memset(vif->ssid, 0, sizeof(vif->ssid));
525 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300526 ath6kl_err("invalid request\n");
527 return -ENOENT;
528 } else if (status) {
529 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
530 return -EIO;
531 }
532
533 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530534 ((vif->auth_mode == WPA_PSK_AUTH)
535 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530536 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300537 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
538 }
539
540 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530541 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300542
543 return 0;
544}
545
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530546static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300547 struct ieee80211_channel *chan,
548 const u8 *beacon_ie, size_t beacon_ie_len)
549{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530550 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300551 struct cfg80211_bss *bss;
552 u8 *ie;
553
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530554 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530555 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300556 WLAN_CAPABILITY_ESS);
557 if (bss == NULL) {
558 /*
559 * Since cfg80211 may not yet know about the BSS,
560 * generate a partial entry until the first BSS info
561 * event becomes available.
562 *
563 * Prepend SSID element since it is not included in the Beacon
564 * IEs from the target.
565 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530566 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300567 if (ie == NULL)
568 return -ENOMEM;
569 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530570 ie[1] = vif->ssid_len;
571 memcpy(ie + 2, vif->ssid, vif->ssid_len);
572 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530573 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300574 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530575 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300576 0, GFP_KERNEL);
577 if (bss)
578 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
579 "%pM prior to indicating connect/roamed "
580 "event\n", bssid);
581 kfree(ie);
582 } else
583 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
584 "entry\n");
585
586 if (bss == NULL)
587 return -ENOMEM;
588
589 cfg80211_put_bss(bss);
590
591 return 0;
592}
593
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530594void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300595 u8 *bssid, u16 listen_intvl,
596 u16 beacon_intvl,
597 enum network_type nw_type,
598 u8 beacon_ie_len, u8 assoc_req_len,
599 u8 assoc_resp_len, u8 *assoc_info)
600{
Jouni Malinen01cac472011-09-19 19:14:59 +0300601 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530602 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300603
604 /* capinfo + listen interval */
605 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
606
607 /* capinfo + status code + associd */
608 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
609
610 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
611 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
612 assoc_resp_ie_offset;
613
614 assoc_req_len -= assoc_req_ie_offset;
615 assoc_resp_len -= assoc_resp_ie_offset;
616
Jouni Malinen32c10872011-09-19 19:15:07 +0300617 /*
618 * Store Beacon interval here; DTIM period will be available only once
619 * a Beacon frame from the AP is seen.
620 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530621 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530622 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300623
Kalle Valobdcd8172011-07-18 00:22:30 +0300624 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530625 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300626 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
627 "%s: ath6k not in ibss mode\n", __func__);
628 return;
629 }
630 }
631
632 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530633 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
634 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300635 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
636 "%s: ath6k not in station mode\n", __func__);
637 return;
638 }
639 }
640
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530641 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300642
Kalle Valobdcd8172011-07-18 00:22:30 +0300643
644 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530645 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300646 return;
647 }
648
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530649 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300650 beacon_ie_len) < 0) {
651 ath6kl_err("could not add cfg80211 bss entry for "
652 "connect/roamed notification\n");
653 return;
654 }
655
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530656 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300657 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530658 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530659 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300660 assoc_req_ie, assoc_req_len,
661 assoc_resp_ie, assoc_resp_len,
662 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530663 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530665 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300666 assoc_req_ie, assoc_req_len,
667 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
668 }
669}
670
671static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
672 struct net_device *dev, u16 reason_code)
673{
674 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530675 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300676
677 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
678 reason_code);
679
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530680 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300681 return -EIO;
682
683 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
684 ath6kl_err("busy, destroy in progress\n");
685 return -EBUSY;
686 }
687
688 if (down_interruptible(&ar->sem)) {
689 ath6kl_err("busy, couldn't get access\n");
690 return -ERESTARTSYS;
691 }
692
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530693 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530694 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530695 memset(vif->ssid, 0, sizeof(vif->ssid));
696 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300697
698 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530699 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300700
701 up(&ar->sem);
702
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530703 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530704
Kalle Valobdcd8172011-07-18 00:22:30 +0300705 return 0;
706}
707
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530708void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300709 u8 *bssid, u8 assoc_resp_len,
710 u8 *assoc_info, u16 proto_reason)
711{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530712 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530713
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530714 if (vif->scan_req) {
715 cfg80211_scan_done(vif->scan_req, true);
716 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300717 }
718
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530719 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530720 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300721 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
722 "%s: ath6k not in ibss mode\n", __func__);
723 return;
724 }
725 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 return;
728 }
729
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530730 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530731 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
732 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300733 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
734 "%s: ath6k not in station mode\n", __func__);
735 return;
736 }
737 }
738
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530739 /*
740 * Send a disconnect command to target when a disconnect event is
741 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
742 * request from host) to make the firmware stop trying to connect even
743 * after giving disconnect event. There will be one more disconnect
744 * event for this disconnect command with reason code DISCONNECT_CMD
745 * which will be notified to cfg80211.
746 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300747
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530748 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530749 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300750 return;
751 }
752
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530753 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300754
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530755 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530756 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530757 bssid, NULL, 0,
758 NULL, 0,
759 WLAN_STATUS_UNSPECIFIED_FAILURE,
760 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530761 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530762 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530763 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300764 }
765
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530766 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300767}
768
Kalle Valobdcd8172011-07-18 00:22:30 +0300769static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
770 struct cfg80211_scan_request *request)
771{
772 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530773 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300774 s8 n_channels = 0;
775 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300776 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530777 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300778
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530779 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300780 return -EIO;
781
782 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530783 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300784 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530785 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530786 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300787 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
788 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300789 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300790 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300791 }
792 }
793
794 if (request->n_ssids && request->ssids[0].ssid_len) {
795 u8 i;
796
797 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
798 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
799
800 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530801 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
802 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300803 request->ssids[i].ssid_len,
804 request->ssids[i].ssid);
805 }
806
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300807 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530808 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
809 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300810 request->ie, request->ie_len);
811 if (ret) {
812 ath6kl_err("failed to set Probe Request appie for "
813 "scan");
814 return ret;
815 }
816 }
817
Jouni Malinen11869be2011-09-02 20:07:06 +0300818 /*
819 * Scan only the requested channels if the request specifies a set of
820 * channels. If the list is longer than the target supports, do not
821 * configure the list and instead, scan all available channels.
822 */
823 if (request->n_channels > 0 &&
824 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300825 u8 i;
826
Jouni Malinen11869be2011-09-02 20:07:06 +0300827 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300828
829 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
830 if (channels == NULL) {
831 ath6kl_warn("failed to set scan channels, "
832 "scan all channels");
833 n_channels = 0;
834 }
835
836 for (i = 0; i < n_channels; i++)
837 channels[i] = request->channels[i]->center_freq;
838 }
839
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530840 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530841 force_fg_scan = 1;
842
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530843 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
844 force_fg_scan, false, 0, 0, n_channels,
845 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300846 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300847 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300848 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530849 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300850
Edward Lu1276c9e2011-08-30 21:58:00 +0300851 kfree(channels);
852
Kalle Valobdcd8172011-07-18 00:22:30 +0300853 return ret;
854}
855
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530856void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, int status)
Kalle Valobdcd8172011-07-18 00:22:30 +0300857{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530858 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300859 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300860
861 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
862
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530863 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300864 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300865
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300866 if ((status == -ECANCELED) || (status == -EBUSY)) {
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530867 cfg80211_scan_done(vif->scan_req, true);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300868 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300869 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300870
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530871 cfg80211_scan_done(vif->scan_req, false);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300872
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530873 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
874 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530875 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
876 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300877 0, NULL);
878 }
879 }
880
881out:
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530882 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300883}
884
885static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
886 u8 key_index, bool pairwise,
887 const u8 *mac_addr,
888 struct key_params *params)
889{
890 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530891 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300892 struct ath6kl_key *key = NULL;
893 u8 key_usage;
894 u8 key_type;
895 int status = 0;
896
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530897 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300898 return -EIO;
899
Jouni Malinen837cb972011-10-11 17:31:57 +0300900 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
901 if (params->key_len != WMI_KRK_LEN)
902 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530903 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
904 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300905 }
906
Kalle Valobdcd8172011-07-18 00:22:30 +0300907 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
908 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
909 "%s: key index %d out of bounds\n", __func__,
910 key_index);
911 return -ENOENT;
912 }
913
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530914 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300915 memset(key, 0, sizeof(struct ath6kl_key));
916
917 if (pairwise)
918 key_usage = PAIRWISE_USAGE;
919 else
920 key_usage = GROUP_USAGE;
921
922 if (params) {
923 if (params->key_len > WLAN_MAX_KEY_LEN ||
924 params->seq_len > sizeof(key->seq))
925 return -EINVAL;
926
927 key->key_len = params->key_len;
928 memcpy(key->key, params->key, key->key_len);
929 key->seq_len = params->seq_len;
930 memcpy(key->seq, params->seq, key->seq_len);
931 key->cipher = params->cipher;
932 }
933
934 switch (key->cipher) {
935 case WLAN_CIPHER_SUITE_WEP40:
936 case WLAN_CIPHER_SUITE_WEP104:
937 key_type = WEP_CRYPT;
938 break;
939
940 case WLAN_CIPHER_SUITE_TKIP:
941 key_type = TKIP_CRYPT;
942 break;
943
944 case WLAN_CIPHER_SUITE_CCMP:
945 key_type = AES_CRYPT;
946 break;
947
948 default:
949 return -ENOTSUPP;
950 }
951
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530952 if (((vif->auth_mode == WPA_PSK_AUTH)
953 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300954 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530955 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300956
957 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
958 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
959 __func__, key_index, key->key_len, key_type,
960 key_usage, key->seq_len);
961
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530962 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300963
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530964 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300965 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
966 ar->ap_mode_bkey.valid = true;
967 ar->ap_mode_bkey.key_index = key_index;
968 ar->ap_mode_bkey.key_type = key_type;
969 ar->ap_mode_bkey.key_len = key->key_len;
970 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530971 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300972 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
973 "key configuration until AP mode has been "
974 "started\n");
975 /*
976 * The key will be set in ath6kl_connect_ap_mode() once
977 * the connected event is received from the target.
978 */
979 return 0;
980 }
981 }
982
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530983 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530984 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300985 /*
986 * Store the key locally so that it can be re-configured after
987 * the AP mode has properly started
988 * (ath6kl_install_statioc_wep_keys).
989 */
990 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
991 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530992 vif->wep_key_list[key_index].key_len = key->key_len;
993 memcpy(vif->wep_key_list[key_index].key, key->key,
994 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +0300995 return 0;
996 }
997
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530998 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
999 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +03001000 key_type, key_usage, key->key_len,
1001 key->seq, key->key, KEY_OP_INIT_VAL,
1002 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
1003
1004 if (status)
1005 return -EIO;
1006
1007 return 0;
1008}
1009
1010static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1011 u8 key_index, bool pairwise,
1012 const u8 *mac_addr)
1013{
1014 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301015 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001016
1017 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1018
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301019 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001020 return -EIO;
1021
1022 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1023 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1024 "%s: key index %d out of bounds\n", __func__,
1025 key_index);
1026 return -ENOENT;
1027 }
1028
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301029 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001030 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1031 "%s: index %d is empty\n", __func__, key_index);
1032 return 0;
1033 }
1034
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301035 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001036
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301037 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001038}
1039
1040static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1041 u8 key_index, bool pairwise,
1042 const u8 *mac_addr, void *cookie,
1043 void (*callback) (void *cookie,
1044 struct key_params *))
1045{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301046 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001047 struct ath6kl_key *key = NULL;
1048 struct key_params params;
1049
1050 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1051
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301052 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001053 return -EIO;
1054
1055 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1056 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1057 "%s: key index %d out of bounds\n", __func__,
1058 key_index);
1059 return -ENOENT;
1060 }
1061
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301062 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001063 memset(&params, 0, sizeof(params));
1064 params.cipher = key->cipher;
1065 params.key_len = key->key_len;
1066 params.seq_len = key->seq_len;
1067 params.seq = key->seq;
1068 params.key = key->key;
1069
1070 callback(cookie, &params);
1071
1072 return key->key_len ? 0 : -ENOENT;
1073}
1074
1075static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1076 struct net_device *ndev,
1077 u8 key_index, bool unicast,
1078 bool multicast)
1079{
1080 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301081 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001082 struct ath6kl_key *key = NULL;
1083 int status = 0;
1084 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001085 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001086
1087 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1088
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301089 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001090 return -EIO;
1091
1092 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1093 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1094 "%s: key index %d out of bounds\n",
1095 __func__, key_index);
1096 return -ENOENT;
1097 }
1098
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301099 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001100 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1101 __func__, key_index);
1102 return -EINVAL;
1103 }
1104
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301105 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301106 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001107 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301108 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001109 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001110 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301111 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001112 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301113 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001114
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301115 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001116 return 0; /* Delay until AP mode has been started */
1117
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301118 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1119 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001120 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001121 key->key_len, key->seq, key->key,
1122 KEY_OP_INIT_VAL, NULL,
1123 SYNC_BOTH_WMIFLAG);
1124 if (status)
1125 return -EIO;
1126
1127 return 0;
1128}
1129
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301130void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001131 bool ismcast)
1132{
1133 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1134 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1135
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301136 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001137 (ismcast ? NL80211_KEYTYPE_GROUP :
1138 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1139 GFP_KERNEL);
1140}
1141
1142static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1143{
1144 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301145 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001146 int ret;
1147
1148 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1149 changed);
1150
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301151 vif = ath6kl_vif_first(ar);
1152 if (!vif)
1153 return -EIO;
1154
1155 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001156 return -EIO;
1157
1158 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1159 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1160 if (ret != 0) {
1161 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1162 return -EIO;
1163 }
1164 }
1165
1166 return 0;
1167}
1168
1169/*
1170 * The type nl80211_tx_power_setting replaces the following
1171 * data type from 2.6.36 onwards
1172*/
1173static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1174 enum nl80211_tx_power_setting type,
1175 int dbm)
1176{
1177 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301178 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001179 u8 ath6kl_dbm;
1180
1181 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1182 type, dbm);
1183
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301184 vif = ath6kl_vif_first(ar);
1185 if (!vif)
1186 return -EIO;
1187
1188 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001189 return -EIO;
1190
1191 switch (type) {
1192 case NL80211_TX_POWER_AUTOMATIC:
1193 return 0;
1194 case NL80211_TX_POWER_LIMITED:
1195 ar->tx_pwr = ath6kl_dbm = dbm;
1196 break;
1197 default:
1198 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1199 __func__, type);
1200 return -EOPNOTSUPP;
1201 }
1202
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301203 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001204
1205 return 0;
1206}
1207
1208static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1209{
1210 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301211 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001212
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301213 vif = ath6kl_vif_first(ar);
1214 if (!vif)
1215 return -EIO;
1216
1217 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001218 return -EIO;
1219
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301220 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001221 ar->tx_pwr = 0;
1222
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301223 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001224 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1225 return -EIO;
1226 }
1227
1228 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1229 5 * HZ);
1230
1231 if (signal_pending(current)) {
1232 ath6kl_err("target did not respond\n");
1233 return -EINTR;
1234 }
1235 }
1236
1237 *dbm = ar->tx_pwr;
1238 return 0;
1239}
1240
1241static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1242 struct net_device *dev,
1243 bool pmgmt, int timeout)
1244{
1245 struct ath6kl *ar = ath6kl_priv(dev);
1246 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301247 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001248
1249 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1250 __func__, pmgmt, timeout);
1251
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301252 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001253 return -EIO;
1254
1255 if (pmgmt) {
1256 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1257 mode.pwr_mode = REC_POWER;
1258 } else {
1259 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1260 mode.pwr_mode = MAX_PERF_POWER;
1261 }
1262
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301263 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1264 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001265 ath6kl_err("wmi_powermode_cmd failed\n");
1266 return -EIO;
1267 }
1268
1269 return 0;
1270}
1271
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301272static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1273 char *name,
1274 enum nl80211_iftype type,
1275 u32 *flags,
1276 struct vif_params *params)
1277{
1278 struct ath6kl *ar = wiphy_priv(wiphy);
1279 struct net_device *ndev;
1280 u8 if_idx, nw_type;
1281
1282 if (ar->num_vif == MAX_NUM_VIF) {
1283 ath6kl_err("Reached maximum number of supported vif\n");
1284 return ERR_PTR(-EINVAL);
1285 }
1286
1287 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1288 ath6kl_err("Not a supported interface type\n");
1289 return ERR_PTR(-EINVAL);
1290 }
1291
1292 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1293 if (!ndev)
1294 return ERR_PTR(-ENOMEM);
1295
1296 ar->num_vif++;
1297
1298 return ndev;
1299}
1300
1301static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1302 struct net_device *ndev)
1303{
1304 struct ath6kl *ar = wiphy_priv(wiphy);
1305 struct ath6kl_vif *vif = netdev_priv(ndev);
1306
1307 spin_lock(&ar->list_lock);
1308 list_del(&vif->list);
1309 spin_unlock(&ar->list_lock);
1310
1311 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1312
1313 ath6kl_deinit_if_data(vif);
1314
1315 return 0;
1316}
1317
Kalle Valobdcd8172011-07-18 00:22:30 +03001318static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1319 struct net_device *ndev,
1320 enum nl80211_iftype type, u32 *flags,
1321 struct vif_params *params)
1322{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301323 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001324
1325 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1326
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301327 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001328 return -EIO;
1329
1330 switch (type) {
1331 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301332 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001333 break;
1334 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301335 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001336 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001337 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301338 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001339 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001340 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301341 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001342 break;
1343 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301344 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001345 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001346 default:
1347 ath6kl_err("invalid interface type %u\n", type);
1348 return -EOPNOTSUPP;
1349 }
1350
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301351 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001352
1353 return 0;
1354}
1355
1356static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1357 struct net_device *dev,
1358 struct cfg80211_ibss_params *ibss_param)
1359{
1360 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301361 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001362 int status;
1363
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301364 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001365 return -EIO;
1366
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301367 vif->ssid_len = ibss_param->ssid_len;
1368 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001369
1370 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301371 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001372
1373 if (ibss_param->channel_fixed) {
1374 /*
1375 * TODO: channel_fixed: The channel should be fixed, do not
1376 * search for IBSSs to join on other channels. Target
1377 * firmware does not support this feature, needs to be
1378 * updated.
1379 */
1380 return -EOPNOTSUPP;
1381 }
1382
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301383 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001384 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301385 memcpy(vif->req_bssid, ibss_param->bssid,
1386 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001387
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301388 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001389
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301390 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001391 if (status)
1392 return status;
1393
1394 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301395 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1396 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001397 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301398 ath6kl_set_cipher(vif, 0, true);
1399 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001400 }
1401
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301402 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001403
1404 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1405 "%s: connect called with authmode %d dot11 auth %d"
1406 " PW crypto %d PW crypto len %d GRP crypto %d"
1407 " GRP crypto len %d channel hint %u\n",
1408 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301409 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1410 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301411 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001412
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301413 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301414 vif->dot11_auth_mode, vif->auth_mode,
1415 vif->prwise_crypto,
1416 vif->prwise_crypto_len,
1417 vif->grp_crypto, vif->grp_crypto_len,
1418 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301419 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001420 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301421 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001422
1423 return 0;
1424}
1425
1426static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1427 struct net_device *dev)
1428{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301429 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001430
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301431 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001432 return -EIO;
1433
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301434 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301435 memset(vif->ssid, 0, sizeof(vif->ssid));
1436 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001437
1438 return 0;
1439}
1440
1441static const u32 cipher_suites[] = {
1442 WLAN_CIPHER_SUITE_WEP40,
1443 WLAN_CIPHER_SUITE_WEP104,
1444 WLAN_CIPHER_SUITE_TKIP,
1445 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001446 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001447};
1448
1449static bool is_rate_legacy(s32 rate)
1450{
1451 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1452 6000, 9000, 12000, 18000, 24000,
1453 36000, 48000, 54000
1454 };
1455 u8 i;
1456
1457 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1458 if (rate == legacy[i])
1459 return true;
1460
1461 return false;
1462}
1463
1464static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1465{
1466 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1467 52000, 58500, 65000, 72200
1468 };
1469 u8 i;
1470
1471 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1472 if (rate == ht20[i]) {
1473 if (i == ARRAY_SIZE(ht20) - 1)
1474 /* last rate uses sgi */
1475 *sgi = true;
1476 else
1477 *sgi = false;
1478
1479 *mcs = i;
1480 return true;
1481 }
1482 }
1483 return false;
1484}
1485
1486static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1487{
1488 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1489 81000, 108000, 121500, 135000,
1490 150000
1491 };
1492 u8 i;
1493
1494 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1495 if (rate == ht40[i]) {
1496 if (i == ARRAY_SIZE(ht40) - 1)
1497 /* last rate uses sgi */
1498 *sgi = true;
1499 else
1500 *sgi = false;
1501
1502 *mcs = i;
1503 return true;
1504 }
1505 }
1506
1507 return false;
1508}
1509
1510static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1511 u8 *mac, struct station_info *sinfo)
1512{
1513 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301514 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001515 long left;
1516 bool sgi;
1517 s32 rate;
1518 int ret;
1519 u8 mcs;
1520
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301521 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001522 return -ENOENT;
1523
1524 if (down_interruptible(&ar->sem))
1525 return -EBUSY;
1526
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301527 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001528
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301529 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001530
1531 if (ret != 0) {
1532 up(&ar->sem);
1533 return -EIO;
1534 }
1535
1536 left = wait_event_interruptible_timeout(ar->event_wq,
1537 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301538 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001539 WMI_TIMEOUT);
1540
1541 up(&ar->sem);
1542
1543 if (left == 0)
1544 return -ETIMEDOUT;
1545 else if (left < 0)
1546 return left;
1547
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301548 if (vif->target_stats.rx_byte) {
1549 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001550 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301551 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001552 sinfo->filled |= STATION_INFO_RX_PACKETS;
1553 }
1554
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301555 if (vif->target_stats.tx_byte) {
1556 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001557 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301558 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001559 sinfo->filled |= STATION_INFO_TX_PACKETS;
1560 }
1561
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301562 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001563 sinfo->filled |= STATION_INFO_SIGNAL;
1564
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301565 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001566
1567 if (is_rate_legacy(rate)) {
1568 sinfo->txrate.legacy = rate / 100;
1569 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1570 if (sgi) {
1571 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1572 sinfo->txrate.mcs = mcs - 1;
1573 } else {
1574 sinfo->txrate.mcs = mcs;
1575 }
1576
1577 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1578 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1579 if (sgi) {
1580 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1581 sinfo->txrate.mcs = mcs - 1;
1582 } else {
1583 sinfo->txrate.mcs = mcs;
1584 }
1585
1586 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1587 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1588 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001589 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1590 "invalid rate from stats: %d\n", rate);
1591 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001592 return 0;
1593 }
1594
1595 sinfo->filled |= STATION_INFO_TX_BITRATE;
1596
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301597 if (test_bit(CONNECTED, &vif->flags) &&
1598 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301599 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001600 sinfo->filled |= STATION_INFO_BSS_PARAM;
1601 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301602 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1603 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001604 }
1605
Kalle Valobdcd8172011-07-18 00:22:30 +03001606 return 0;
1607}
1608
1609static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1610 struct cfg80211_pmksa *pmksa)
1611{
1612 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301613 struct ath6kl_vif *vif = netdev_priv(netdev);
1614
1615 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001616 pmksa->pmkid, true);
1617}
1618
1619static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1620 struct cfg80211_pmksa *pmksa)
1621{
1622 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301623 struct ath6kl_vif *vif = netdev_priv(netdev);
1624
1625 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001626 pmksa->pmkid, false);
1627}
1628
1629static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1630{
1631 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301632 struct ath6kl_vif *vif = netdev_priv(netdev);
1633
1634 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301635 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1636 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001637 return 0;
1638}
1639
Kalle Valoabcb3442011-07-22 08:26:20 +03001640#ifdef CONFIG_PM
1641static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1642 struct cfg80211_wowlan *wow)
1643{
1644 struct ath6kl *ar = wiphy_priv(wiphy);
1645
1646 return ath6kl_hif_suspend(ar);
1647}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001648
1649static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1650{
1651 struct ath6kl *ar = wiphy_priv(wiphy);
1652
1653 return ath6kl_hif_resume(ar);
1654}
Kalle Valoabcb3442011-07-22 08:26:20 +03001655#endif
1656
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001657static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1658 struct ieee80211_channel *chan,
1659 enum nl80211_channel_type channel_type)
1660{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301661 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001662
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301663 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001664 return -EIO;
1665
1666 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1667 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301668 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001669
1670 return 0;
1671}
1672
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001673static bool ath6kl_is_p2p_ie(const u8 *pos)
1674{
1675 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1676 pos[2] == 0x50 && pos[3] == 0x6f &&
1677 pos[4] == 0x9a && pos[5] == 0x09;
1678}
1679
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301680static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1681 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001682{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301683 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001684 const u8 *pos;
1685 u8 *buf = NULL;
1686 size_t len = 0;
1687 int ret;
1688
1689 /*
1690 * Filter out P2P IE(s) since they will be included depending on
1691 * the Probe Request frame in ath6kl_send_go_probe_resp().
1692 */
1693
1694 if (ies && ies_len) {
1695 buf = kmalloc(ies_len, GFP_KERNEL);
1696 if (buf == NULL)
1697 return -ENOMEM;
1698 pos = ies;
1699 while (pos + 1 < ies + ies_len) {
1700 if (pos + 2 + pos[1] > ies + ies_len)
1701 break;
1702 if (!ath6kl_is_p2p_ie(pos)) {
1703 memcpy(buf + len, pos, 2 + pos[1]);
1704 len += 2 + pos[1];
1705 }
1706 pos += 2 + pos[1];
1707 }
1708 }
1709
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301710 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1711 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001712 kfree(buf);
1713 return ret;
1714}
1715
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001716static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1717 struct beacon_parameters *info, bool add)
1718{
1719 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301720 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001721 struct ieee80211_mgmt *mgmt;
1722 u8 *ies;
1723 int ies_len;
1724 struct wmi_connect_cmd p;
1725 int res;
1726 int i;
1727
1728 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1729
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301730 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001731 return -EIO;
1732
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301733 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001734 return -EOPNOTSUPP;
1735
1736 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301737 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1738 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001739 info->beacon_ies,
1740 info->beacon_ies_len);
1741 if (res)
1742 return res;
1743 }
1744 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301745 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001746 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001747 if (res)
1748 return res;
1749 }
1750 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301751 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1752 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001753 info->assocresp_ies,
1754 info->assocresp_ies_len);
1755 if (res)
1756 return res;
1757 }
1758
1759 if (!add)
1760 return 0;
1761
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001762 ar->ap_mode_bkey.valid = false;
1763
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001764 /* TODO:
1765 * info->interval
1766 * info->dtim_period
1767 */
1768
1769 if (info->head == NULL)
1770 return -EINVAL;
1771 mgmt = (struct ieee80211_mgmt *) info->head;
1772 ies = mgmt->u.beacon.variable;
1773 if (ies > info->head + info->head_len)
1774 return -EINVAL;
1775 ies_len = info->head + info->head_len - ies;
1776
1777 if (info->ssid == NULL)
1778 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301779 memcpy(vif->ssid, info->ssid, info->ssid_len);
1780 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001781 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1782 return -EOPNOTSUPP; /* TODO */
1783
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301784 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001785
1786 memset(&p, 0, sizeof(p));
1787
1788 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1789 switch (info->crypto.akm_suites[i]) {
1790 case WLAN_AKM_SUITE_8021X:
1791 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1792 p.auth_mode |= WPA_AUTH;
1793 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1794 p.auth_mode |= WPA2_AUTH;
1795 break;
1796 case WLAN_AKM_SUITE_PSK:
1797 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1798 p.auth_mode |= WPA_PSK_AUTH;
1799 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1800 p.auth_mode |= WPA2_PSK_AUTH;
1801 break;
1802 }
1803 }
1804 if (p.auth_mode == 0)
1805 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301806 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001807
1808 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1809 switch (info->crypto.ciphers_pairwise[i]) {
1810 case WLAN_CIPHER_SUITE_WEP40:
1811 case WLAN_CIPHER_SUITE_WEP104:
1812 p.prwise_crypto_type |= WEP_CRYPT;
1813 break;
1814 case WLAN_CIPHER_SUITE_TKIP:
1815 p.prwise_crypto_type |= TKIP_CRYPT;
1816 break;
1817 case WLAN_CIPHER_SUITE_CCMP:
1818 p.prwise_crypto_type |= AES_CRYPT;
1819 break;
1820 }
1821 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001822 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001823 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301824 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001825 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301826 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001827
1828 switch (info->crypto.cipher_group) {
1829 case WLAN_CIPHER_SUITE_WEP40:
1830 case WLAN_CIPHER_SUITE_WEP104:
1831 p.grp_crypto_type = WEP_CRYPT;
1832 break;
1833 case WLAN_CIPHER_SUITE_TKIP:
1834 p.grp_crypto_type = TKIP_CRYPT;
1835 break;
1836 case WLAN_CIPHER_SUITE_CCMP:
1837 p.grp_crypto_type = AES_CRYPT;
1838 break;
1839 default:
1840 p.grp_crypto_type = NONE_CRYPT;
1841 break;
1842 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301843 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001844
1845 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301846 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001847
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301848 p.ssid_len = vif->ssid_len;
1849 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1850 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301851 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001852
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301853 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001854 if (res < 0)
1855 return res;
1856
1857 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001858}
1859
1860static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1861 struct beacon_parameters *info)
1862{
1863 return ath6kl_ap_beacon(wiphy, dev, info, true);
1864}
1865
1866static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1867 struct beacon_parameters *info)
1868{
1869 return ath6kl_ap_beacon(wiphy, dev, info, false);
1870}
1871
1872static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1873{
1874 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301875 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001876
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301877 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001878 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301879 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001880 return -ENOTCONN;
1881
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301882 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301883 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001884
1885 return 0;
1886}
1887
Jouni Malinen23875132011-08-30 21:57:53 +03001888static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1889 u8 *mac, struct station_parameters *params)
1890{
1891 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301892 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001893
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301894 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001895 return -EOPNOTSUPP;
1896
1897 /* Use this only for authorizing/unauthorizing a station */
1898 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1899 return -EOPNOTSUPP;
1900
1901 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301902 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1903 WMI_AP_MLME_AUTHORIZE, mac, 0);
1904 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1905 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03001906}
1907
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001908static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1909 struct net_device *dev,
1910 struct ieee80211_channel *chan,
1911 enum nl80211_channel_type channel_type,
1912 unsigned int duration,
1913 u64 *cookie)
1914{
1915 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301916 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001917
1918 /* TODO: if already pending or ongoing remain-on-channel,
1919 * return -EBUSY */
1920 *cookie = 1; /* only a single pending request is supported */
1921
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301922 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
1923 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001924}
1925
1926static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1927 struct net_device *dev,
1928 u64 cookie)
1929{
1930 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301931 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001932
1933 if (cookie != 1)
1934 return -ENOENT;
1935
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301936 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001937}
1938
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301939static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
1940 const u8 *buf, size_t len,
1941 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001942{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301943 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001944 const u8 *pos;
1945 u8 *p2p;
1946 int p2p_len;
1947 int ret;
1948 const struct ieee80211_mgmt *mgmt;
1949
1950 mgmt = (const struct ieee80211_mgmt *) buf;
1951
1952 /* Include P2P IE(s) from the frame generated in user space. */
1953
1954 p2p = kmalloc(len, GFP_KERNEL);
1955 if (p2p == NULL)
1956 return -ENOMEM;
1957 p2p_len = 0;
1958
1959 pos = mgmt->u.probe_resp.variable;
1960 while (pos + 1 < buf + len) {
1961 if (pos + 2 + pos[1] > buf + len)
1962 break;
1963 if (ath6kl_is_p2p_ie(pos)) {
1964 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1965 p2p_len += 2 + pos[1];
1966 }
1967 pos += 2 + pos[1];
1968 }
1969
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301970 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
1971 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001972 kfree(p2p);
1973 return ret;
1974}
1975
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001976static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1977 struct ieee80211_channel *chan, bool offchan,
1978 enum nl80211_channel_type channel_type,
1979 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001980 const u8 *buf, size_t len, bool no_cck,
1981 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001982{
1983 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301984 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001985 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001986 const struct ieee80211_mgmt *mgmt;
1987
1988 mgmt = (const struct ieee80211_mgmt *) buf;
1989 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301990 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001991 ieee80211_is_probe_resp(mgmt->frame_control)) {
1992 /*
1993 * Send Probe Response frame in AP mode using a separate WMI
1994 * command to allow the target to fill in the generic IEs.
1995 */
1996 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301997 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001998 chan->center_freq);
1999 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002000
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302001 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002002 if (id == 0) {
2003 /*
2004 * 0 is a reserved value in the WMI command and shall not be
2005 * used for the command.
2006 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302007 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002008 }
2009
2010 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302011 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2012 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002013 buf, len);
2014}
2015
Jouni Malinenae32c302011-08-30 21:58:01 +03002016static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2017 struct net_device *dev,
2018 u16 frame_type, bool reg)
2019{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302020 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002021
2022 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2023 __func__, frame_type, reg);
2024 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2025 /*
2026 * Note: This notification callback is not allowed to sleep, so
2027 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2028 * hardcode target to report Probe Request frames all the time.
2029 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302030 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002031 }
2032}
2033
Jouni Malinenf80574a2011-08-30 21:58:04 +03002034static const struct ieee80211_txrx_stypes
2035ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2036 [NL80211_IFTYPE_STATION] = {
2037 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2038 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2039 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2040 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2041 },
2042 [NL80211_IFTYPE_P2P_CLIENT] = {
2043 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2044 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2045 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2046 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2047 },
2048 [NL80211_IFTYPE_P2P_GO] = {
2049 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2050 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2051 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2052 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2053 },
2054};
2055
Kalle Valobdcd8172011-07-18 00:22:30 +03002056static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302057 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2058 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002059 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2060 .scan = ath6kl_cfg80211_scan,
2061 .connect = ath6kl_cfg80211_connect,
2062 .disconnect = ath6kl_cfg80211_disconnect,
2063 .add_key = ath6kl_cfg80211_add_key,
2064 .get_key = ath6kl_cfg80211_get_key,
2065 .del_key = ath6kl_cfg80211_del_key,
2066 .set_default_key = ath6kl_cfg80211_set_default_key,
2067 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2068 .set_tx_power = ath6kl_cfg80211_set_txpower,
2069 .get_tx_power = ath6kl_cfg80211_get_txpower,
2070 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2071 .join_ibss = ath6kl_cfg80211_join_ibss,
2072 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2073 .get_station = ath6kl_get_station,
2074 .set_pmksa = ath6kl_set_pmksa,
2075 .del_pmksa = ath6kl_del_pmksa,
2076 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002077 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002078#ifdef CONFIG_PM
2079 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002080 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002081#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002082 .set_channel = ath6kl_set_channel,
2083 .add_beacon = ath6kl_add_beacon,
2084 .set_beacon = ath6kl_set_beacon,
2085 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002086 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002087 .remain_on_channel = ath6kl_remain_on_channel,
2088 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002089 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002090 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002091};
2092
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302093struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002094{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002095 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302096 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302097 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002098
2099 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302100 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302101
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302102 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002103 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002104 return NULL;
2105 }
2106
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302107 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302108 if (!multi_norm_if_support)
2109 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302110 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302111 ar->dev = dev;
2112
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302113 if (multi_norm_if_support)
2114 ar->max_norm_iface = 2;
2115 else
2116 ar->max_norm_iface = 1;
2117
2118 /* FIXME: Remove this once the multivif support is enabled */
2119 ar->max_norm_iface = 1;
2120
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302121 spin_lock_init(&ar->lock);
2122 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302123 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302124
2125 init_waitqueue_head(&ar->event_wq);
2126 sema_init(&ar->sem, 1);
2127
2128 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302129 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302130
2131 clear_bit(WMI_ENABLED, &ar->flag);
2132 clear_bit(SKIP_SCAN, &ar->flag);
2133 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2134
2135 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2136 ar->listen_intvl_b = 0;
2137 ar->tx_pwr = 0;
2138
2139 ar->intra_bss = 1;
2140 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2141 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2142 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2143 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2144
2145 memset((u8 *)ar->sta_list, 0,
2146 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2147
2148 /* Init the PS queues */
2149 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2150 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2151 skb_queue_head_init(&ar->sta_list[ctr].psq);
2152 }
2153
2154 skb_queue_head_init(&ar->mcastpsq);
2155
2156 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2157
2158 return ar;
2159}
2160
2161int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2162{
2163 struct wiphy *wiphy = ar->wiphy;
2164 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002165
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302166 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002167
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302168 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002169
Kalle Valobdcd8172011-07-18 00:22:30 +03002170 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302171 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002172
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302173 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302174 BIT(NL80211_IFTYPE_ADHOC) |
2175 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002176 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302177 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302178 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002179 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302180
Kalle Valobdcd8172011-07-18 00:22:30 +03002181 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302182 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2183 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2184 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2185 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2186 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002187
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302188 wiphy->cipher_suites = cipher_suites;
2189 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002190
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302191 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002192 if (ret < 0) {
2193 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302194 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002195 }
2196
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302197 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002198}
2199
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302200static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002201{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302202 vif->aggr_cntxt = aggr_init(vif->ndev);
2203 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302204 ath6kl_err("failed to initialize aggr\n");
2205 return -ENOMEM;
2206 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002207
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302208 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302209 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302210 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302211 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302212
2213 return 0;
2214}
2215
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302216void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302217{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302218 struct ath6kl *ar = vif->ar;
2219
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302220 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302221
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302222 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2223
2224 if (vif->nw_type == ADHOC_NETWORK)
2225 ar->ibss_if_active = false;
2226
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302227 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302228
2229 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302230}
2231
2232struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302233 enum nl80211_iftype type, u8 fw_vif_idx,
2234 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302235{
2236 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302237 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302238
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302239 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302240 if (!ndev)
2241 return NULL;
2242
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302243 vif = netdev_priv(ndev);
2244 ndev->ieee80211_ptr = &vif->wdev;
2245 vif->wdev.wiphy = ar->wiphy;
2246 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302247 vif->ndev = ndev;
2248 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2249 vif->wdev.netdev = ndev;
2250 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302251 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302252 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302253
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302254 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2255 if (fw_vif_idx != 0)
2256 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2257 0x2;
2258
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302259 init_netdev(ndev);
2260
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302261 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302262
2263 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302264 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302265 goto err;
2266
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302267 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302268 goto err;
2269
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302270 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302271 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302272 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302273 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302274 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302275
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302276 if (type == NL80211_IFTYPE_ADHOC)
2277 ar->ibss_if_active = true;
2278
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302279 spin_lock(&ar->list_lock);
2280 list_add_tail(&vif->list, &ar->vif_list);
2281 spin_unlock(&ar->list_lock);
2282
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302283 return ndev;
2284
2285err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302286 aggr_module_destroy(vif->aggr_cntxt);
2287 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302288 return NULL;
2289}
2290
2291void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2292{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302293 wiphy_unregister(ar->wiphy);
2294 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002295}