blob: 9dd1f48977aa12368564c88d603129b2a22baffa [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;
24
25module_param(ath6kl_p2p, uint, 0644);
26
Kalle Valobdcd8172011-07-18 00:22:30 +030027#define RATETAB_ENT(_rate, _rateid, _flags) { \
28 .bitrate = (_rate), \
29 .flags = (_flags), \
30 .hw_value = (_rateid), \
31}
32
33#define CHAN2G(_channel, _freq, _flags) { \
34 .band = IEEE80211_BAND_2GHZ, \
35 .hw_value = (_channel), \
36 .center_freq = (_freq), \
37 .flags = (_flags), \
38 .max_antenna_gain = 0, \
39 .max_power = 30, \
40}
41
42#define CHAN5G(_channel, _flags) { \
43 .band = IEEE80211_BAND_5GHZ, \
44 .hw_value = (_channel), \
45 .center_freq = 5000 + (5 * (_channel)), \
46 .flags = (_flags), \
47 .max_antenna_gain = 0, \
48 .max_power = 30, \
49}
50
51static struct ieee80211_rate ath6kl_rates[] = {
52 RATETAB_ENT(10, 0x1, 0),
53 RATETAB_ENT(20, 0x2, 0),
54 RATETAB_ENT(55, 0x4, 0),
55 RATETAB_ENT(110, 0x8, 0),
56 RATETAB_ENT(60, 0x10, 0),
57 RATETAB_ENT(90, 0x20, 0),
58 RATETAB_ENT(120, 0x40, 0),
59 RATETAB_ENT(180, 0x80, 0),
60 RATETAB_ENT(240, 0x100, 0),
61 RATETAB_ENT(360, 0x200, 0),
62 RATETAB_ENT(480, 0x400, 0),
63 RATETAB_ENT(540, 0x800, 0),
64};
65
66#define ath6kl_a_rates (ath6kl_rates + 4)
67#define ath6kl_a_rates_size 8
68#define ath6kl_g_rates (ath6kl_rates + 0)
69#define ath6kl_g_rates_size 12
70
71static struct ieee80211_channel ath6kl_2ghz_channels[] = {
72 CHAN2G(1, 2412, 0),
73 CHAN2G(2, 2417, 0),
74 CHAN2G(3, 2422, 0),
75 CHAN2G(4, 2427, 0),
76 CHAN2G(5, 2432, 0),
77 CHAN2G(6, 2437, 0),
78 CHAN2G(7, 2442, 0),
79 CHAN2G(8, 2447, 0),
80 CHAN2G(9, 2452, 0),
81 CHAN2G(10, 2457, 0),
82 CHAN2G(11, 2462, 0),
83 CHAN2G(12, 2467, 0),
84 CHAN2G(13, 2472, 0),
85 CHAN2G(14, 2484, 0),
86};
87
88static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
89 CHAN5G(34, 0), CHAN5G(36, 0),
90 CHAN5G(38, 0), CHAN5G(40, 0),
91 CHAN5G(42, 0), CHAN5G(44, 0),
92 CHAN5G(46, 0), CHAN5G(48, 0),
93 CHAN5G(52, 0), CHAN5G(56, 0),
94 CHAN5G(60, 0), CHAN5G(64, 0),
95 CHAN5G(100, 0), CHAN5G(104, 0),
96 CHAN5G(108, 0), CHAN5G(112, 0),
97 CHAN5G(116, 0), CHAN5G(120, 0),
98 CHAN5G(124, 0), CHAN5G(128, 0),
99 CHAN5G(132, 0), CHAN5G(136, 0),
100 CHAN5G(140, 0), CHAN5G(149, 0),
101 CHAN5G(153, 0), CHAN5G(157, 0),
102 CHAN5G(161, 0), CHAN5G(165, 0),
103 CHAN5G(184, 0), CHAN5G(188, 0),
104 CHAN5G(192, 0), CHAN5G(196, 0),
105 CHAN5G(200, 0), CHAN5G(204, 0),
106 CHAN5G(208, 0), CHAN5G(212, 0),
107 CHAN5G(216, 0),
108};
109
110static struct ieee80211_supported_band ath6kl_band_2ghz = {
111 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
112 .channels = ath6kl_2ghz_channels,
113 .n_bitrates = ath6kl_g_rates_size,
114 .bitrates = ath6kl_g_rates,
115};
116
117static struct ieee80211_supported_band ath6kl_band_5ghz = {
118 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
119 .channels = ath6kl_5ghz_a_channels,
120 .n_bitrates = ath6kl_a_rates_size,
121 .bitrates = ath6kl_a_rates,
122};
123
Jouni Malinen837cb972011-10-11 17:31:57 +0300124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
125
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530126static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300127 enum nl80211_wpa_versions wpa_version)
128{
129 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
130
131 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530132 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300133 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530134 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300135 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530136 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300137 } else {
138 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
139 return -ENOTSUPP;
140 }
141
142 return 0;
143}
144
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530145static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300146 enum nl80211_auth_type auth_type)
147{
Kalle Valobdcd8172011-07-18 00:22:30 +0300148 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
149
150 switch (auth_type) {
151 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530152 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300153 break;
154 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530155 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300156 break;
157 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530158 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300159 break;
160
161 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530162 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300163 break;
164
165 default:
166 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
167 return -ENOTSUPP;
168 }
169
170 return 0;
171}
172
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530173static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300174{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530175 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
176 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
177 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300178
179 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
180 __func__, cipher, ucast);
181
182 switch (cipher) {
183 case 0:
184 /* our own hack to use value 0 as no crypto used */
185 *ar_cipher = NONE_CRYPT;
186 *ar_cipher_len = 0;
187 break;
188 case WLAN_CIPHER_SUITE_WEP40:
189 *ar_cipher = WEP_CRYPT;
190 *ar_cipher_len = 5;
191 break;
192 case WLAN_CIPHER_SUITE_WEP104:
193 *ar_cipher = WEP_CRYPT;
194 *ar_cipher_len = 13;
195 break;
196 case WLAN_CIPHER_SUITE_TKIP:
197 *ar_cipher = TKIP_CRYPT;
198 *ar_cipher_len = 0;
199 break;
200 case WLAN_CIPHER_SUITE_CCMP:
201 *ar_cipher = AES_CRYPT;
202 *ar_cipher_len = 0;
203 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200204 case WLAN_CIPHER_SUITE_SMS4:
205 *ar_cipher = WAPI_CRYPT;
206 *ar_cipher_len = 0;
207 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300208 default:
209 ath6kl_err("cipher 0x%x not supported\n", cipher);
210 return -ENOTSUPP;
211 }
212
213 return 0;
214}
215
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530216static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300217{
218 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
219
220 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530221 if (vif->auth_mode == WPA_AUTH)
222 vif->auth_mode = WPA_PSK_AUTH;
223 else if (vif->auth_mode == WPA2_AUTH)
224 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300225 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530226 if (vif->auth_mode == WPA_AUTH)
227 vif->auth_mode = WPA_AUTH_CCKM;
228 else if (vif->auth_mode == WPA2_AUTH)
229 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300230 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530231 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300232 }
233}
234
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530235static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300236{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530237 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530238
Kalle Valobdcd8172011-07-18 00:22:30 +0300239 if (!test_bit(WMI_READY, &ar->flag)) {
240 ath6kl_err("wmi is not ready\n");
241 return false;
242 }
243
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530244 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300245 ath6kl_err("wlan disabled\n");
246 return false;
247 }
248
249 return true;
250}
251
Kevin Fang6981ffd2011-10-07 08:51:19 +0800252static bool ath6kl_is_wpa_ie(const u8 *pos)
253{
254 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
255 pos[2] == 0x00 && pos[3] == 0x50 &&
256 pos[4] == 0xf2 && pos[5] == 0x01;
257}
258
259static bool ath6kl_is_rsn_ie(const u8 *pos)
260{
261 return pos[0] == WLAN_EID_RSN;
262}
263
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700264static bool ath6kl_is_wps_ie(const u8 *pos)
265{
266 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
267 pos[1] >= 4 &&
268 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
269 pos[5] == 0x04);
270}
271
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530272static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
273 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800274{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530275 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800276 const u8 *pos;
277 u8 *buf = NULL;
278 size_t len = 0;
279 int ret;
280
281 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700282 * Clear previously set flag
283 */
284
285 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
286
287 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800288 * Filter out RSN/WPA IE(s)
289 */
290
291 if (ies && ies_len) {
292 buf = kmalloc(ies_len, GFP_KERNEL);
293 if (buf == NULL)
294 return -ENOMEM;
295 pos = ies;
296
297 while (pos + 1 < ies + ies_len) {
298 if (pos + 2 + pos[1] > ies + ies_len)
299 break;
300 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
301 memcpy(buf + len, pos, 2 + pos[1]);
302 len += 2 + pos[1];
303 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700304
305 if (ath6kl_is_wps_ie(pos))
306 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
307
Kevin Fang6981ffd2011-10-07 08:51:19 +0800308 pos += 2 + pos[1];
309 }
310 }
311
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530312 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
313 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800314 kfree(buf);
315 return ret;
316}
317
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530318static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
319{
320 switch (type) {
321 case NL80211_IFTYPE_STATION:
322 *nw_type = INFRA_NETWORK;
323 break;
324 case NL80211_IFTYPE_ADHOC:
325 *nw_type = ADHOC_NETWORK;
326 break;
327 case NL80211_IFTYPE_AP:
328 *nw_type = AP_NETWORK;
329 break;
330 case NL80211_IFTYPE_P2P_CLIENT:
331 *nw_type = INFRA_NETWORK;
332 break;
333 case NL80211_IFTYPE_P2P_GO:
334 *nw_type = AP_NETWORK;
335 break;
336 default:
337 ath6kl_err("invalid interface type %u\n", type);
338 return -ENOTSUPP;
339 }
340
341 return 0;
342}
343
344static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
345 u8 *if_idx, u8 *nw_type)
346{
347 int i;
348
349 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
350 return false;
351
352 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
353 ar->num_vif))
354 return false;
355
356 if (type == NL80211_IFTYPE_STATION ||
357 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200358 for (i = 0; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530359 if ((ar->avail_idx_map >> i) & BIT(0)) {
360 *if_idx = i;
361 return true;
362 }
363 }
364 }
365
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530366 if (type == NL80211_IFTYPE_P2P_CLIENT ||
367 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200368 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530369 if ((ar->avail_idx_map >> i) & BIT(0)) {
370 *if_idx = i;
371 return true;
372 }
373 }
374 }
375
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530376 return false;
377}
378
Kalle Valobdcd8172011-07-18 00:22:30 +0300379static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
380 struct cfg80211_connect_params *sme)
381{
382 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530383 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300384 int status;
385
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530386 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300387
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530388 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300389 return -EIO;
390
391 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
392 ath6kl_err("destroy in progress\n");
393 return -EBUSY;
394 }
395
396 if (test_bit(SKIP_SCAN, &ar->flag) &&
397 ((sme->channel && sme->channel->center_freq == 0) ||
398 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
399 ath6kl_err("SkipScan: channel or bssid invalid\n");
400 return -EINVAL;
401 }
402
403 if (down_interruptible(&ar->sem)) {
404 ath6kl_err("busy, couldn't get access\n");
405 return -ERESTARTSYS;
406 }
407
408 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
409 ath6kl_err("busy, destroy in progress\n");
410 up(&ar->sem);
411 return -EBUSY;
412 }
413
414 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
415 /*
416 * sleep until the command queue drains
417 */
418 wait_event_interruptible_timeout(ar->event_wq,
419 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
420 WMI_TIMEOUT);
421 if (signal_pending(current)) {
422 ath6kl_err("cmd queue drain timeout\n");
423 up(&ar->sem);
424 return -EINTR;
425 }
426 }
427
Kevin Fang6981ffd2011-10-07 08:51:19 +0800428 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530429 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Dan Carpenter743b4512011-11-18 17:09:32 +0300430 if (status) {
431 up(&ar->sem);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800432 return status;
Dan Carpenter743b4512011-11-18 17:09:32 +0300433 }
Raja Mani542c5192011-11-15 14:14:56 +0530434 } else
435 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800436
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530437 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530438 vif->ssid_len == sme->ssid_len &&
439 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530440 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530441 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
442 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530443 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300444
445 up(&ar->sem);
446 if (status) {
447 ath6kl_err("wmi_reconnect_cmd failed\n");
448 return -EIO;
449 }
450 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530451 } else if (vif->ssid_len == sme->ssid_len &&
452 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530453 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300454 }
455
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530456 memset(vif->ssid, 0, sizeof(vif->ssid));
457 vif->ssid_len = sme->ssid_len;
458 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300459
460 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530461 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300462
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530463 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300464 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530465 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300466
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530467 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300468
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530469 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300470 if (status) {
471 up(&ar->sem);
472 return status;
473 }
474
475 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530476 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300477 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530478 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300479
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530480 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300481
482 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530483 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300484
485 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530486 (vif->auth_mode == NONE_AUTH) &&
487 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300488 struct ath6kl_key *key = NULL;
489
490 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
491 sme->key_idx > WMI_MAX_KEY_INDEX) {
492 ath6kl_err("key index %d out of bounds\n",
493 sme->key_idx);
494 up(&ar->sem);
495 return -ENOENT;
496 }
497
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530498 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300499 key->key_len = sme->key_len;
500 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530501 key->cipher = vif->prwise_crypto;
502 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300503
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530504 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530505 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300506 GROUP_USAGE | TX_USAGE,
507 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200508 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300509 key->key, KEY_OP_INIT_VAL, NULL,
510 NO_SYNC_WMIFLAG);
511 }
512
513 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530514 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530515 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
516 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300517 ath6kl_err("couldn't set bss filtering\n");
518 up(&ar->sem);
519 return -EIO;
520 }
521 }
522
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530523 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300524
525 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
526 "%s: connect called with authmode %d dot11 auth %d"
527 " PW crypto %d PW crypto len %d GRP crypto %d"
528 " GRP crypto len %d channel hint %u\n",
529 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530530 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
531 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530532 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300533
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530534 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530535 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530536 vif->dot11_auth_mode, vif->auth_mode,
537 vif->prwise_crypto,
538 vif->prwise_crypto_len,
539 vif->grp_crypto, vif->grp_crypto_len,
540 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530541 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300542 ar->connect_ctrl_flags);
543
544 up(&ar->sem);
545
546 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530547 memset(vif->ssid, 0, sizeof(vif->ssid));
548 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300549 ath6kl_err("invalid request\n");
550 return -ENOENT;
551 } else if (status) {
552 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
553 return -EIO;
554 }
555
556 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530557 ((vif->auth_mode == WPA_PSK_AUTH)
558 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530559 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300560 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
561 }
562
563 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530564 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300565
566 return 0;
567}
568
Raja Mani4eab6f42011-11-09 17:02:23 +0530569static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
570 enum network_type nw_type,
571 const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300572 struct ieee80211_channel *chan,
573 const u8 *beacon_ie, size_t beacon_ie_len)
574{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530575 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300576 struct cfg80211_bss *bss;
Raja Mani4eab6f42011-11-09 17:02:23 +0530577 u16 cap_mask, cap_val;
Jouni Malinen01cac472011-09-19 19:14:59 +0300578 u8 *ie;
579
Raja Mani4eab6f42011-11-09 17:02:23 +0530580 if (nw_type & ADHOC_NETWORK) {
581 cap_mask = WLAN_CAPABILITY_IBSS;
582 cap_val = WLAN_CAPABILITY_IBSS;
583 } else {
584 cap_mask = WLAN_CAPABILITY_ESS;
585 cap_val = WLAN_CAPABILITY_ESS;
586 }
587
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530588 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530589 vif->ssid, vif->ssid_len,
590 cap_mask, cap_val);
Jouni Malinen01cac472011-09-19 19:14:59 +0300591 if (bss == NULL) {
592 /*
593 * Since cfg80211 may not yet know about the BSS,
594 * generate a partial entry until the first BSS info
595 * event becomes available.
596 *
597 * Prepend SSID element since it is not included in the Beacon
598 * IEs from the target.
599 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530600 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300601 if (ie == NULL)
602 return -ENOMEM;
603 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530604 ie[1] = vif->ssid_len;
605 memcpy(ie + 2, vif->ssid, vif->ssid_len);
606 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530607 bss = cfg80211_inform_bss(ar->wiphy, chan,
Raja Mani4eab6f42011-11-09 17:02:23 +0530608 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530609 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300610 0, GFP_KERNEL);
611 if (bss)
Raja Mani4eab6f42011-11-09 17:02:23 +0530612 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
613 "cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300614 kfree(ie);
615 } else
616 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
617 "entry\n");
618
619 if (bss == NULL)
620 return -ENOMEM;
621
622 cfg80211_put_bss(bss);
623
624 return 0;
625}
626
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530627void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300628 u8 *bssid, u16 listen_intvl,
629 u16 beacon_intvl,
630 enum network_type nw_type,
631 u8 beacon_ie_len, u8 assoc_req_len,
632 u8 assoc_resp_len, u8 *assoc_info)
633{
Jouni Malinen01cac472011-09-19 19:14:59 +0300634 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530635 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300636
637 /* capinfo + listen interval */
638 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
639
640 /* capinfo + status code + associd */
641 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
642
643 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
644 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
645 assoc_resp_ie_offset;
646
647 assoc_req_len -= assoc_req_ie_offset;
648 assoc_resp_len -= assoc_resp_ie_offset;
649
Jouni Malinen32c10872011-09-19 19:15:07 +0300650 /*
651 * Store Beacon interval here; DTIM period will be available only once
652 * a Beacon frame from the AP is seen.
653 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530654 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530655 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300656
Kalle Valobdcd8172011-07-18 00:22:30 +0300657 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530658 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300659 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
660 "%s: ath6k not in ibss mode\n", __func__);
661 return;
662 }
663 }
664
665 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530666 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
667 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300668 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
669 "%s: ath6k not in station mode\n", __func__);
670 return;
671 }
672 }
673
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530674 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300675
Raja Mani4eab6f42011-11-09 17:02:23 +0530676 if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
677 beacon_ie_len) < 0) {
678 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300679 return;
680 }
681
Raja Mani4eab6f42011-11-09 17:02:23 +0530682 if (nw_type & ADHOC_NETWORK) {
683 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
684 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
685 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300686 return;
687 }
688
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530689 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300690 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530691 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530692 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300693 assoc_req_ie, assoc_req_len,
694 assoc_resp_ie, assoc_resp_len,
695 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530696 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300697 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530698 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300699 assoc_req_ie, assoc_req_len,
700 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
701 }
702}
703
704static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
705 struct net_device *dev, u16 reason_code)
706{
Kalle Valod6d5c062011-11-25 13:17:37 +0200707 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530708 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300709
710 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
711 reason_code);
712
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530713 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300714 return -EIO;
715
716 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
717 ath6kl_err("busy, destroy in progress\n");
718 return -EBUSY;
719 }
720
721 if (down_interruptible(&ar->sem)) {
722 ath6kl_err("busy, couldn't get access\n");
723 return -ERESTARTSYS;
724 }
725
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530726 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530727 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530728 memset(vif->ssid, 0, sizeof(vif->ssid));
729 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300730
731 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530732 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300733
734 up(&ar->sem);
735
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530736 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530737
Kalle Valobdcd8172011-07-18 00:22:30 +0300738 return 0;
739}
740
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530741void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300742 u8 *bssid, u8 assoc_resp_len,
743 u8 *assoc_info, u16 proto_reason)
744{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530745 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530746
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530747 if (vif->scan_req) {
748 cfg80211_scan_done(vif->scan_req, true);
749 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300750 }
751
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530752 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530753 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300754 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
755 "%s: ath6k not in ibss mode\n", __func__);
756 return;
757 }
758 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530759 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300760 return;
761 }
762
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530763 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530764 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
765 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300766 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
767 "%s: ath6k not in station mode\n", __func__);
768 return;
769 }
770 }
771
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530772 /*
773 * Send a disconnect command to target when a disconnect event is
774 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
775 * request from host) to make the firmware stop trying to connect even
776 * after giving disconnect event. There will be one more disconnect
777 * event for this disconnect command with reason code DISCONNECT_CMD
778 * which will be notified to cfg80211.
779 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300780
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530781 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530782 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300783 return;
784 }
785
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530786 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300787
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530788 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530789 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530790 bssid, NULL, 0,
791 NULL, 0,
792 WLAN_STATUS_UNSPECIFIED_FAILURE,
793 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530794 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530795 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530796 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300797 }
798
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530799 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300800}
801
Kalle Valobdcd8172011-07-18 00:22:30 +0300802static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
803 struct cfg80211_scan_request *request)
804{
Kalle Valod6d5c062011-11-25 13:17:37 +0200805 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530806 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300807 s8 n_channels = 0;
808 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300809 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530810 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300811
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530812 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300813 return -EIO;
814
815 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530816 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300817 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530818 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530819 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300820 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
821 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300822 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300823 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300824 }
825 }
826
827 if (request->n_ssids && request->ssids[0].ssid_len) {
828 u8 i;
829
830 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
831 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
832
833 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530834 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
835 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300836 request->ssids[i].ssid_len,
837 request->ssids[i].ssid);
838 }
839
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300840 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530841 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
842 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300843 request->ie, request->ie_len);
844 if (ret) {
845 ath6kl_err("failed to set Probe Request appie for "
846 "scan");
847 return ret;
848 }
849 }
850
Jouni Malinen11869be2011-09-02 20:07:06 +0300851 /*
852 * Scan only the requested channels if the request specifies a set of
853 * channels. If the list is longer than the target supports, do not
854 * configure the list and instead, scan all available channels.
855 */
856 if (request->n_channels > 0 &&
857 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300858 u8 i;
859
Jouni Malinen11869be2011-09-02 20:07:06 +0300860 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300861
862 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
863 if (channels == NULL) {
864 ath6kl_warn("failed to set scan channels, "
865 "scan all channels");
866 n_channels = 0;
867 }
868
869 for (i = 0; i < n_channels; i++)
870 channels[i] = request->channels[i]->center_freq;
871 }
872
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530873 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530874 force_fg_scan = 1;
875
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530876 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
877 force_fg_scan, false, 0, 0, n_channels,
878 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300879 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300880 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300881 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530882 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300883
Edward Lu1276c9e2011-08-30 21:58:00 +0300884 kfree(channels);
885
Kalle Valobdcd8172011-07-18 00:22:30 +0300886 return ret;
887}
888
Kalle Valo1c17d312011-11-01 08:43:56 +0200889void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300890{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530891 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300892 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300893
Kalle Valo1c17d312011-11-01 08:43:56 +0200894 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
895 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300896
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530897 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300898 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300899
Kalle Valo1c17d312011-11-01 08:43:56 +0200900 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300901 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300902
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530903 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
904 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530905 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
906 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300907 0, NULL);
908 }
909 }
910
911out:
Kalle Valocb938212011-10-27 18:47:46 +0300912 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530913 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300914}
915
916static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
917 u8 key_index, bool pairwise,
918 const u8 *mac_addr,
919 struct key_params *params)
920{
Kalle Valod6d5c062011-11-25 13:17:37 +0200921 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530922 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300923 struct ath6kl_key *key = NULL;
924 u8 key_usage;
925 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300926
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530927 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300928 return -EIO;
929
Jouni Malinen837cb972011-10-11 17:31:57 +0300930 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
931 if (params->key_len != WMI_KRK_LEN)
932 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530933 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
934 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300935 }
936
Kalle Valobdcd8172011-07-18 00:22:30 +0300937 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
938 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
939 "%s: key index %d out of bounds\n", __func__,
940 key_index);
941 return -ENOENT;
942 }
943
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530944 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300945 memset(key, 0, sizeof(struct ath6kl_key));
946
947 if (pairwise)
948 key_usage = PAIRWISE_USAGE;
949 else
950 key_usage = GROUP_USAGE;
951
952 if (params) {
Dai Shuibing5e070212011-11-03 11:39:37 +0200953 int seq_len = params->seq_len;
954 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
955 seq_len > ATH6KL_KEY_SEQ_LEN) {
956 /* Only first half of the WPI PN is configured */
957 seq_len = ATH6KL_KEY_SEQ_LEN;
958 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300959 if (params->key_len > WLAN_MAX_KEY_LEN ||
Dai Shuibing5e070212011-11-03 11:39:37 +0200960 seq_len > sizeof(key->seq))
Kalle Valobdcd8172011-07-18 00:22:30 +0300961 return -EINVAL;
962
963 key->key_len = params->key_len;
964 memcpy(key->key, params->key, key->key_len);
Dai Shuibing5e070212011-11-03 11:39:37 +0200965 key->seq_len = seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300966 memcpy(key->seq, params->seq, key->seq_len);
967 key->cipher = params->cipher;
968 }
969
970 switch (key->cipher) {
971 case WLAN_CIPHER_SUITE_WEP40:
972 case WLAN_CIPHER_SUITE_WEP104:
973 key_type = WEP_CRYPT;
974 break;
975
976 case WLAN_CIPHER_SUITE_TKIP:
977 key_type = TKIP_CRYPT;
978 break;
979
980 case WLAN_CIPHER_SUITE_CCMP:
981 key_type = AES_CRYPT;
982 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200983 case WLAN_CIPHER_SUITE_SMS4:
984 key_type = WAPI_CRYPT;
985 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300986
987 default:
988 return -ENOTSUPP;
989 }
990
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530991 if (((vif->auth_mode == WPA_PSK_AUTH)
992 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300993 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530994 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300995
996 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
997 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
998 __func__, key_index, key->key_len, key_type,
999 key_usage, key->seq_len);
1000
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301001 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001002 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
1003 key_type == WAPI_CRYPT) && params) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001004 ar->ap_mode_bkey.valid = true;
1005 ar->ap_mode_bkey.key_index = key_index;
1006 ar->ap_mode_bkey.key_type = key_type;
1007 ar->ap_mode_bkey.key_len = key->key_len;
1008 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301009 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001010 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1011 "key configuration until AP mode has been "
1012 "started\n");
1013 /*
1014 * The key will be set in ath6kl_connect_ap_mode() once
1015 * the connected event is received from the target.
1016 */
1017 return 0;
1018 }
1019 }
1020
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301021 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301022 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001023 /*
1024 * Store the key locally so that it can be re-configured after
1025 * the AP mode has properly started
1026 * (ath6kl_install_statioc_wep_keys).
1027 */
1028 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1029 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301030 vif->wep_key_list[key_index].key_len = key->key_len;
1031 memcpy(vif->wep_key_list[key_index].key, key->key,
1032 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001033 return 0;
1034 }
1035
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301036 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001037 key_type, key_usage, key->key_len,
1038 key->seq, key->seq_len, key->key,
1039 KEY_OP_INIT_VAL,
1040 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001041}
1042
1043static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1044 u8 key_index, bool pairwise,
1045 const u8 *mac_addr)
1046{
Kalle Valod6d5c062011-11-25 13:17:37 +02001047 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301048 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001049
1050 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1051
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301052 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001053 return -EIO;
1054
1055 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1056 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1057 "%s: key index %d out of bounds\n", __func__,
1058 key_index);
1059 return -ENOENT;
1060 }
1061
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301062 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001063 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1064 "%s: index %d is empty\n", __func__, key_index);
1065 return 0;
1066 }
1067
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301068 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001069
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301070 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001071}
1072
1073static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1074 u8 key_index, bool pairwise,
1075 const u8 *mac_addr, void *cookie,
1076 void (*callback) (void *cookie,
1077 struct key_params *))
1078{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301079 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001080 struct ath6kl_key *key = NULL;
1081 struct key_params params;
1082
1083 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1084
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301085 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001086 return -EIO;
1087
1088 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1089 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1090 "%s: key index %d out of bounds\n", __func__,
1091 key_index);
1092 return -ENOENT;
1093 }
1094
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301095 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001096 memset(&params, 0, sizeof(params));
1097 params.cipher = key->cipher;
1098 params.key_len = key->key_len;
1099 params.seq_len = key->seq_len;
1100 params.seq = key->seq;
1101 params.key = key->key;
1102
1103 callback(cookie, &params);
1104
1105 return key->key_len ? 0 : -ENOENT;
1106}
1107
1108static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1109 struct net_device *ndev,
1110 u8 key_index, bool unicast,
1111 bool multicast)
1112{
Kalle Valod6d5c062011-11-25 13:17:37 +02001113 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301114 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001115 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001116 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001117 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001118
1119 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1120
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301121 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001122 return -EIO;
1123
1124 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1125 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1126 "%s: key index %d out of bounds\n",
1127 __func__, key_index);
1128 return -ENOENT;
1129 }
1130
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301131 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001132 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1133 __func__, key_index);
1134 return -EINVAL;
1135 }
1136
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301137 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301138 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001139 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301140 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001141 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001142 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301143 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001144 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301145 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001146
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301147 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001148 return 0; /* Delay until AP mode has been started */
1149
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001150 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1151 vif->def_txkey_index,
1152 key_type, key_usage,
1153 key->key_len, key->seq, key->seq_len,
1154 key->key,
1155 KEY_OP_INIT_VAL, NULL,
1156 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001157}
1158
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301159void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001160 bool ismcast)
1161{
1162 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1163 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1164
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301165 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001166 (ismcast ? NL80211_KEYTYPE_GROUP :
1167 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1168 GFP_KERNEL);
1169}
1170
1171static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1172{
1173 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301174 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001175 int ret;
1176
1177 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1178 changed);
1179
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301180 vif = ath6kl_vif_first(ar);
1181 if (!vif)
1182 return -EIO;
1183
1184 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001185 return -EIO;
1186
1187 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1188 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1189 if (ret != 0) {
1190 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1191 return -EIO;
1192 }
1193 }
1194
1195 return 0;
1196}
1197
1198/*
1199 * The type nl80211_tx_power_setting replaces the following
1200 * data type from 2.6.36 onwards
1201*/
1202static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1203 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001204 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001205{
1206 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301207 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001208 u8 ath6kl_dbm;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001209 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001210
1211 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1212 type, dbm);
1213
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301214 vif = ath6kl_vif_first(ar);
1215 if (!vif)
1216 return -EIO;
1217
1218 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001219 return -EIO;
1220
1221 switch (type) {
1222 case NL80211_TX_POWER_AUTOMATIC:
1223 return 0;
1224 case NL80211_TX_POWER_LIMITED:
1225 ar->tx_pwr = ath6kl_dbm = dbm;
1226 break;
1227 default:
1228 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1229 __func__, type);
1230 return -EOPNOTSUPP;
1231 }
1232
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301233 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001234
1235 return 0;
1236}
1237
1238static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1239{
1240 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301241 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001242
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301243 vif = ath6kl_vif_first(ar);
1244 if (!vif)
1245 return -EIO;
1246
1247 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001248 return -EIO;
1249
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301250 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001251 ar->tx_pwr = 0;
1252
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301253 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001254 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1255 return -EIO;
1256 }
1257
1258 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1259 5 * HZ);
1260
1261 if (signal_pending(current)) {
1262 ath6kl_err("target did not respond\n");
1263 return -EINTR;
1264 }
1265 }
1266
1267 *dbm = ar->tx_pwr;
1268 return 0;
1269}
1270
1271static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1272 struct net_device *dev,
1273 bool pmgmt, int timeout)
1274{
1275 struct ath6kl *ar = ath6kl_priv(dev);
1276 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301277 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001278
1279 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1280 __func__, pmgmt, timeout);
1281
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301282 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001283 return -EIO;
1284
1285 if (pmgmt) {
1286 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1287 mode.pwr_mode = REC_POWER;
1288 } else {
1289 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1290 mode.pwr_mode = MAX_PERF_POWER;
1291 }
1292
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301293 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1294 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001295 ath6kl_err("wmi_powermode_cmd failed\n");
1296 return -EIO;
1297 }
1298
1299 return 0;
1300}
1301
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301302static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1303 char *name,
1304 enum nl80211_iftype type,
1305 u32 *flags,
1306 struct vif_params *params)
1307{
1308 struct ath6kl *ar = wiphy_priv(wiphy);
1309 struct net_device *ndev;
1310 u8 if_idx, nw_type;
1311
Kalle Valo71f96ee2011-11-14 19:31:30 +02001312 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301313 ath6kl_err("Reached maximum number of supported vif\n");
1314 return ERR_PTR(-EINVAL);
1315 }
1316
1317 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1318 ath6kl_err("Not a supported interface type\n");
1319 return ERR_PTR(-EINVAL);
1320 }
1321
1322 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1323 if (!ndev)
1324 return ERR_PTR(-ENOMEM);
1325
1326 ar->num_vif++;
1327
1328 return ndev;
1329}
1330
1331static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1332 struct net_device *ndev)
1333{
1334 struct ath6kl *ar = wiphy_priv(wiphy);
1335 struct ath6kl_vif *vif = netdev_priv(ndev);
1336
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301337 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301338 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301339 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301340
1341 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1342
1343 ath6kl_deinit_if_data(vif);
1344
1345 return 0;
1346}
1347
Kalle Valobdcd8172011-07-18 00:22:30 +03001348static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1349 struct net_device *ndev,
1350 enum nl80211_iftype type, u32 *flags,
1351 struct vif_params *params)
1352{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301353 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001354
1355 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1356
Kalle Valobdcd8172011-07-18 00:22:30 +03001357 switch (type) {
1358 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301359 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001360 break;
1361 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301362 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001363 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001364 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301365 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001366 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001367 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301368 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001369 break;
1370 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301371 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001372 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001373 default:
1374 ath6kl_err("invalid interface type %u\n", type);
1375 return -EOPNOTSUPP;
1376 }
1377
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301378 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001379
1380 return 0;
1381}
1382
1383static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1384 struct net_device *dev,
1385 struct cfg80211_ibss_params *ibss_param)
1386{
1387 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301388 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001389 int status;
1390
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301391 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001392 return -EIO;
1393
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301394 vif->ssid_len = ibss_param->ssid_len;
1395 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001396
1397 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301398 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001399
1400 if (ibss_param->channel_fixed) {
1401 /*
1402 * TODO: channel_fixed: The channel should be fixed, do not
1403 * search for IBSSs to join on other channels. Target
1404 * firmware does not support this feature, needs to be
1405 * updated.
1406 */
1407 return -EOPNOTSUPP;
1408 }
1409
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301410 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001411 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301412 memcpy(vif->req_bssid, ibss_param->bssid,
1413 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001414
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301415 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001416
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301417 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001418 if (status)
1419 return status;
1420
1421 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301422 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1423 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001424 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301425 ath6kl_set_cipher(vif, 0, true);
1426 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001427 }
1428
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301429 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001430
1431 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1432 "%s: connect called with authmode %d dot11 auth %d"
1433 " PW crypto %d PW crypto len %d GRP crypto %d"
1434 " GRP crypto len %d channel hint %u\n",
1435 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301436 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1437 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301438 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001439
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301440 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301441 vif->dot11_auth_mode, vif->auth_mode,
1442 vif->prwise_crypto,
1443 vif->prwise_crypto_len,
1444 vif->grp_crypto, vif->grp_crypto_len,
1445 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301446 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001447 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301448 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001449
1450 return 0;
1451}
1452
1453static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1454 struct net_device *dev)
1455{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301456 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001457
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301458 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001459 return -EIO;
1460
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301461 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301462 memset(vif->ssid, 0, sizeof(vif->ssid));
1463 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001464
1465 return 0;
1466}
1467
1468static const u32 cipher_suites[] = {
1469 WLAN_CIPHER_SUITE_WEP40,
1470 WLAN_CIPHER_SUITE_WEP104,
1471 WLAN_CIPHER_SUITE_TKIP,
1472 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001473 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001474 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001475};
1476
1477static bool is_rate_legacy(s32 rate)
1478{
1479 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1480 6000, 9000, 12000, 18000, 24000,
1481 36000, 48000, 54000
1482 };
1483 u8 i;
1484
1485 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1486 if (rate == legacy[i])
1487 return true;
1488
1489 return false;
1490}
1491
1492static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1493{
1494 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1495 52000, 58500, 65000, 72200
1496 };
1497 u8 i;
1498
1499 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1500 if (rate == ht20[i]) {
1501 if (i == ARRAY_SIZE(ht20) - 1)
1502 /* last rate uses sgi */
1503 *sgi = true;
1504 else
1505 *sgi = false;
1506
1507 *mcs = i;
1508 return true;
1509 }
1510 }
1511 return false;
1512}
1513
1514static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1515{
1516 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1517 81000, 108000, 121500, 135000,
1518 150000
1519 };
1520 u8 i;
1521
1522 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1523 if (rate == ht40[i]) {
1524 if (i == ARRAY_SIZE(ht40) - 1)
1525 /* last rate uses sgi */
1526 *sgi = true;
1527 else
1528 *sgi = false;
1529
1530 *mcs = i;
1531 return true;
1532 }
1533 }
1534
1535 return false;
1536}
1537
1538static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1539 u8 *mac, struct station_info *sinfo)
1540{
1541 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301542 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001543 long left;
1544 bool sgi;
1545 s32 rate;
1546 int ret;
1547 u8 mcs;
1548
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301549 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001550 return -ENOENT;
1551
1552 if (down_interruptible(&ar->sem))
1553 return -EBUSY;
1554
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301555 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001556
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301557 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001558
1559 if (ret != 0) {
1560 up(&ar->sem);
1561 return -EIO;
1562 }
1563
1564 left = wait_event_interruptible_timeout(ar->event_wq,
1565 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301566 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001567 WMI_TIMEOUT);
1568
1569 up(&ar->sem);
1570
1571 if (left == 0)
1572 return -ETIMEDOUT;
1573 else if (left < 0)
1574 return left;
1575
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301576 if (vif->target_stats.rx_byte) {
1577 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001578 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301579 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001580 sinfo->filled |= STATION_INFO_RX_PACKETS;
1581 }
1582
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301583 if (vif->target_stats.tx_byte) {
1584 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001585 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301586 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001587 sinfo->filled |= STATION_INFO_TX_PACKETS;
1588 }
1589
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301590 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001591 sinfo->filled |= STATION_INFO_SIGNAL;
1592
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301593 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001594
1595 if (is_rate_legacy(rate)) {
1596 sinfo->txrate.legacy = rate / 100;
1597 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1598 if (sgi) {
1599 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1600 sinfo->txrate.mcs = mcs - 1;
1601 } else {
1602 sinfo->txrate.mcs = mcs;
1603 }
1604
1605 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1606 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1607 if (sgi) {
1608 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1609 sinfo->txrate.mcs = mcs - 1;
1610 } else {
1611 sinfo->txrate.mcs = mcs;
1612 }
1613
1614 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1615 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1616 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001617 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1618 "invalid rate from stats: %d\n", rate);
1619 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001620 return 0;
1621 }
1622
1623 sinfo->filled |= STATION_INFO_TX_BITRATE;
1624
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301625 if (test_bit(CONNECTED, &vif->flags) &&
1626 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301627 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001628 sinfo->filled |= STATION_INFO_BSS_PARAM;
1629 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301630 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1631 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001632 }
1633
Kalle Valobdcd8172011-07-18 00:22:30 +03001634 return 0;
1635}
1636
1637static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1638 struct cfg80211_pmksa *pmksa)
1639{
1640 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301641 struct ath6kl_vif *vif = netdev_priv(netdev);
1642
1643 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001644 pmksa->pmkid, true);
1645}
1646
1647static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1648 struct cfg80211_pmksa *pmksa)
1649{
1650 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301651 struct ath6kl_vif *vif = netdev_priv(netdev);
1652
1653 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001654 pmksa->pmkid, false);
1655}
1656
1657static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1658{
1659 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301660 struct ath6kl_vif *vif = netdev_priv(netdev);
1661
1662 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301663 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1664 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001665 return 0;
1666}
1667
Raja Mani6cb3c712011-11-07 22:52:45 +02001668static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1669{
1670 struct ath6kl_vif *vif;
1671 int ret, pos, left;
1672 u32 filter = 0;
1673 u16 i;
1674 u8 mask[WOW_MASK_SIZE];
1675
1676 vif = ath6kl_vif_first(ar);
1677 if (!vif)
1678 return -EIO;
1679
1680 if (!ath6kl_cfg80211_ready(vif))
1681 return -EIO;
1682
1683 if (!test_bit(CONNECTED, &vif->flags))
1684 return -EINVAL;
1685
1686 /* Clear existing WOW patterns */
1687 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
1688 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
1689 WOW_LIST_ID, i);
1690 /* Configure new WOW patterns */
1691 for (i = 0; i < wow->n_patterns; i++) {
1692
1693 /*
1694 * Convert given nl80211 specific mask value to equivalent
1695 * driver specific mask value and send it to the chip along
1696 * with patterns. For example, If the mask value defined in
1697 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1698 * then equivalent driver specific mask value is
1699 * "0xFF 0x00 0xFF 0x00".
1700 */
1701 memset(&mask, 0, sizeof(mask));
1702 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1703 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1704 mask[pos] = 0xFF;
1705 }
1706 /*
1707 * Note: Pattern's offset is not passed as part of wowlan
1708 * parameter from CFG layer. So it's always passed as ZERO
1709 * to the firmware. It means, given WOW patterns are always
1710 * matched from the first byte of received pkt in the firmware.
1711 */
1712 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1713 vif->fw_vif_idx, WOW_LIST_ID,
1714 wow->patterns[i].pattern_len,
1715 0 /* pattern offset */,
1716 wow->patterns[i].pattern, mask);
1717 if (ret)
1718 return ret;
1719 }
1720
1721 if (wow->disconnect)
1722 filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1723
1724 if (wow->magic_pkt)
1725 filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1726
1727 if (wow->gtk_rekey_failure)
1728 filter |= WOW_FILTER_OPTION_GTK_ERROR;
1729
1730 if (wow->eap_identity_req)
1731 filter |= WOW_FILTER_OPTION_EAP_REQ;
1732
1733 if (wow->four_way_handshake)
1734 filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1735
1736 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
1737 ATH6KL_WOW_MODE_ENABLE,
1738 filter,
1739 WOW_HOST_REQ_DELAY);
1740 if (ret)
1741 return ret;
1742
1743 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1744 ATH6KL_HOST_MODE_ASLEEP);
1745 if (ret)
1746 return ret;
1747
1748 if (ar->tx_pending[ar->ctrl_ep]) {
1749 left = wait_event_interruptible_timeout(ar->event_wq,
1750 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
1751 if (left == 0) {
1752 ath6kl_warn("clear wmi ctrl data timeout\n");
1753 ret = -ETIMEDOUT;
1754 } else if (left < 0) {
1755 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
1756 ret = left;
1757 }
1758 }
1759
1760 return ret;
1761}
1762
1763static int ath6kl_wow_resume(struct ath6kl *ar)
1764{
1765 struct ath6kl_vif *vif;
1766 int ret;
1767
1768 vif = ath6kl_vif_first(ar);
1769 if (!vif)
1770 return -EIO;
1771
1772 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1773 ATH6KL_HOST_MODE_AWAKE);
1774 return ret;
1775}
1776
Kalle Valo52d81a62011-11-01 08:44:21 +02001777int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02001778 enum ath6kl_cfg_suspend_mode mode,
1779 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02001780{
1781 int ret;
1782
Kalle Valo52d81a62011-11-01 08:44:21 +02001783 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02001784 case ATH6KL_CFG_SUSPEND_WOW:
1785
1786 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
1787
1788 /* Flush all non control pkts in TX path */
1789 ath6kl_tx_data_cleanup(ar);
1790
1791 ret = ath6kl_wow_suspend(ar, wow);
1792 if (ret) {
1793 ath6kl_err("wow suspend failed: %d\n", ret);
1794 return ret;
1795 }
1796 ar->state = ATH6KL_STATE_WOW;
1797 break;
1798
Kalle Valo52d81a62011-11-01 08:44:21 +02001799 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02001800
1801 ath6kl_cfg80211_stop(ar);
1802
Kalle Valo52d81a62011-11-01 08:44:21 +02001803 /* save the current power mode before enabling power save */
1804 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
1805
1806 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
1807 if (ret) {
1808 ath6kl_warn("wmi powermode command failed during suspend: %d\n",
1809 ret);
1810 }
1811
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001812 ar->state = ATH6KL_STATE_DEEPSLEEP;
1813
Kalle Valo52d81a62011-11-01 08:44:21 +02001814 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001815
1816 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02001817
1818 ath6kl_cfg80211_stop(ar);
1819
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001820 if (ar->state == ATH6KL_STATE_OFF) {
1821 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
1822 "suspend hw off, no action for cutpower\n");
1823 break;
1824 }
1825
1826 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
1827
1828 ret = ath6kl_init_hw_stop(ar);
1829 if (ret) {
1830 ath6kl_warn("failed to stop hw during suspend: %d\n",
1831 ret);
1832 }
1833
1834 ar->state = ATH6KL_STATE_CUTPOWER;
1835
1836 break;
1837
1838 default:
1839 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001840 }
1841
1842 return 0;
1843}
1844
1845int ath6kl_cfg80211_resume(struct ath6kl *ar)
1846{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001847 int ret;
1848
1849 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02001850 case ATH6KL_STATE_WOW:
1851 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
1852
1853 ret = ath6kl_wow_resume(ar);
1854 if (ret) {
1855 ath6kl_warn("wow mode resume failed: %d\n", ret);
1856 return ret;
1857 }
1858
1859 ar->state = ATH6KL_STATE_ON;
1860 break;
1861
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001862 case ATH6KL_STATE_DEEPSLEEP:
1863 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
1864 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
1865 ar->wmi->saved_pwr_mode);
1866 if (ret) {
1867 ath6kl_warn("wmi powermode command failed during resume: %d\n",
1868 ret);
1869 }
1870 }
1871
1872 ar->state = ATH6KL_STATE_ON;
1873
1874 break;
1875
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001876 case ATH6KL_STATE_CUTPOWER:
1877 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
1878
1879 ret = ath6kl_init_hw_start(ar);
1880 if (ret) {
1881 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
1882 return ret;
1883 }
Raja Manid7c44e02011-11-07 22:52:46 +02001884 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02001885
Kalle Valo76a9fbe2011-11-01 08:44:28 +02001886 default:
1887 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02001888 }
1889
1890 return 0;
1891}
1892
Kalle Valoabcb3442011-07-22 08:26:20 +03001893#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02001894
1895/* hif layer decides what suspend mode to use */
1896static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03001897 struct cfg80211_wowlan *wow)
1898{
1899 struct ath6kl *ar = wiphy_priv(wiphy);
1900
Raja Mani0f60e9f2011-11-07 22:52:45 +02001901 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03001902}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001903
Kalle Valo52d81a62011-11-01 08:44:21 +02001904static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001905{
1906 struct ath6kl *ar = wiphy_priv(wiphy);
1907
1908 return ath6kl_hif_resume(ar);
1909}
Raja Mania918fb32011-11-07 22:52:46 +02001910
1911/*
1912 * FIXME: WOW suspend mode is selected if the host sdio controller supports
1913 * both sdio irq wake up and keep power. The target pulls sdio data line to
1914 * wake up the host when WOW pattern matches. This causes sdio irq handler
1915 * is being called in the host side which internally hits ath6kl's RX path.
1916 *
1917 * Since sdio interrupt is not disabled, RX path executes even before
1918 * the host executes the actual resume operation from PM module.
1919 *
1920 * In the current scenario, WOW resume should happen before start processing
1921 * any data from the target. So It's required to perform WOW resume in RX path.
1922 * Ideally we should perform WOW resume only in the actual platform
1923 * resume path. This area needs bit rework to avoid WOW resume in RX path.
1924 *
1925 * ath6kl_check_wow_status() is called from ath6kl_rx().
1926 */
1927void ath6kl_check_wow_status(struct ath6kl *ar)
1928{
1929 if (ar->state == ATH6KL_STATE_WOW)
1930 ath6kl_cfg80211_resume(ar);
1931}
1932
1933#else
1934
1935void ath6kl_check_wow_status(struct ath6kl *ar)
1936{
1937}
Kalle Valoabcb3442011-07-22 08:26:20 +03001938#endif
1939
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001940static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1941 struct ieee80211_channel *chan,
1942 enum nl80211_channel_type channel_type)
1943{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301944 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001945
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301946 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001947 return -EIO;
1948
1949 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1950 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301951 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001952
1953 return 0;
1954}
1955
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001956static bool ath6kl_is_p2p_ie(const u8 *pos)
1957{
1958 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1959 pos[2] == 0x50 && pos[3] == 0x6f &&
1960 pos[4] == 0x9a && pos[5] == 0x09;
1961}
1962
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301963static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1964 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001965{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301966 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001967 const u8 *pos;
1968 u8 *buf = NULL;
1969 size_t len = 0;
1970 int ret;
1971
1972 /*
1973 * Filter out P2P IE(s) since they will be included depending on
1974 * the Probe Request frame in ath6kl_send_go_probe_resp().
1975 */
1976
1977 if (ies && ies_len) {
1978 buf = kmalloc(ies_len, GFP_KERNEL);
1979 if (buf == NULL)
1980 return -ENOMEM;
1981 pos = ies;
1982 while (pos + 1 < ies + ies_len) {
1983 if (pos + 2 + pos[1] > ies + ies_len)
1984 break;
1985 if (!ath6kl_is_p2p_ie(pos)) {
1986 memcpy(buf + len, pos, 2 + pos[1]);
1987 len += 2 + pos[1];
1988 }
1989 pos += 2 + pos[1];
1990 }
1991 }
1992
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301993 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1994 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001995 kfree(buf);
1996 return ret;
1997}
1998
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001999static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
2000 struct beacon_parameters *info, bool add)
2001{
2002 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302003 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002004 struct ieee80211_mgmt *mgmt;
2005 u8 *ies;
2006 int ies_len;
2007 struct wmi_connect_cmd p;
2008 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302009 int i, ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002010
2011 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
2012
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302013 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002014 return -EIO;
2015
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302016 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002017 return -EOPNOTSUPP;
2018
2019 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302020 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2021 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002022 info->beacon_ies,
2023 info->beacon_ies_len);
2024 if (res)
2025 return res;
2026 }
2027 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302028 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002029 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002030 if (res)
2031 return res;
2032 }
2033 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302034 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2035 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002036 info->assocresp_ies,
2037 info->assocresp_ies_len);
2038 if (res)
2039 return res;
2040 }
2041
2042 if (!add)
2043 return 0;
2044
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002045 ar->ap_mode_bkey.valid = false;
2046
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002047 /* TODO:
2048 * info->interval
2049 * info->dtim_period
2050 */
2051
2052 if (info->head == NULL)
2053 return -EINVAL;
2054 mgmt = (struct ieee80211_mgmt *) info->head;
2055 ies = mgmt->u.beacon.variable;
2056 if (ies > info->head + info->head_len)
2057 return -EINVAL;
2058 ies_len = info->head + info->head_len - ies;
2059
2060 if (info->ssid == NULL)
2061 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302062 memcpy(vif->ssid, info->ssid, info->ssid_len);
2063 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002064 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
2065 return -EOPNOTSUPP; /* TODO */
2066
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302067 ret = ath6kl_set_auth_type(vif, info->auth_type);
2068 if (ret)
2069 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002070
2071 memset(&p, 0, sizeof(p));
2072
2073 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2074 switch (info->crypto.akm_suites[i]) {
2075 case WLAN_AKM_SUITE_8021X:
2076 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2077 p.auth_mode |= WPA_AUTH;
2078 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2079 p.auth_mode |= WPA2_AUTH;
2080 break;
2081 case WLAN_AKM_SUITE_PSK:
2082 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2083 p.auth_mode |= WPA_PSK_AUTH;
2084 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2085 p.auth_mode |= WPA2_PSK_AUTH;
2086 break;
2087 }
2088 }
2089 if (p.auth_mode == 0)
2090 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302091 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002092
2093 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2094 switch (info->crypto.ciphers_pairwise[i]) {
2095 case WLAN_CIPHER_SUITE_WEP40:
2096 case WLAN_CIPHER_SUITE_WEP104:
2097 p.prwise_crypto_type |= WEP_CRYPT;
2098 break;
2099 case WLAN_CIPHER_SUITE_TKIP:
2100 p.prwise_crypto_type |= TKIP_CRYPT;
2101 break;
2102 case WLAN_CIPHER_SUITE_CCMP:
2103 p.prwise_crypto_type |= AES_CRYPT;
2104 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002105 case WLAN_CIPHER_SUITE_SMS4:
2106 p.prwise_crypto_type |= WAPI_CRYPT;
2107 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002108 }
2109 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002110 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002111 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302112 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002113 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302114 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002115
2116 switch (info->crypto.cipher_group) {
2117 case WLAN_CIPHER_SUITE_WEP40:
2118 case WLAN_CIPHER_SUITE_WEP104:
2119 p.grp_crypto_type = WEP_CRYPT;
2120 break;
2121 case WLAN_CIPHER_SUITE_TKIP:
2122 p.grp_crypto_type = TKIP_CRYPT;
2123 break;
2124 case WLAN_CIPHER_SUITE_CCMP:
2125 p.grp_crypto_type = AES_CRYPT;
2126 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002127 case WLAN_CIPHER_SUITE_SMS4:
2128 p.grp_crypto_type = WAPI_CRYPT;
2129 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002130 default:
2131 p.grp_crypto_type = NONE_CRYPT;
2132 break;
2133 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302134 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002135
2136 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302137 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002138
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302139 p.ssid_len = vif->ssid_len;
2140 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2141 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302142 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002143
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302144 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002145 if (res < 0)
2146 return res;
2147
2148 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002149}
2150
2151static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
2152 struct beacon_parameters *info)
2153{
2154 return ath6kl_ap_beacon(wiphy, dev, info, true);
2155}
2156
2157static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
2158 struct beacon_parameters *info)
2159{
2160 return ath6kl_ap_beacon(wiphy, dev, info, false);
2161}
2162
2163static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
2164{
2165 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302166 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002167
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302168 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002169 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302170 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002171 return -ENOTCONN;
2172
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302173 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302174 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002175
2176 return 0;
2177}
2178
Jouni Malinen23875132011-08-30 21:57:53 +03002179static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2180 u8 *mac, struct station_parameters *params)
2181{
2182 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302183 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002184
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302185 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002186 return -EOPNOTSUPP;
2187
2188 /* Use this only for authorizing/unauthorizing a station */
2189 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2190 return -EOPNOTSUPP;
2191
2192 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302193 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2194 WMI_AP_MLME_AUTHORIZE, mac, 0);
2195 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2196 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002197}
2198
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002199static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2200 struct net_device *dev,
2201 struct ieee80211_channel *chan,
2202 enum nl80211_channel_type channel_type,
2203 unsigned int duration,
2204 u64 *cookie)
2205{
2206 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302207 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002208 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002209
2210 /* TODO: if already pending or ongoing remain-on-channel,
2211 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002212 id = ++vif->last_roc_id;
2213 if (id == 0) {
2214 /* Do not use 0 as the cookie value */
2215 id = ++vif->last_roc_id;
2216 }
2217 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002218
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302219 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2220 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002221}
2222
2223static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2224 struct net_device *dev,
2225 u64 cookie)
2226{
2227 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302228 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002229
Jouni Malinen10522612011-10-27 16:00:13 +03002230 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002231 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002232 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002233
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302234 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002235}
2236
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302237static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2238 const u8 *buf, size_t len,
2239 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002240{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302241 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002242 const u8 *pos;
2243 u8 *p2p;
2244 int p2p_len;
2245 int ret;
2246 const struct ieee80211_mgmt *mgmt;
2247
2248 mgmt = (const struct ieee80211_mgmt *) buf;
2249
2250 /* Include P2P IE(s) from the frame generated in user space. */
2251
2252 p2p = kmalloc(len, GFP_KERNEL);
2253 if (p2p == NULL)
2254 return -ENOMEM;
2255 p2p_len = 0;
2256
2257 pos = mgmt->u.probe_resp.variable;
2258 while (pos + 1 < buf + len) {
2259 if (pos + 2 + pos[1] > buf + len)
2260 break;
2261 if (ath6kl_is_p2p_ie(pos)) {
2262 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2263 p2p_len += 2 + pos[1];
2264 }
2265 pos += 2 + pos[1];
2266 }
2267
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302268 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2269 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002270 kfree(p2p);
2271 return ret;
2272}
2273
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002274static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2275 struct ieee80211_channel *chan, bool offchan,
2276 enum nl80211_channel_type channel_type,
2277 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002278 const u8 *buf, size_t len, bool no_cck,
2279 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002280{
2281 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302282 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002283 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002284 const struct ieee80211_mgmt *mgmt;
2285
2286 mgmt = (const struct ieee80211_mgmt *) buf;
2287 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302288 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002289 ieee80211_is_probe_resp(mgmt->frame_control)) {
2290 /*
2291 * Send Probe Response frame in AP mode using a separate WMI
2292 * command to allow the target to fill in the generic IEs.
2293 */
2294 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302295 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002296 chan->center_freq);
2297 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002298
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302299 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002300 if (id == 0) {
2301 /*
2302 * 0 is a reserved value in the WMI command and shall not be
2303 * used for the command.
2304 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302305 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002306 }
2307
2308 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302309 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2310 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002311 buf, len);
2312}
2313
Jouni Malinenae32c302011-08-30 21:58:01 +03002314static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2315 struct net_device *dev,
2316 u16 frame_type, bool reg)
2317{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302318 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002319
2320 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2321 __func__, frame_type, reg);
2322 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2323 /*
2324 * Note: This notification callback is not allowed to sleep, so
2325 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2326 * hardcode target to report Probe Request frames all the time.
2327 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302328 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002329 }
2330}
2331
Jouni Malinenf80574a2011-08-30 21:58:04 +03002332static const struct ieee80211_txrx_stypes
2333ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2334 [NL80211_IFTYPE_STATION] = {
2335 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2336 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2337 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2338 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2339 },
2340 [NL80211_IFTYPE_P2P_CLIENT] = {
2341 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2342 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2343 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2344 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2345 },
2346 [NL80211_IFTYPE_P2P_GO] = {
2347 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2348 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2349 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2350 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2351 },
2352};
2353
Kalle Valobdcd8172011-07-18 00:22:30 +03002354static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302355 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2356 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002357 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2358 .scan = ath6kl_cfg80211_scan,
2359 .connect = ath6kl_cfg80211_connect,
2360 .disconnect = ath6kl_cfg80211_disconnect,
2361 .add_key = ath6kl_cfg80211_add_key,
2362 .get_key = ath6kl_cfg80211_get_key,
2363 .del_key = ath6kl_cfg80211_del_key,
2364 .set_default_key = ath6kl_cfg80211_set_default_key,
2365 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2366 .set_tx_power = ath6kl_cfg80211_set_txpower,
2367 .get_tx_power = ath6kl_cfg80211_get_txpower,
2368 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2369 .join_ibss = ath6kl_cfg80211_join_ibss,
2370 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2371 .get_station = ath6kl_get_station,
2372 .set_pmksa = ath6kl_set_pmksa,
2373 .del_pmksa = ath6kl_del_pmksa,
2374 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002375 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002376#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002377 .suspend = __ath6kl_cfg80211_suspend,
2378 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002379#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002380 .set_channel = ath6kl_set_channel,
2381 .add_beacon = ath6kl_add_beacon,
2382 .set_beacon = ath6kl_set_beacon,
2383 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002384 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002385 .remain_on_channel = ath6kl_remain_on_channel,
2386 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002387 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002388 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002389};
2390
Kalle Valoec4b7f62011-11-01 08:44:04 +02002391void ath6kl_cfg80211_stop(struct ath6kl *ar)
2392{
2393 struct ath6kl_vif *vif;
2394
2395 /* FIXME: for multi vif */
2396 vif = ath6kl_vif_first(ar);
2397 if (!vif) {
2398 /* save the current power mode before enabling power save */
2399 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2400
2401 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
2402 ath6kl_warn("ath6kl_deep_sleep_enable: "
2403 "wmi_powermode_cmd failed\n");
2404 return;
2405 }
2406
2407 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02002408 case SME_DISCONNECTED:
2409 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02002410 case SME_CONNECTING:
2411 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
2412 NULL, 0,
2413 WLAN_STATUS_UNSPECIFIED_FAILURE,
2414 GFP_KERNEL);
2415 break;
2416 case SME_CONNECTED:
Kalle Valoec4b7f62011-11-01 08:44:04 +02002417 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
2418 break;
2419 }
2420
2421 if (test_bit(CONNECTED, &vif->flags) ||
2422 test_bit(CONNECT_PEND, &vif->flags))
2423 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2424
2425 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02002426 clear_bit(CONNECTED, &vif->flags);
2427 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02002428
2429 /* disable scanning */
2430 if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
2431 0, 0, 0, 0, 0, 0, 0) != 0)
2432 printk(KERN_WARNING "ath6kl: failed to disable scan "
2433 "during suspend\n");
2434
2435 ath6kl_cfg80211_scan_complete_event(vif, true);
2436}
2437
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302438struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002439{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002440 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302441 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302442 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002443
2444 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302445 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302446
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302447 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002448 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002449 return NULL;
2450 }
2451
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302452 ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan774439a2011-11-18 10:05:26 +05302453 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302454 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302455 ar->dev = dev;
2456
Kalle Valo71f96ee2011-11-14 19:31:30 +02002457 ar->vif_max = 1;
2458
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +05302459 ar->max_norm_iface = 1;
2460
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302461 spin_lock_init(&ar->lock);
2462 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302463 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302464
2465 init_waitqueue_head(&ar->event_wq);
2466 sema_init(&ar->sem, 1);
2467
2468 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302469 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302470
2471 clear_bit(WMI_ENABLED, &ar->flag);
2472 clear_bit(SKIP_SCAN, &ar->flag);
2473 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2474
2475 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2476 ar->listen_intvl_b = 0;
2477 ar->tx_pwr = 0;
2478
2479 ar->intra_bss = 1;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302480 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2481
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002482 ar->state = ATH6KL_STATE_OFF;
2483
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302484 memset((u8 *)ar->sta_list, 0,
2485 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2486
2487 /* Init the PS queues */
2488 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2489 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2490 skb_queue_head_init(&ar->sta_list[ctr].psq);
2491 }
2492
2493 skb_queue_head_init(&ar->mcastpsq);
2494
2495 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2496
2497 return ar;
2498}
2499
2500int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2501{
2502 struct wiphy *wiphy = ar->wiphy;
2503 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002504
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302505 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002506
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302507 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002508
Kalle Valobdcd8172011-07-18 00:22:30 +03002509 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302510 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002511
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302512 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302513 BIT(NL80211_IFTYPE_ADHOC) |
2514 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002515 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302516 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302517 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002518 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302519
Kalle Valobdcd8172011-07-18 00:22:30 +03002520 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302521 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2522 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2523 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2524 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2525 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002526
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302527 wiphy->cipher_suites = cipher_suites;
2528 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002529
Raja Manieae9e062011-11-07 22:52:46 +02002530 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
2531 WIPHY_WOWLAN_DISCONNECT |
2532 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
2533 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
2534 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
2535 WIPHY_WOWLAN_4WAY_HANDSHAKE;
2536 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
2537 wiphy->wowlan.pattern_min_len = 1;
2538 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2539
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302540 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002541 if (ret < 0) {
2542 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302543 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002544 }
2545
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302546 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002547}
2548
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302549static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002550{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302551 vif->aggr_cntxt = aggr_init(vif->ndev);
2552 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302553 ath6kl_err("failed to initialize aggr\n");
2554 return -ENOMEM;
2555 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002556
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302557 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302558 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302559 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302560 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302561
2562 return 0;
2563}
2564
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302565void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302566{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302567 struct ath6kl *ar = vif->ar;
2568
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302569 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302570
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302571 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2572
2573 if (vif->nw_type == ADHOC_NETWORK)
2574 ar->ibss_if_active = false;
2575
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302576 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302577
2578 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302579}
2580
2581struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302582 enum nl80211_iftype type, u8 fw_vif_idx,
2583 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302584{
2585 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302586 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302587
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302588 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302589 if (!ndev)
2590 return NULL;
2591
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302592 vif = netdev_priv(ndev);
2593 ndev->ieee80211_ptr = &vif->wdev;
2594 vif->wdev.wiphy = ar->wiphy;
2595 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302596 vif->ndev = ndev;
2597 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2598 vif->wdev.netdev = ndev;
2599 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302600 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302601 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302602
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302603 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2604 if (fw_vif_idx != 0)
2605 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2606 0x2;
2607
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302608 init_netdev(ndev);
2609
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302610 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302611
2612 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302613 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302614 goto err;
2615
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302616 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302617 goto err;
2618
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302619 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302620 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302621 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302622 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302623 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302624
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302625 if (type == NL80211_IFTYPE_ADHOC)
2626 ar->ibss_if_active = true;
2627
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302628 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302629 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05302630 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302631
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302632 return ndev;
2633
2634err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302635 aggr_module_destroy(vif->aggr_cntxt);
2636 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302637 return NULL;
2638}
2639
2640void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2641{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302642 wiphy_unregister(ar->wiphy);
2643 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002644}