blob: 4d1394a3dc190b66147ebb506c22e0c1e1261968 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053024static unsigned int multi_norm_if_support;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030025
26module_param(ath6kl_p2p, uint, 0644);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +053027module_param(multi_norm_if_support, uint, 0644);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030028
Kalle Valobdcd8172011-07-18 00:22:30 +030029#define RATETAB_ENT(_rate, _rateid, _flags) { \
30 .bitrate = (_rate), \
31 .flags = (_flags), \
32 .hw_value = (_rateid), \
33}
34
35#define CHAN2G(_channel, _freq, _flags) { \
36 .band = IEEE80211_BAND_2GHZ, \
37 .hw_value = (_channel), \
38 .center_freq = (_freq), \
39 .flags = (_flags), \
40 .max_antenna_gain = 0, \
41 .max_power = 30, \
42}
43
44#define CHAN5G(_channel, _flags) { \
45 .band = IEEE80211_BAND_5GHZ, \
46 .hw_value = (_channel), \
47 .center_freq = 5000 + (5 * (_channel)), \
48 .flags = (_flags), \
49 .max_antenna_gain = 0, \
50 .max_power = 30, \
51}
52
53static struct ieee80211_rate ath6kl_rates[] = {
54 RATETAB_ENT(10, 0x1, 0),
55 RATETAB_ENT(20, 0x2, 0),
56 RATETAB_ENT(55, 0x4, 0),
57 RATETAB_ENT(110, 0x8, 0),
58 RATETAB_ENT(60, 0x10, 0),
59 RATETAB_ENT(90, 0x20, 0),
60 RATETAB_ENT(120, 0x40, 0),
61 RATETAB_ENT(180, 0x80, 0),
62 RATETAB_ENT(240, 0x100, 0),
63 RATETAB_ENT(360, 0x200, 0),
64 RATETAB_ENT(480, 0x400, 0),
65 RATETAB_ENT(540, 0x800, 0),
66};
67
68#define ath6kl_a_rates (ath6kl_rates + 4)
69#define ath6kl_a_rates_size 8
70#define ath6kl_g_rates (ath6kl_rates + 0)
71#define ath6kl_g_rates_size 12
72
73static struct ieee80211_channel ath6kl_2ghz_channels[] = {
74 CHAN2G(1, 2412, 0),
75 CHAN2G(2, 2417, 0),
76 CHAN2G(3, 2422, 0),
77 CHAN2G(4, 2427, 0),
78 CHAN2G(5, 2432, 0),
79 CHAN2G(6, 2437, 0),
80 CHAN2G(7, 2442, 0),
81 CHAN2G(8, 2447, 0),
82 CHAN2G(9, 2452, 0),
83 CHAN2G(10, 2457, 0),
84 CHAN2G(11, 2462, 0),
85 CHAN2G(12, 2467, 0),
86 CHAN2G(13, 2472, 0),
87 CHAN2G(14, 2484, 0),
88};
89
90static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
91 CHAN5G(34, 0), CHAN5G(36, 0),
92 CHAN5G(38, 0), CHAN5G(40, 0),
93 CHAN5G(42, 0), CHAN5G(44, 0),
94 CHAN5G(46, 0), CHAN5G(48, 0),
95 CHAN5G(52, 0), CHAN5G(56, 0),
96 CHAN5G(60, 0), CHAN5G(64, 0),
97 CHAN5G(100, 0), CHAN5G(104, 0),
98 CHAN5G(108, 0), CHAN5G(112, 0),
99 CHAN5G(116, 0), CHAN5G(120, 0),
100 CHAN5G(124, 0), CHAN5G(128, 0),
101 CHAN5G(132, 0), CHAN5G(136, 0),
102 CHAN5G(140, 0), CHAN5G(149, 0),
103 CHAN5G(153, 0), CHAN5G(157, 0),
104 CHAN5G(161, 0), CHAN5G(165, 0),
105 CHAN5G(184, 0), CHAN5G(188, 0),
106 CHAN5G(192, 0), CHAN5G(196, 0),
107 CHAN5G(200, 0), CHAN5G(204, 0),
108 CHAN5G(208, 0), CHAN5G(212, 0),
109 CHAN5G(216, 0),
110};
111
112static struct ieee80211_supported_band ath6kl_band_2ghz = {
113 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
114 .channels = ath6kl_2ghz_channels,
115 .n_bitrates = ath6kl_g_rates_size,
116 .bitrates = ath6kl_g_rates,
117};
118
119static struct ieee80211_supported_band ath6kl_band_5ghz = {
120 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
121 .channels = ath6kl_5ghz_a_channels,
122 .n_bitrates = ath6kl_a_rates_size,
123 .bitrates = ath6kl_a_rates,
124};
125
Jouni Malinen837cb972011-10-11 17:31:57 +0300126#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
127
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530128static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300129 enum nl80211_wpa_versions wpa_version)
130{
131 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
132
133 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530134 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300135 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530136 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300137 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530138 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300139 } else {
140 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
141 return -ENOTSUPP;
142 }
143
144 return 0;
145}
146
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530147static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300148 enum nl80211_auth_type auth_type)
149{
Kalle Valobdcd8172011-07-18 00:22:30 +0300150 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
151
152 switch (auth_type) {
153 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530154 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300155 break;
156 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530157 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300158 break;
159 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530160 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300161 break;
162
163 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530164 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 break;
166
167 default:
168 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
169 return -ENOTSUPP;
170 }
171
172 return 0;
173}
174
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530175static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300176{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530177 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
178 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
179 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300180
181 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
182 __func__, cipher, ucast);
183
184 switch (cipher) {
185 case 0:
186 /* our own hack to use value 0 as no crypto used */
187 *ar_cipher = NONE_CRYPT;
188 *ar_cipher_len = 0;
189 break;
190 case WLAN_CIPHER_SUITE_WEP40:
191 *ar_cipher = WEP_CRYPT;
192 *ar_cipher_len = 5;
193 break;
194 case WLAN_CIPHER_SUITE_WEP104:
195 *ar_cipher = WEP_CRYPT;
196 *ar_cipher_len = 13;
197 break;
198 case WLAN_CIPHER_SUITE_TKIP:
199 *ar_cipher = TKIP_CRYPT;
200 *ar_cipher_len = 0;
201 break;
202 case WLAN_CIPHER_SUITE_CCMP:
203 *ar_cipher = AES_CRYPT;
204 *ar_cipher_len = 0;
205 break;
206 default:
207 ath6kl_err("cipher 0x%x not supported\n", cipher);
208 return -ENOTSUPP;
209 }
210
211 return 0;
212}
213
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530214static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300215{
216 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
217
218 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530219 if (vif->auth_mode == WPA_AUTH)
220 vif->auth_mode = WPA_PSK_AUTH;
221 else if (vif->auth_mode == WPA2_AUTH)
222 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300223 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530224 if (vif->auth_mode == WPA_AUTH)
225 vif->auth_mode = WPA_AUTH_CCKM;
226 else if (vif->auth_mode == WPA2_AUTH)
227 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300228 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530229 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300230 }
231}
232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530233static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300234{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530235 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530236
Kalle Valobdcd8172011-07-18 00:22:30 +0300237 if (!test_bit(WMI_READY, &ar->flag)) {
238 ath6kl_err("wmi is not ready\n");
239 return false;
240 }
241
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530242 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300243 ath6kl_err("wlan disabled\n");
244 return false;
245 }
246
247 return true;
248}
249
Kevin Fang6981ffd2011-10-07 08:51:19 +0800250static bool ath6kl_is_wpa_ie(const u8 *pos)
251{
252 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
253 pos[2] == 0x00 && pos[3] == 0x50 &&
254 pos[4] == 0xf2 && pos[5] == 0x01;
255}
256
257static bool ath6kl_is_rsn_ie(const u8 *pos)
258{
259 return pos[0] == WLAN_EID_RSN;
260}
261
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700262static bool ath6kl_is_wps_ie(const u8 *pos)
263{
264 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
265 pos[1] >= 4 &&
266 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
267 pos[5] == 0x04);
268}
269
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530270static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
271 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800272{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530273 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800274 const u8 *pos;
275 u8 *buf = NULL;
276 size_t len = 0;
277 int ret;
278
279 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700280 * Clear previously set flag
281 */
282
283 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
284
285 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800286 * Filter out RSN/WPA IE(s)
287 */
288
289 if (ies && ies_len) {
290 buf = kmalloc(ies_len, GFP_KERNEL);
291 if (buf == NULL)
292 return -ENOMEM;
293 pos = ies;
294
295 while (pos + 1 < ies + ies_len) {
296 if (pos + 2 + pos[1] > ies + ies_len)
297 break;
298 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
299 memcpy(buf + len, pos, 2 + pos[1]);
300 len += 2 + pos[1];
301 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700302
303 if (ath6kl_is_wps_ie(pos))
304 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
305
Kevin Fang6981ffd2011-10-07 08:51:19 +0800306 pos += 2 + pos[1];
307 }
308 }
309
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530310 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
311 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800312 kfree(buf);
313 return ret;
314}
315
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530316static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
317{
318 switch (type) {
319 case NL80211_IFTYPE_STATION:
320 *nw_type = INFRA_NETWORK;
321 break;
322 case NL80211_IFTYPE_ADHOC:
323 *nw_type = ADHOC_NETWORK;
324 break;
325 case NL80211_IFTYPE_AP:
326 *nw_type = AP_NETWORK;
327 break;
328 case NL80211_IFTYPE_P2P_CLIENT:
329 *nw_type = INFRA_NETWORK;
330 break;
331 case NL80211_IFTYPE_P2P_GO:
332 *nw_type = AP_NETWORK;
333 break;
334 default:
335 ath6kl_err("invalid interface type %u\n", type);
336 return -ENOTSUPP;
337 }
338
339 return 0;
340}
341
342static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
343 u8 *if_idx, u8 *nw_type)
344{
345 int i;
346
347 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
348 return false;
349
350 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
351 ar->num_vif))
352 return false;
353
354 if (type == NL80211_IFTYPE_STATION ||
355 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
356 for (i = 0; i < MAX_NUM_VIF; i++) {
357 if ((ar->avail_idx_map >> i) & BIT(0)) {
358 *if_idx = i;
359 return true;
360 }
361 }
362 }
363
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530364 if (type == NL80211_IFTYPE_P2P_CLIENT ||
365 type == NL80211_IFTYPE_P2P_GO) {
366 for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
367 if ((ar->avail_idx_map >> i) & BIT(0)) {
368 *if_idx = i;
369 return true;
370 }
371 }
372 }
373
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530374 return false;
375}
376
Kalle Valobdcd8172011-07-18 00:22:30 +0300377static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
378 struct cfg80211_connect_params *sme)
379{
380 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530381 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300382 int status;
383
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530384 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300385
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530386 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300387 return -EIO;
388
389 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
390 ath6kl_err("destroy in progress\n");
391 return -EBUSY;
392 }
393
394 if (test_bit(SKIP_SCAN, &ar->flag) &&
395 ((sme->channel && sme->channel->center_freq == 0) ||
396 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
397 ath6kl_err("SkipScan: channel or bssid invalid\n");
398 return -EINVAL;
399 }
400
401 if (down_interruptible(&ar->sem)) {
402 ath6kl_err("busy, couldn't get access\n");
403 return -ERESTARTSYS;
404 }
405
406 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
407 ath6kl_err("busy, destroy in progress\n");
408 up(&ar->sem);
409 return -EBUSY;
410 }
411
412 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
413 /*
414 * sleep until the command queue drains
415 */
416 wait_event_interruptible_timeout(ar->event_wq,
417 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
418 WMI_TIMEOUT);
419 if (signal_pending(current)) {
420 ath6kl_err("cmd queue drain timeout\n");
421 up(&ar->sem);
422 return -EINTR;
423 }
424 }
425
Kevin Fang6981ffd2011-10-07 08:51:19 +0800426 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530427 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800428 if (status)
429 return status;
430 }
431
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530432 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530433 vif->ssid_len == sme->ssid_len &&
434 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530435 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530436 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
437 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530438 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300439
440 up(&ar->sem);
441 if (status) {
442 ath6kl_err("wmi_reconnect_cmd failed\n");
443 return -EIO;
444 }
445 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530446 } else if (vif->ssid_len == sme->ssid_len &&
447 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530448 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300449 }
450
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530451 memset(vif->ssid, 0, sizeof(vif->ssid));
452 vif->ssid_len = sme->ssid_len;
453 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300454
455 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530456 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300457
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530458 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300459 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530460 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300461
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530462 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300463
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530464 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300465 if (status) {
466 up(&ar->sem);
467 return status;
468 }
469
470 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530471 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300472 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530473 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300474
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530475 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300476
477 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530478 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300479
480 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530481 (vif->auth_mode == NONE_AUTH) &&
482 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300483 struct ath6kl_key *key = NULL;
484
485 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
486 sme->key_idx > WMI_MAX_KEY_INDEX) {
487 ath6kl_err("key index %d out of bounds\n",
488 sme->key_idx);
489 up(&ar->sem);
490 return -ENOENT;
491 }
492
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530493 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300494 key->key_len = sme->key_len;
495 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530496 key->cipher = vif->prwise_crypto;
497 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300498
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530499 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530500 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300501 GROUP_USAGE | TX_USAGE,
502 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200503 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300504 key->key, KEY_OP_INIT_VAL, NULL,
505 NO_SYNC_WMIFLAG);
506 }
507
508 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530509 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530510 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
511 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300512 ath6kl_err("couldn't set bss filtering\n");
513 up(&ar->sem);
514 return -EIO;
515 }
516 }
517
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530518 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300519
520 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
521 "%s: connect called with authmode %d dot11 auth %d"
522 " PW crypto %d PW crypto len %d GRP crypto %d"
523 " GRP crypto len %d channel hint %u\n",
524 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530525 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
526 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530527 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300528
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530529 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530530 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530531 vif->dot11_auth_mode, vif->auth_mode,
532 vif->prwise_crypto,
533 vif->prwise_crypto_len,
534 vif->grp_crypto, vif->grp_crypto_len,
535 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530536 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300537 ar->connect_ctrl_flags);
538
539 up(&ar->sem);
540
541 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530542 memset(vif->ssid, 0, sizeof(vif->ssid));
543 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300544 ath6kl_err("invalid request\n");
545 return -ENOENT;
546 } else if (status) {
547 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
548 return -EIO;
549 }
550
551 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530552 ((vif->auth_mode == WPA_PSK_AUTH)
553 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530554 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300555 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
556 }
557
558 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530559 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300560
561 return 0;
562}
563
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530564static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300565 struct ieee80211_channel *chan,
566 const u8 *beacon_ie, size_t beacon_ie_len)
567{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530568 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300569 struct cfg80211_bss *bss;
570 u8 *ie;
571
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530572 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530573 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300574 WLAN_CAPABILITY_ESS);
575 if (bss == NULL) {
576 /*
577 * Since cfg80211 may not yet know about the BSS,
578 * generate a partial entry until the first BSS info
579 * event becomes available.
580 *
581 * Prepend SSID element since it is not included in the Beacon
582 * IEs from the target.
583 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300585 if (ie == NULL)
586 return -ENOMEM;
587 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530588 ie[1] = vif->ssid_len;
589 memcpy(ie + 2, vif->ssid, vif->ssid_len);
590 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530591 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300592 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530593 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300594 0, GFP_KERNEL);
595 if (bss)
596 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
597 "%pM prior to indicating connect/roamed "
598 "event\n", bssid);
599 kfree(ie);
600 } else
601 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
602 "entry\n");
603
604 if (bss == NULL)
605 return -ENOMEM;
606
607 cfg80211_put_bss(bss);
608
609 return 0;
610}
611
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530612void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300613 u8 *bssid, u16 listen_intvl,
614 u16 beacon_intvl,
615 enum network_type nw_type,
616 u8 beacon_ie_len, u8 assoc_req_len,
617 u8 assoc_resp_len, u8 *assoc_info)
618{
Jouni Malinen01cac472011-09-19 19:14:59 +0300619 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530620 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300621
622 /* capinfo + listen interval */
623 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
624
625 /* capinfo + status code + associd */
626 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
627
628 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
629 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
630 assoc_resp_ie_offset;
631
632 assoc_req_len -= assoc_req_ie_offset;
633 assoc_resp_len -= assoc_resp_ie_offset;
634
Jouni Malinen32c10872011-09-19 19:15:07 +0300635 /*
636 * Store Beacon interval here; DTIM period will be available only once
637 * a Beacon frame from the AP is seen.
638 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530639 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530640 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300641
Kalle Valobdcd8172011-07-18 00:22:30 +0300642 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530643 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300644 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
645 "%s: ath6k not in ibss mode\n", __func__);
646 return;
647 }
648 }
649
650 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530651 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
652 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
654 "%s: ath6k not in station mode\n", __func__);
655 return;
656 }
657 }
658
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530659 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300660
Kalle Valobdcd8172011-07-18 00:22:30 +0300661
662 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530663 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 return;
665 }
666
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530667 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300668 beacon_ie_len) < 0) {
669 ath6kl_err("could not add cfg80211 bss entry for "
670 "connect/roamed notification\n");
671 return;
672 }
673
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530674 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300675 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530676 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530677 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300678 assoc_req_ie, assoc_req_len,
679 assoc_resp_ie, assoc_resp_len,
680 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530681 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300682 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530683 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300684 assoc_req_ie, assoc_req_len,
685 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
686 }
687}
688
689static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
690 struct net_device *dev, u16 reason_code)
691{
692 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530693 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300694
695 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
696 reason_code);
697
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530698 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300699 return -EIO;
700
701 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
702 ath6kl_err("busy, destroy in progress\n");
703 return -EBUSY;
704 }
705
706 if (down_interruptible(&ar->sem)) {
707 ath6kl_err("busy, couldn't get access\n");
708 return -ERESTARTSYS;
709 }
710
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530711 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530712 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530713 memset(vif->ssid, 0, sizeof(vif->ssid));
714 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300715
716 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530717 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300718
719 up(&ar->sem);
720
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530721 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530722
Kalle Valobdcd8172011-07-18 00:22:30 +0300723 return 0;
724}
725
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530726void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300727 u8 *bssid, u8 assoc_resp_len,
728 u8 *assoc_info, u16 proto_reason)
729{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530730 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530731
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530732 if (vif->scan_req) {
733 cfg80211_scan_done(vif->scan_req, true);
734 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300735 }
736
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530737 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530738 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300739 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
740 "%s: ath6k not in ibss mode\n", __func__);
741 return;
742 }
743 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300745 return;
746 }
747
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530748 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530749 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
750 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300751 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
752 "%s: ath6k not in station mode\n", __func__);
753 return;
754 }
755 }
756
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530757 /*
758 * Send a disconnect command to target when a disconnect event is
759 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
760 * request from host) to make the firmware stop trying to connect even
761 * after giving disconnect event. There will be one more disconnect
762 * event for this disconnect command with reason code DISCONNECT_CMD
763 * which will be notified to cfg80211.
764 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300765
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530766 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530767 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 return;
769 }
770
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530771 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300772
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530773 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530774 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530775 bssid, NULL, 0,
776 NULL, 0,
777 WLAN_STATUS_UNSPECIFIED_FAILURE,
778 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530779 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530780 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530781 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300782 }
783
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530784 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300785}
786
Kalle Valobdcd8172011-07-18 00:22:30 +0300787static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
788 struct cfg80211_scan_request *request)
789{
790 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530791 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300792 s8 n_channels = 0;
793 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530795 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300796
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530797 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300798 return -EIO;
799
800 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530801 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300802 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530803 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530804 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300805 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
806 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300807 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300808 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300809 }
810 }
811
812 if (request->n_ssids && request->ssids[0].ssid_len) {
813 u8 i;
814
815 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
816 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
817
818 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530819 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
820 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300821 request->ssids[i].ssid_len,
822 request->ssids[i].ssid);
823 }
824
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300825 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530826 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
827 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300828 request->ie, request->ie_len);
829 if (ret) {
830 ath6kl_err("failed to set Probe Request appie for "
831 "scan");
832 return ret;
833 }
834 }
835
Jouni Malinen11869be2011-09-02 20:07:06 +0300836 /*
837 * Scan only the requested channels if the request specifies a set of
838 * channels. If the list is longer than the target supports, do not
839 * configure the list and instead, scan all available channels.
840 */
841 if (request->n_channels > 0 &&
842 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300843 u8 i;
844
Jouni Malinen11869be2011-09-02 20:07:06 +0300845 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300846
847 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
848 if (channels == NULL) {
849 ath6kl_warn("failed to set scan channels, "
850 "scan all channels");
851 n_channels = 0;
852 }
853
854 for (i = 0; i < n_channels; i++)
855 channels[i] = request->channels[i]->center_freq;
856 }
857
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530858 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530859 force_fg_scan = 1;
860
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530861 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
862 force_fg_scan, false, 0, 0, n_channels,
863 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300864 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300865 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300866 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530867 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300868
Edward Lu1276c9e2011-08-30 21:58:00 +0300869 kfree(channels);
870
Kalle Valobdcd8172011-07-18 00:22:30 +0300871 return ret;
872}
873
Kalle Valo1c17d312011-11-01 08:43:56 +0200874void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300875{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530876 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300877 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300878
Kalle Valo1c17d312011-11-01 08:43:56 +0200879 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
880 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300881
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530882 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300883 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300884
Kalle Valo1c17d312011-11-01 08:43:56 +0200885 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300886 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300887
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530888 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
889 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530890 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
891 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300892 0, NULL);
893 }
894 }
895
896out:
Kalle Valocb938212011-10-27 18:47:46 +0300897 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530898 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300899}
900
901static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
902 u8 key_index, bool pairwise,
903 const u8 *mac_addr,
904 struct key_params *params)
905{
906 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530907 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300908 struct ath6kl_key *key = NULL;
909 u8 key_usage;
910 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300911
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530912 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300913 return -EIO;
914
Jouni Malinen837cb972011-10-11 17:31:57 +0300915 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
916 if (params->key_len != WMI_KRK_LEN)
917 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530918 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
919 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300920 }
921
Kalle Valobdcd8172011-07-18 00:22:30 +0300922 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
923 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
924 "%s: key index %d out of bounds\n", __func__,
925 key_index);
926 return -ENOENT;
927 }
928
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530929 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300930 memset(key, 0, sizeof(struct ath6kl_key));
931
932 if (pairwise)
933 key_usage = PAIRWISE_USAGE;
934 else
935 key_usage = GROUP_USAGE;
936
937 if (params) {
938 if (params->key_len > WLAN_MAX_KEY_LEN ||
939 params->seq_len > sizeof(key->seq))
940 return -EINVAL;
941
942 key->key_len = params->key_len;
943 memcpy(key->key, params->key, key->key_len);
944 key->seq_len = params->seq_len;
945 memcpy(key->seq, params->seq, key->seq_len);
946 key->cipher = params->cipher;
947 }
948
949 switch (key->cipher) {
950 case WLAN_CIPHER_SUITE_WEP40:
951 case WLAN_CIPHER_SUITE_WEP104:
952 key_type = WEP_CRYPT;
953 break;
954
955 case WLAN_CIPHER_SUITE_TKIP:
956 key_type = TKIP_CRYPT;
957 break;
958
959 case WLAN_CIPHER_SUITE_CCMP:
960 key_type = AES_CRYPT;
961 break;
962
963 default:
964 return -ENOTSUPP;
965 }
966
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530967 if (((vif->auth_mode == WPA_PSK_AUTH)
968 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300969 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530970 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300971
972 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
973 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
974 __func__, key_index, key->key_len, key_type,
975 key_usage, key->seq_len);
976
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530977 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300978
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530979 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300980 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
981 ar->ap_mode_bkey.valid = true;
982 ar->ap_mode_bkey.key_index = key_index;
983 ar->ap_mode_bkey.key_type = key_type;
984 ar->ap_mode_bkey.key_len = key->key_len;
985 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530986 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300987 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
988 "key configuration until AP mode has been "
989 "started\n");
990 /*
991 * The key will be set in ath6kl_connect_ap_mode() once
992 * the connected event is received from the target.
993 */
994 return 0;
995 }
996 }
997
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530998 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530999 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001000 /*
1001 * Store the key locally so that it can be re-configured after
1002 * the AP mode has properly started
1003 * (ath6kl_install_statioc_wep_keys).
1004 */
1005 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1006 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301007 vif->wep_key_list[key_index].key_len = key->key_len;
1008 memcpy(vif->wep_key_list[key_index].key, key->key,
1009 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001010 return 0;
1011 }
1012
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001013 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1014 vif->def_txkey_index,
1015 key_type, key_usage, key->key_len,
1016 key->seq, key->seq_len, key->key,
1017 KEY_OP_INIT_VAL,
1018 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001019}
1020
1021static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1022 u8 key_index, bool pairwise,
1023 const u8 *mac_addr)
1024{
1025 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301026 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001027
1028 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1029
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301030 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001031 return -EIO;
1032
1033 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1034 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1035 "%s: key index %d out of bounds\n", __func__,
1036 key_index);
1037 return -ENOENT;
1038 }
1039
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301040 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001041 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1042 "%s: index %d is empty\n", __func__, key_index);
1043 return 0;
1044 }
1045
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301046 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001047
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301048 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001049}
1050
1051static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1052 u8 key_index, bool pairwise,
1053 const u8 *mac_addr, void *cookie,
1054 void (*callback) (void *cookie,
1055 struct key_params *))
1056{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301057 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001058 struct ath6kl_key *key = NULL;
1059 struct key_params params;
1060
1061 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1062
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301063 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001064 return -EIO;
1065
1066 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1067 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1068 "%s: key index %d out of bounds\n", __func__,
1069 key_index);
1070 return -ENOENT;
1071 }
1072
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301073 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001074 memset(&params, 0, sizeof(params));
1075 params.cipher = key->cipher;
1076 params.key_len = key->key_len;
1077 params.seq_len = key->seq_len;
1078 params.seq = key->seq;
1079 params.key = key->key;
1080
1081 callback(cookie, &params);
1082
1083 return key->key_len ? 0 : -ENOENT;
1084}
1085
1086static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1087 struct net_device *ndev,
1088 u8 key_index, bool unicast,
1089 bool multicast)
1090{
1091 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301092 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001093 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001094 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001095 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001096
1097 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1098
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301099 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001100 return -EIO;
1101
1102 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1103 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1104 "%s: key index %d out of bounds\n",
1105 __func__, key_index);
1106 return -ENOENT;
1107 }
1108
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301109 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001110 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1111 __func__, key_index);
1112 return -EINVAL;
1113 }
1114
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301115 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301116 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001117 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301118 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001119 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001120 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301121 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001122 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301123 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001124
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301125 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001126 return 0; /* Delay until AP mode has been started */
1127
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001128 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1129 vif->def_txkey_index,
1130 key_type, key_usage,
1131 key->key_len, key->seq, key->seq_len,
1132 key->key,
1133 KEY_OP_INIT_VAL, NULL,
1134 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001135}
1136
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301137void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001138 bool ismcast)
1139{
1140 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1141 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1142
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301143 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001144 (ismcast ? NL80211_KEYTYPE_GROUP :
1145 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1146 GFP_KERNEL);
1147}
1148
1149static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1150{
1151 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301152 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001153 int ret;
1154
1155 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1156 changed);
1157
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301158 vif = ath6kl_vif_first(ar);
1159 if (!vif)
1160 return -EIO;
1161
1162 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001163 return -EIO;
1164
1165 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1166 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1167 if (ret != 0) {
1168 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1169 return -EIO;
1170 }
1171 }
1172
1173 return 0;
1174}
1175
1176/*
1177 * The type nl80211_tx_power_setting replaces the following
1178 * data type from 2.6.36 onwards
1179*/
1180static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1181 enum nl80211_tx_power_setting type,
1182 int dbm)
1183{
1184 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301185 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001186 u8 ath6kl_dbm;
1187
1188 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1189 type, dbm);
1190
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301191 vif = ath6kl_vif_first(ar);
1192 if (!vif)
1193 return -EIO;
1194
1195 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001196 return -EIO;
1197
1198 switch (type) {
1199 case NL80211_TX_POWER_AUTOMATIC:
1200 return 0;
1201 case NL80211_TX_POWER_LIMITED:
1202 ar->tx_pwr = ath6kl_dbm = dbm;
1203 break;
1204 default:
1205 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1206 __func__, type);
1207 return -EOPNOTSUPP;
1208 }
1209
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301210 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001211
1212 return 0;
1213}
1214
1215static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1216{
1217 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301218 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001219
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301220 vif = ath6kl_vif_first(ar);
1221 if (!vif)
1222 return -EIO;
1223
1224 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001225 return -EIO;
1226
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301227 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001228 ar->tx_pwr = 0;
1229
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301230 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001231 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1232 return -EIO;
1233 }
1234
1235 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1236 5 * HZ);
1237
1238 if (signal_pending(current)) {
1239 ath6kl_err("target did not respond\n");
1240 return -EINTR;
1241 }
1242 }
1243
1244 *dbm = ar->tx_pwr;
1245 return 0;
1246}
1247
1248static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1249 struct net_device *dev,
1250 bool pmgmt, int timeout)
1251{
1252 struct ath6kl *ar = ath6kl_priv(dev);
1253 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301254 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001255
1256 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1257 __func__, pmgmt, timeout);
1258
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301259 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001260 return -EIO;
1261
1262 if (pmgmt) {
1263 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1264 mode.pwr_mode = REC_POWER;
1265 } else {
1266 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1267 mode.pwr_mode = MAX_PERF_POWER;
1268 }
1269
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301270 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1271 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001272 ath6kl_err("wmi_powermode_cmd failed\n");
1273 return -EIO;
1274 }
1275
1276 return 0;
1277}
1278
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301279static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1280 char *name,
1281 enum nl80211_iftype type,
1282 u32 *flags,
1283 struct vif_params *params)
1284{
1285 struct ath6kl *ar = wiphy_priv(wiphy);
1286 struct net_device *ndev;
1287 u8 if_idx, nw_type;
1288
1289 if (ar->num_vif == MAX_NUM_VIF) {
1290 ath6kl_err("Reached maximum number of supported vif\n");
1291 return ERR_PTR(-EINVAL);
1292 }
1293
1294 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1295 ath6kl_err("Not a supported interface type\n");
1296 return ERR_PTR(-EINVAL);
1297 }
1298
1299 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1300 if (!ndev)
1301 return ERR_PTR(-ENOMEM);
1302
1303 ar->num_vif++;
1304
1305 return ndev;
1306}
1307
1308static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1309 struct net_device *ndev)
1310{
1311 struct ath6kl *ar = wiphy_priv(wiphy);
1312 struct ath6kl_vif *vif = netdev_priv(ndev);
1313
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301314 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301315 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301316 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301317
1318 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1319
1320 ath6kl_deinit_if_data(vif);
1321
1322 return 0;
1323}
1324
Kalle Valobdcd8172011-07-18 00:22:30 +03001325static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1326 struct net_device *ndev,
1327 enum nl80211_iftype type, u32 *flags,
1328 struct vif_params *params)
1329{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301330 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001331
1332 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1333
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301334 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001335 return -EIO;
1336
1337 switch (type) {
1338 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301339 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001340 break;
1341 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301342 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001343 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001344 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301345 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001346 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001347 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301348 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001349 break;
1350 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301351 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001352 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001353 default:
1354 ath6kl_err("invalid interface type %u\n", type);
1355 return -EOPNOTSUPP;
1356 }
1357
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301358 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001359
1360 return 0;
1361}
1362
1363static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1364 struct net_device *dev,
1365 struct cfg80211_ibss_params *ibss_param)
1366{
1367 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301368 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001369 int status;
1370
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301371 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001372 return -EIO;
1373
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301374 vif->ssid_len = ibss_param->ssid_len;
1375 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001376
1377 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301378 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001379
1380 if (ibss_param->channel_fixed) {
1381 /*
1382 * TODO: channel_fixed: The channel should be fixed, do not
1383 * search for IBSSs to join on other channels. Target
1384 * firmware does not support this feature, needs to be
1385 * updated.
1386 */
1387 return -EOPNOTSUPP;
1388 }
1389
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301390 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001391 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301392 memcpy(vif->req_bssid, ibss_param->bssid,
1393 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001394
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301395 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001396
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301397 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001398 if (status)
1399 return status;
1400
1401 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301402 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1403 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001404 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301405 ath6kl_set_cipher(vif, 0, true);
1406 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001407 }
1408
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301409 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001410
1411 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1412 "%s: connect called with authmode %d dot11 auth %d"
1413 " PW crypto %d PW crypto len %d GRP crypto %d"
1414 " GRP crypto len %d channel hint %u\n",
1415 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301416 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1417 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301418 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001419
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301420 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301421 vif->dot11_auth_mode, vif->auth_mode,
1422 vif->prwise_crypto,
1423 vif->prwise_crypto_len,
1424 vif->grp_crypto, vif->grp_crypto_len,
1425 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301426 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001427 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301428 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001429
1430 return 0;
1431}
1432
1433static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1434 struct net_device *dev)
1435{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301436 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001437
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301438 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001439 return -EIO;
1440
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301441 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301442 memset(vif->ssid, 0, sizeof(vif->ssid));
1443 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001444
1445 return 0;
1446}
1447
1448static const u32 cipher_suites[] = {
1449 WLAN_CIPHER_SUITE_WEP40,
1450 WLAN_CIPHER_SUITE_WEP104,
1451 WLAN_CIPHER_SUITE_TKIP,
1452 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001453 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001454};
1455
1456static bool is_rate_legacy(s32 rate)
1457{
1458 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1459 6000, 9000, 12000, 18000, 24000,
1460 36000, 48000, 54000
1461 };
1462 u8 i;
1463
1464 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1465 if (rate == legacy[i])
1466 return true;
1467
1468 return false;
1469}
1470
1471static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1472{
1473 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1474 52000, 58500, 65000, 72200
1475 };
1476 u8 i;
1477
1478 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1479 if (rate == ht20[i]) {
1480 if (i == ARRAY_SIZE(ht20) - 1)
1481 /* last rate uses sgi */
1482 *sgi = true;
1483 else
1484 *sgi = false;
1485
1486 *mcs = i;
1487 return true;
1488 }
1489 }
1490 return false;
1491}
1492
1493static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1494{
1495 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1496 81000, 108000, 121500, 135000,
1497 150000
1498 };
1499 u8 i;
1500
1501 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1502 if (rate == ht40[i]) {
1503 if (i == ARRAY_SIZE(ht40) - 1)
1504 /* last rate uses sgi */
1505 *sgi = true;
1506 else
1507 *sgi = false;
1508
1509 *mcs = i;
1510 return true;
1511 }
1512 }
1513
1514 return false;
1515}
1516
1517static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1518 u8 *mac, struct station_info *sinfo)
1519{
1520 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301521 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001522 long left;
1523 bool sgi;
1524 s32 rate;
1525 int ret;
1526 u8 mcs;
1527
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301528 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001529 return -ENOENT;
1530
1531 if (down_interruptible(&ar->sem))
1532 return -EBUSY;
1533
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301534 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001535
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301536 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001537
1538 if (ret != 0) {
1539 up(&ar->sem);
1540 return -EIO;
1541 }
1542
1543 left = wait_event_interruptible_timeout(ar->event_wq,
1544 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301545 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001546 WMI_TIMEOUT);
1547
1548 up(&ar->sem);
1549
1550 if (left == 0)
1551 return -ETIMEDOUT;
1552 else if (left < 0)
1553 return left;
1554
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301555 if (vif->target_stats.rx_byte) {
1556 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001557 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301558 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001559 sinfo->filled |= STATION_INFO_RX_PACKETS;
1560 }
1561
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301562 if (vif->target_stats.tx_byte) {
1563 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001564 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301565 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001566 sinfo->filled |= STATION_INFO_TX_PACKETS;
1567 }
1568
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301569 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001570 sinfo->filled |= STATION_INFO_SIGNAL;
1571
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301572 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001573
1574 if (is_rate_legacy(rate)) {
1575 sinfo->txrate.legacy = rate / 100;
1576 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1577 if (sgi) {
1578 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1579 sinfo->txrate.mcs = mcs - 1;
1580 } else {
1581 sinfo->txrate.mcs = mcs;
1582 }
1583
1584 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1585 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1586 if (sgi) {
1587 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1588 sinfo->txrate.mcs = mcs - 1;
1589 } else {
1590 sinfo->txrate.mcs = mcs;
1591 }
1592
1593 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1594 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1595 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001596 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1597 "invalid rate from stats: %d\n", rate);
1598 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001599 return 0;
1600 }
1601
1602 sinfo->filled |= STATION_INFO_TX_BITRATE;
1603
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301604 if (test_bit(CONNECTED, &vif->flags) &&
1605 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301606 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001607 sinfo->filled |= STATION_INFO_BSS_PARAM;
1608 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301609 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1610 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001611 }
1612
Kalle Valobdcd8172011-07-18 00:22:30 +03001613 return 0;
1614}
1615
1616static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1617 struct cfg80211_pmksa *pmksa)
1618{
1619 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301620 struct ath6kl_vif *vif = netdev_priv(netdev);
1621
1622 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001623 pmksa->pmkid, true);
1624}
1625
1626static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1627 struct cfg80211_pmksa *pmksa)
1628{
1629 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301630 struct ath6kl_vif *vif = netdev_priv(netdev);
1631
1632 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001633 pmksa->pmkid, false);
1634}
1635
1636static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1637{
1638 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301639 struct ath6kl_vif *vif = netdev_priv(netdev);
1640
1641 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301642 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1643 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001644 return 0;
1645}
1646
Raja Mani6cb3c712011-11-07 22:52:45 +02001647static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1648{
1649 struct ath6kl_vif *vif;
1650 int ret, pos, left;
1651 u32 filter = 0;
1652 u16 i;
1653 u8 mask[WOW_MASK_SIZE];
1654
1655 vif = ath6kl_vif_first(ar);
1656 if (!vif)
1657 return -EIO;
1658
1659 if (!ath6kl_cfg80211_ready(vif))
1660 return -EIO;
1661
1662 if (!test_bit(CONNECTED, &vif->flags))
1663 return -EINVAL;
1664
1665 /* Clear existing WOW patterns */
1666 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1667 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1668 WOW_LIST_ID, i);
1669 /* Configure new WOW patterns */
1670 for (i = 0; i < wow->n_patterns; i++) {
1671
1672 /*
1673 * Convert given nl80211 specific mask value to equivalent
1674 * driver specific mask value and send it to the chip along
1675 * with patterns. For example, If the mask value defined in
1676 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1677 * then equivalent driver specific mask value is
1678 * "0xFF 0x00 0xFF 0x00".
1679 */
1680 memset(&mask, 0, sizeof(mask));
1681 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1682 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1683 mask[pos] = 0xFF;
1684 }
1685 /*
1686 * Note: Pattern's offset is not passed as part of wowlan
1687 * parameter from CFG layer. So it's always passed as ZERO
1688 * to the firmware. It means, given WOW patterns are always
1689 * matched from the first byte of received pkt in the firmware.
1690 */
1691 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1692 vif->fw_vif_idx, WOW_LIST_ID,
1693 wow->patterns[i].pattern_len,
1694 0 /* pattern offset */,
1695 wow->patterns[i].pattern, mask);
1696 if (ret)
1697 return ret;
1698 }
1699
1700 if (wow->disconnect)
1701 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1702
1703 if (wow->magic_pkt)
1704 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1705
1706 if (wow->gtk_rekey_failure)
1707 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1708
1709 if (wow->eap_identity_req)
1710 filter |= WOW_FILTER_OPTION_EAP_REQ;
1711
1712 if (wow->four_way_handshake)
1713 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1714
1715 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1716 ATH6KL_WOW_MODE_ENABLE,
1717 filter,
1718 WOW_HOST_REQ_DELAY);
1719 if (ret)
1720 return ret;
1721
1722 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1723 ATH6KL_HOST_MODE_ASLEEP);
1724 if (ret)
1725 return ret;
1726
1727 if (ar->tx_pending[ar->ctrl_ep]) {
1728 left = wait_event_interruptible_timeout(ar->event_wq,
1729 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1730 if (left == 0) {
1731 ath6kl_warn("clear wmi ctrl data timeout\n");
1732 ret = -ETIMEDOUT;
1733 } else if (left < 0) {
1734 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1735 ret = left;
1736 }
1737 }
1738
1739 return ret;
1740}
1741
1742static int ath6kl_wow_resume(struct ath6kl *ar)
1743{
1744 struct ath6kl_vif *vif;
1745 int ret;
1746
1747 vif = ath6kl_vif_first(ar);
1748 if (!vif)
1749 return -EIO;
1750
1751 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1752 ATH6KL_HOST_MODE_AWAKE);
1753 return ret;
1754}
1755
Kalle Valo52d81a62011-11-01 08:44:21 +02001756int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001757 enum ath6kl_cfg_suspend_mode mode,
1758 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001759{
1760 int ret;
1761
Kalle Valo52d81a62011-11-01 08:44:21 +02001762 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001763 case ATH6KL_CFG_SUSPEND_WOW:
1764
1765 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1766
1767 /* Flush all non control pkts in TX path */
1768 ath6kl_tx_data_cleanup(ar);
1769
1770 ret = ath6kl_wow_suspend(ar, wow);
1771 if (ret) {
1772 ath6kl_err("wow suspend failed: %d\n", ret);
1773 return ret;
1774 }
1775 ar->state = ATH6KL_STATE_WOW;
1776 break;
1777
Kalle Valo52d81a62011-11-01 08:44:21 +02001778 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001779
1780 ath6kl_cfg80211_stop(ar);
1781
Kalle Valo52d81a62011-11-01 08:44:21 +02001782 /* save the current power mode before enabling power save */
1783 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1784
1785 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1786 if (ret) {
1787 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1788 ret);
1789 }
1790
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001791 ar->state = ATH6KL_STATE_DEEPSLEEP;
1792
Kalle Valo52d81a62011-11-01 08:44:21 +02001793 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001794
1795 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001796
1797 ath6kl_cfg80211_stop(ar);
1798
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001799 if (ar->state == ATH6KL_STATE_OFF) {
1800 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1801 "suspend hw off, no action for cutpower\n");
1802 break;
1803 }
1804
1805 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1806
1807 ret = ath6kl_init_hw_stop(ar);
1808 if (ret) {
1809 ath6kl_warn("failed to stop hw during suspend: %d\n",
1810 ret);
1811 }
1812
1813 ar->state = ATH6KL_STATE_CUTPOWER;
1814
1815 break;
1816
1817 default:
1818 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001819 }
1820
1821 return 0;
1822}
1823
1824int ath6kl_cfg80211_resume(struct ath6kl *ar)
1825{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001826 int ret;
1827
1828 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001829 case ATH6KL_STATE_WOW:
1830 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1831
1832 ret = ath6kl_wow_resume(ar);
1833 if (ret) {
1834 ath6kl_warn("wow mode resume failed: %d\n", ret);
1835 return ret;
1836 }
1837
1838 ar->state = ATH6KL_STATE_ON;
1839 break;
1840
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001841 case ATH6KL_STATE_DEEPSLEEP:
1842 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1843 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1844 ar->wmi->saved_pwr_mode);
1845 if (ret) {
1846 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1847 ret);
1848 }
1849 }
1850
1851 ar->state = ATH6KL_STATE_ON;
1852
1853 break;
1854
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001855 case ATH6KL_STATE_CUTPOWER:
1856 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1857
1858 ret = ath6kl_init_hw_start(ar);
1859 if (ret) {
1860 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1861 return ret;
1862 }
Raja Manid7c44e02011-11-07 22:52:46 +02001863 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001864
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001865 default:
1866 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001867 }
1868
1869 return 0;
1870}
1871
Kalle Valoabcb3442011-07-22 08:26:20 +03001872#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001873
1874/* hif layer decides what suspend mode to use */
1875static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001876 struct cfg80211_wowlan *wow)
1877{
1878 struct ath6kl *ar = wiphy_priv(wiphy);
1879
Raja Mani0f60e9f2011-11-07 22:52:45 +02001880 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001881}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001882
Kalle Valo52d81a62011-11-01 08:44:21 +02001883static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001884{
1885 struct ath6kl *ar = wiphy_priv(wiphy);
1886
1887 return ath6kl_hif_resume(ar);
1888}
Raja Mania918fb32011-11-07 22:52:46 +02001889
1890/*
1891 * FIXME: WOW suspend mode is selected if the host sdio controller supports
1892 * both sdio irq wake up and keep power. The target pulls sdio data line to
1893 * wake up the host when WOW pattern matches. This causes sdio irq handler
1894 * is being called in the host side which internally hits ath6kl's RX path.
1895 *
1896 * Since sdio interrupt is not disabled, RX path executes even before
1897 * the host executes the actual resume operation from PM module.
1898 *
1899 * In the current scenario, WOW resume should happen before start processing
1900 * any data from the target. So It's required to perform WOW resume in RX path.
1901 * Ideally we should perform WOW resume only in the actual platform
1902 * resume path. This area needs bit rework to avoid WOW resume in RX path.
1903 *
1904 * ath6kl_check_wow_status() is called from ath6kl_rx().
1905 */
1906void ath6kl_check_wow_status(struct ath6kl *ar)
1907{
1908 if (ar->state == ATH6KL_STATE_WOW)
1909 ath6kl_cfg80211_resume(ar);
1910}
1911
1912#else
1913
1914void ath6kl_check_wow_status(struct ath6kl *ar)
1915{
1916}
Kalle Valoabcb3442011-07-22 08:26:20 +03001917#endif
1918
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001919static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1920 struct ieee80211_channel *chan,
1921 enum nl80211_channel_type channel_type)
1922{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301923 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001924
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301925 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001926 return -EIO;
1927
1928 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1929 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301930 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001931
1932 return 0;
1933}
1934
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001935static bool ath6kl_is_p2p_ie(const u8 *pos)
1936{
1937 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1938 pos[2] == 0x50 && pos[3] == 0x6f &&
1939 pos[4] == 0x9a && pos[5] == 0x09;
1940}
1941
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301942static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1943 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001944{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301945 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001946 const u8 *pos;
1947 u8 *buf = NULL;
1948 size_t len = 0;
1949 int ret;
1950
1951 /*
1952 * Filter out P2P IE(s) since they will be included depending on
1953 * the Probe Request frame in ath6kl_send_go_probe_resp().
1954 */
1955
1956 if (ies && ies_len) {
1957 buf = kmalloc(ies_len, GFP_KERNEL);
1958 if (buf == NULL)
1959 return -ENOMEM;
1960 pos = ies;
1961 while (pos + 1 < ies + ies_len) {
1962 if (pos + 2 + pos[1] > ies + ies_len)
1963 break;
1964 if (!ath6kl_is_p2p_ie(pos)) {
1965 memcpy(buf + len, pos, 2 + pos[1]);
1966 len += 2 + pos[1];
1967 }
1968 pos += 2 + pos[1];
1969 }
1970 }
1971
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301972 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1973 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001974 kfree(buf);
1975 return ret;
1976}
1977
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001978static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1979 struct beacon_parameters *info, bool add)
1980{
1981 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301982 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001983 struct ieee80211_mgmt *mgmt;
1984 u8 *ies;
1985 int ies_len;
1986 struct wmi_connect_cmd p;
1987 int res;
1988 int i;
1989
1990 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1991
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301992 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001993 return -EIO;
1994
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301995 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001996 return -EOPNOTSUPP;
1997
1998 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301999 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2000 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002001 info->beacon_ies,
2002 info->beacon_ies_len);
2003 if (res)
2004 return res;
2005 }
2006 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302007 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002008 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002009 if (res)
2010 return res;
2011 }
2012 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302013 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2014 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002015 info->assocresp_ies,
2016 info->assocresp_ies_len);
2017 if (res)
2018 return res;
2019 }
2020
2021 if (!add)
2022 return 0;
2023
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002024 ar->ap_mode_bkey.valid = false;
2025
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002026 /* TODO:
2027 * info->interval
2028 * info->dtim_period
2029 */
2030
2031 if (info->head == NULL)
2032 return -EINVAL;
2033 mgmt = (struct ieee80211_mgmt *) info->head;
2034 ies = mgmt->u.beacon.variable;
2035 if (ies > info->head + info->head_len)
2036 return -EINVAL;
2037 ies_len = info->head + info->head_len - ies;
2038
2039 if (info->ssid == NULL)
2040 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302041 memcpy(vif->ssid, info->ssid, info->ssid_len);
2042 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002043 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2044 return -EOPNOTSUPP; /* TODO */
2045
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302046 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002047
2048 memset(&p, 0, sizeof(p));
2049
2050 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2051 switch (info->crypto.akm_suites[i]) {
2052 case WLAN_AKM_SUITE_8021X:
2053 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2054 p.auth_mode |= WPA_AUTH;
2055 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2056 p.auth_mode |= WPA2_AUTH;
2057 break;
2058 case WLAN_AKM_SUITE_PSK:
2059 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2060 p.auth_mode |= WPA_PSK_AUTH;
2061 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2062 p.auth_mode |= WPA2_PSK_AUTH;
2063 break;
2064 }
2065 }
2066 if (p.auth_mode == 0)
2067 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302068 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002069
2070 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2071 switch (info->crypto.ciphers_pairwise[i]) {
2072 case WLAN_CIPHER_SUITE_WEP40:
2073 case WLAN_CIPHER_SUITE_WEP104:
2074 p.prwise_crypto_type |= WEP_CRYPT;
2075 break;
2076 case WLAN_CIPHER_SUITE_TKIP:
2077 p.prwise_crypto_type |= TKIP_CRYPT;
2078 break;
2079 case WLAN_CIPHER_SUITE_CCMP:
2080 p.prwise_crypto_type |= AES_CRYPT;
2081 break;
2082 }
2083 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002084 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002085 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302086 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002087 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302088 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002089
2090 switch (info->crypto.cipher_group) {
2091 case WLAN_CIPHER_SUITE_WEP40:
2092 case WLAN_CIPHER_SUITE_WEP104:
2093 p.grp_crypto_type = WEP_CRYPT;
2094 break;
2095 case WLAN_CIPHER_SUITE_TKIP:
2096 p.grp_crypto_type = TKIP_CRYPT;
2097 break;
2098 case WLAN_CIPHER_SUITE_CCMP:
2099 p.grp_crypto_type = AES_CRYPT;
2100 break;
2101 default:
2102 p.grp_crypto_type = NONE_CRYPT;
2103 break;
2104 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302105 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002106
2107 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302108 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002109
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302110 p.ssid_len = vif->ssid_len;
2111 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2112 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302113 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002114
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302115 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002116 if (res < 0)
2117 return res;
2118
2119 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002120}
2121
2122static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2123 struct beacon_parameters *info)
2124{
2125 return ath6kl_ap_beacon(wiphy, dev, info, true);
2126}
2127
2128static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2129 struct beacon_parameters *info)
2130{
2131 return ath6kl_ap_beacon(wiphy, dev, info, false);
2132}
2133
2134static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2135{
2136 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302137 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002138
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302139 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002140 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302141 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002142 return -ENOTCONN;
2143
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302144 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302145 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002146
2147 return 0;
2148}
2149
Jouni Malinen23875132011-08-30 21:57:53 +03002150static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2151 u8 *mac, struct station_parameters *params)
2152{
2153 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302154 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002155
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302156 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002157 return -EOPNOTSUPP;
2158
2159 /* Use this only for authorizing/unauthorizing a station */
2160 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2161 return -EOPNOTSUPP;
2162
2163 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302164 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2165 WMI_AP_MLME_AUTHORIZE, mac, 0);
2166 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2167 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002168}
2169
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002170static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2171 struct net_device *dev,
2172 struct ieee80211_channel *chan,
2173 enum nl80211_channel_type channel_type,
2174 unsigned int duration,
2175 u64 *cookie)
2176{
2177 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302178 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002179 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002180
2181 /* TODO: if already pending or ongoing remain-on-channel,
2182 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002183 id = ++vif->last_roc_id;
2184 if (id == 0) {
2185 /* Do not use 0 as the cookie value */
2186 id = ++vif->last_roc_id;
2187 }
2188 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002189
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302190 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2191 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002192}
2193
2194static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2195 struct net_device *dev,
2196 u64 cookie)
2197{
2198 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302199 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002200
Jouni Malinen10522612011-10-27 16:00:13 +03002201 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002202 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002203 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002204
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302205 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002206}
2207
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302208static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2209 const u8 *buf, size_t len,
2210 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002211{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302212 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002213 const u8 *pos;
2214 u8 *p2p;
2215 int p2p_len;
2216 int ret;
2217 const struct ieee80211_mgmt *mgmt;
2218
2219 mgmt = (const struct ieee80211_mgmt *) buf;
2220
2221 /* Include P2P IE(s) from the frame generated in user space. */
2222
2223 p2p = kmalloc(len, GFP_KERNEL);
2224 if (p2p == NULL)
2225 return -ENOMEM;
2226 p2p_len = 0;
2227
2228 pos = mgmt->u.probe_resp.variable;
2229 while (pos + 1 < buf + len) {
2230 if (pos + 2 + pos[1] > buf + len)
2231 break;
2232 if (ath6kl_is_p2p_ie(pos)) {
2233 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2234 p2p_len += 2 + pos[1];
2235 }
2236 pos += 2 + pos[1];
2237 }
2238
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302239 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2240 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002241 kfree(p2p);
2242 return ret;
2243}
2244
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002245static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2246 struct ieee80211_channel *chan, bool offchan,
2247 enum nl80211_channel_type channel_type,
2248 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002249 const u8 *buf, size_t len, bool no_cck,
2250 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002251{
2252 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302253 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002254 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002255 const struct ieee80211_mgmt *mgmt;
2256
2257 mgmt = (const struct ieee80211_mgmt *) buf;
2258 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302259 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002260 ieee80211_is_probe_resp(mgmt->frame_control)) {
2261 /*
2262 * Send Probe Response frame in AP mode using a separate WMI
2263 * command to allow the target to fill in the generic IEs.
2264 */
2265 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302266 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002267 chan->center_freq);
2268 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002269
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302270 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002271 if (id == 0) {
2272 /*
2273 * 0 is a reserved value in the WMI command and shall not be
2274 * used for the command.
2275 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302276 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002277 }
2278
2279 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302280 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2281 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002282 buf, len);
2283}
2284
Jouni Malinenae32c302011-08-30 21:58:01 +03002285static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2286 struct net_device *dev,
2287 u16 frame_type, bool reg)
2288{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302289 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002290
2291 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2292 __func__, frame_type, reg);
2293 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2294 /*
2295 * Note: This notification callback is not allowed to sleep, so
2296 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2297 * hardcode target to report Probe Request frames all the time.
2298 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302299 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002300 }
2301}
2302
Jouni Malinenf80574a2011-08-30 21:58:04 +03002303static const struct ieee80211_txrx_stypes
2304ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2305 [NL80211_IFTYPE_STATION] = {
2306 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2307 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2308 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2309 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2310 },
2311 [NL80211_IFTYPE_P2P_CLIENT] = {
2312 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2313 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2314 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2315 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2316 },
2317 [NL80211_IFTYPE_P2P_GO] = {
2318 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2319 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2320 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2321 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2322 },
2323};
2324
Kalle Valobdcd8172011-07-18 00:22:30 +03002325static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302326 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2327 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002328 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2329 .scan = ath6kl_cfg80211_scan,
2330 .connect = ath6kl_cfg80211_connect,
2331 .disconnect = ath6kl_cfg80211_disconnect,
2332 .add_key = ath6kl_cfg80211_add_key,
2333 .get_key = ath6kl_cfg80211_get_key,
2334 .del_key = ath6kl_cfg80211_del_key,
2335 .set_default_key = ath6kl_cfg80211_set_default_key,
2336 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2337 .set_tx_power = ath6kl_cfg80211_set_txpower,
2338 .get_tx_power = ath6kl_cfg80211_get_txpower,
2339 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2340 .join_ibss = ath6kl_cfg80211_join_ibss,
2341 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2342 .get_station = ath6kl_get_station,
2343 .set_pmksa = ath6kl_set_pmksa,
2344 .del_pmksa = ath6kl_del_pmksa,
2345 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002346 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002347#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002348 .suspend = __ath6kl_cfg80211_suspend,
2349 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002350#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002351 .set_channel = ath6kl_set_channel,
2352 .add_beacon = ath6kl_add_beacon,
2353 .set_beacon = ath6kl_set_beacon,
2354 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002355 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002356 .remain_on_channel = ath6kl_remain_on_channel,
2357 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002358 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002359 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002360};
2361
Kalle Valoec4b7f62011-11-01 08:44:04 +02002362void ath6kl_cfg80211_stop(struct ath6kl *ar)
2363{
2364 struct ath6kl_vif *vif;
2365
2366 /* FIXME: for multi vif */
2367 vif = ath6kl_vif_first(ar);
2368 if (!vif) {
2369 /* save the current power mode before enabling power save */
2370 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2371
2372 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2373 ath6kl_warn("ath6kl_deep_sleep_enable: "
2374 "wmi_powermode_cmd failed\n");
2375 return;
2376 }
2377
2378 switch (vif->sme_state) {
2379 case SME_CONNECTING:
2380 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2381 NULL, 0,
2382 WLAN_STATUS_UNSPECIFIED_FAILURE,
2383 GFP_KERNEL);
2384 break;
2385 case SME_CONNECTED:
2386 default:
2387 /*
2388 * FIXME: oddly enough smeState is in DISCONNECTED during
2389 * suspend, why? Need to send disconnected event in that
2390 * state.
2391 */
2392 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2393 break;
2394 }
2395
2396 if (test_bit(CONNECTED, &vif->flags) ||
2397 test_bit(CONNECT_PEND, &vif->flags))
2398 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2399
2400 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002401 clear_bit(CONNECTED, &vif->flags);
2402 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002403
2404 /* disable scanning */
2405 if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
2406 0, 0, 0, 0, 0, 0, 0) != 0)
2407 printk(KERN_WARNING "ath6kl: failed to disable scan "
2408 "during suspend\n");
2409
2410 ath6kl_cfg80211_scan_complete_event(vif, true);
2411}
2412
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302413struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002414{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002415 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302416 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302417 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002418
2419 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302420 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302421
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302422 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002423 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002424 return NULL;
2425 }
2426
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302427 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302428 if (!multi_norm_if_support)
2429 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302430 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302431 ar->dev = dev;
2432
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302433 if (multi_norm_if_support)
2434 ar->max_norm_iface = 2;
2435 else
2436 ar->max_norm_iface = 1;
2437
2438 /* FIXME: Remove this once the multivif support is enabled */
2439 ar->max_norm_iface = 1;
2440
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302441 spin_lock_init(&ar->lock);
2442 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302443 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302444
2445 init_waitqueue_head(&ar->event_wq);
2446 sema_init(&ar->sem, 1);
2447
2448 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302449 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302450
2451 clear_bit(WMI_ENABLED, &ar->flag);
2452 clear_bit(SKIP_SCAN, &ar->flag);
2453 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2454
2455 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2456 ar->listen_intvl_b = 0;
2457 ar->tx_pwr = 0;
2458
2459 ar->intra_bss = 1;
2460 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2461 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2462 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2463 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2464
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002465 ar->state = ATH6KL_STATE_OFF;
2466
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302467 memset((u8 *)ar->sta_list, 0,
2468 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2469
2470 /* Init the PS queues */
2471 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2472 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2473 skb_queue_head_init(&ar->sta_list[ctr].psq);
2474 }
2475
2476 skb_queue_head_init(&ar->mcastpsq);
2477
2478 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2479
2480 return ar;
2481}
2482
2483int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2484{
2485 struct wiphy *wiphy = ar->wiphy;
2486 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002487
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302488 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002489
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302490 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002491
Kalle Valobdcd8172011-07-18 00:22:30 +03002492 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302493 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002494
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302495 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302496 BIT(NL80211_IFTYPE_ADHOC) |
2497 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002498 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302499 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302500 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002501 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302502
Kalle Valobdcd8172011-07-18 00:22:30 +03002503 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302504 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2505 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2506 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2507 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2508 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002509
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302510 wiphy->cipher_suites = cipher_suites;
2511 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002512
Raja Manieae9e062011-11-07 22:52:46 +02002513 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2514 WIPHY_WOWLAN_DISCONNECT |
2515 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2516 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2517 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2518 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2519 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2520 wiphy->wowlan.pattern_min_len = 1;
2521 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2522
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302523 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002524 if (ret < 0) {
2525 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302526 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002527 }
2528
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302529 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002530}
2531
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302532static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002533{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302534 vif->aggr_cntxt = aggr_init(vif->ndev);
2535 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302536 ath6kl_err("failed to initialize aggr\n");
2537 return -ENOMEM;
2538 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002539
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302540 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302541 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302542 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302543 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302544
2545 return 0;
2546}
2547
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302548void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302549{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302550 struct ath6kl *ar = vif->ar;
2551
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302552 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302553
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302554 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2555
2556 if (vif->nw_type == ADHOC_NETWORK)
2557 ar->ibss_if_active = false;
2558
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302559 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302560
2561 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302562}
2563
2564struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302565 enum nl80211_iftype type, u8 fw_vif_idx,
2566 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302567{
2568 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302569 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302570
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302571 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302572 if (!ndev)
2573 return NULL;
2574
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302575 vif = netdev_priv(ndev);
2576 ndev->ieee80211_ptr = &vif->wdev;
2577 vif->wdev.wiphy = ar->wiphy;
2578 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302579 vif->ndev = ndev;
2580 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2581 vif->wdev.netdev = ndev;
2582 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302583 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302584 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302585
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302586 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2587 if (fw_vif_idx != 0)
2588 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2589 0x2;
2590
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302591 init_netdev(ndev);
2592
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302593 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302594
2595 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302596 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302597 goto err;
2598
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302599 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302600 goto err;
2601
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302602 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302603 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302604 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302605 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302606 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302607
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302608 if (type == NL80211_IFTYPE_ADHOC)
2609 ar->ibss_if_active = true;
2610
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302611 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302612 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302613 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302614
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302615 return ndev;
2616
2617err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302618 aggr_module_destroy(vif->aggr_cntxt);
2619 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302620 return NULL;
2621}
2622
2623void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2624{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302625 wiphy_unregister(ar->wiphy);
2626 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002627}