blob: 06f12da554e10c244620c3888fb0d8cd36f6378a [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
Vasanthakumar Thiagarajan1b2df402012-02-06 20:15:53 +05303 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
Kalle Valobdcd8172011-07-18 00:22:30 +03004 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040018#include <linux/moduleparam.h>
Raja Manic08631c2011-12-16 14:24:24 +053019#include <linux/inetdevice.h>
Kalle Valod6a434d2012-01-17 20:09:36 +020020#include <linux/export.h>
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040021
Kalle Valobdcd8172011-07-18 00:22:30 +030022#include "core.h"
23#include "cfg80211.h"
24#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030025#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030026#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030027
28#define RATETAB_ENT(_rate, _rateid, _flags) { \
29 .bitrate = (_rate), \
30 .flags = (_flags), \
31 .hw_value = (_rateid), \
32}
33
34#define CHAN2G(_channel, _freq, _flags) { \
35 .band = IEEE80211_BAND_2GHZ, \
36 .hw_value = (_channel), \
37 .center_freq = (_freq), \
38 .flags = (_flags), \
39 .max_antenna_gain = 0, \
40 .max_power = 30, \
41}
42
43#define CHAN5G(_channel, _flags) { \
44 .band = IEEE80211_BAND_5GHZ, \
45 .hw_value = (_channel), \
46 .center_freq = 5000 + (5 * (_channel)), \
47 .flags = (_flags), \
48 .max_antenna_gain = 0, \
49 .max_power = 30, \
50}
51
Bala Shanmugamf5993592012-03-27 12:17:32 +053052#define DEFAULT_BG_SCAN_PERIOD 60
53
Kalle Valobdcd8172011-07-18 00:22:30 +030054static struct ieee80211_rate ath6kl_rates[] = {
55 RATETAB_ENT(10, 0x1, 0),
56 RATETAB_ENT(20, 0x2, 0),
57 RATETAB_ENT(55, 0x4, 0),
58 RATETAB_ENT(110, 0x8, 0),
59 RATETAB_ENT(60, 0x10, 0),
60 RATETAB_ENT(90, 0x20, 0),
61 RATETAB_ENT(120, 0x40, 0),
62 RATETAB_ENT(180, 0x80, 0),
63 RATETAB_ENT(240, 0x100, 0),
64 RATETAB_ENT(360, 0x200, 0),
65 RATETAB_ENT(480, 0x400, 0),
66 RATETAB_ENT(540, 0x800, 0),
67};
68
69#define ath6kl_a_rates (ath6kl_rates + 4)
70#define ath6kl_a_rates_size 8
71#define ath6kl_g_rates (ath6kl_rates + 0)
72#define ath6kl_g_rates_size 12
73
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +053074#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
75 IEEE80211_HT_CAP_SGI_20 | \
76 IEEE80211_HT_CAP_SGI_40)
77
Kalle Valobdcd8172011-07-18 00:22:30 +030078static struct ieee80211_channel ath6kl_2ghz_channels[] = {
79 CHAN2G(1, 2412, 0),
80 CHAN2G(2, 2417, 0),
81 CHAN2G(3, 2422, 0),
82 CHAN2G(4, 2427, 0),
83 CHAN2G(5, 2432, 0),
84 CHAN2G(6, 2437, 0),
85 CHAN2G(7, 2442, 0),
86 CHAN2G(8, 2447, 0),
87 CHAN2G(9, 2452, 0),
88 CHAN2G(10, 2457, 0),
89 CHAN2G(11, 2462, 0),
90 CHAN2G(12, 2467, 0),
91 CHAN2G(13, 2472, 0),
92 CHAN2G(14, 2484, 0),
93};
94
95static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
96 CHAN5G(34, 0), CHAN5G(36, 0),
97 CHAN5G(38, 0), CHAN5G(40, 0),
98 CHAN5G(42, 0), CHAN5G(44, 0),
99 CHAN5G(46, 0), CHAN5G(48, 0),
100 CHAN5G(52, 0), CHAN5G(56, 0),
101 CHAN5G(60, 0), CHAN5G(64, 0),
102 CHAN5G(100, 0), CHAN5G(104, 0),
103 CHAN5G(108, 0), CHAN5G(112, 0),
104 CHAN5G(116, 0), CHAN5G(120, 0),
105 CHAN5G(124, 0), CHAN5G(128, 0),
106 CHAN5G(132, 0), CHAN5G(136, 0),
107 CHAN5G(140, 0), CHAN5G(149, 0),
108 CHAN5G(153, 0), CHAN5G(157, 0),
109 CHAN5G(161, 0), CHAN5G(165, 0),
110 CHAN5G(184, 0), CHAN5G(188, 0),
111 CHAN5G(192, 0), CHAN5G(196, 0),
112 CHAN5G(200, 0), CHAN5G(204, 0),
113 CHAN5G(208, 0), CHAN5G(212, 0),
114 CHAN5G(216, 0),
115};
116
117static struct ieee80211_supported_band ath6kl_band_2ghz = {
118 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
119 .channels = ath6kl_2ghz_channels,
120 .n_bitrates = ath6kl_g_rates_size,
121 .bitrates = ath6kl_g_rates,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530122 .ht_cap.cap = ath6kl_g_htcap,
123 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300124};
125
126static struct ieee80211_supported_band ath6kl_band_5ghz = {
127 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
128 .channels = ath6kl_5ghz_a_channels,
129 .n_bitrates = ath6kl_a_rates_size,
130 .bitrates = ath6kl_a_rates,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530131 .ht_cap.cap = ath6kl_g_htcap,
132 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300133};
134
Jouni Malinen837cb972011-10-11 17:31:57 +0300135#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
136
Kalle Valo10509f92011-12-13 14:52:07 +0200137/* returns true if scheduled scan was stopped */
138static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
139{
140 struct ath6kl *ar = vif->ar;
141
142 if (ar->state != ATH6KL_STATE_SCHED_SCAN)
143 return false;
144
145 del_timer_sync(&vif->sched_scan_timer);
146
147 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
148 ATH6KL_HOST_MODE_AWAKE);
149
150 ar->state = ATH6KL_STATE_ON;
151
152 return true;
153}
154
155static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
156{
157 struct ath6kl *ar = vif->ar;
158 bool stopped;
159
160 stopped = __ath6kl_cfg80211_sscan_stop(vif);
161
162 if (!stopped)
163 return;
164
165 cfg80211_sched_scan_stopped(ar->wiphy);
166}
167
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530168static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300169 enum nl80211_wpa_versions wpa_version)
170{
171 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
172
173 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530174 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300175 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530176 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300177 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530178 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300179 } else {
180 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
181 return -ENOTSUPP;
182 }
183
184 return 0;
185}
186
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530187static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300188 enum nl80211_auth_type auth_type)
189{
Kalle Valobdcd8172011-07-18 00:22:30 +0300190 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
191
192 switch (auth_type) {
193 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530194 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300195 break;
196 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530197 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300198 break;
199 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530200 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300201 break;
202
203 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530204 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300205 break;
206
207 default:
Masanari Iida3c325fb2012-01-31 23:32:55 +0900208 ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300209 return -ENOTSUPP;
210 }
211
212 return 0;
213}
214
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530215static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300216{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530217 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
218 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
219 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300220
221 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
222 __func__, cipher, ucast);
223
224 switch (cipher) {
225 case 0:
226 /* our own hack to use value 0 as no crypto used */
227 *ar_cipher = NONE_CRYPT;
228 *ar_cipher_len = 0;
229 break;
230 case WLAN_CIPHER_SUITE_WEP40:
231 *ar_cipher = WEP_CRYPT;
232 *ar_cipher_len = 5;
233 break;
234 case WLAN_CIPHER_SUITE_WEP104:
235 *ar_cipher = WEP_CRYPT;
236 *ar_cipher_len = 13;
237 break;
238 case WLAN_CIPHER_SUITE_TKIP:
239 *ar_cipher = TKIP_CRYPT;
240 *ar_cipher_len = 0;
241 break;
242 case WLAN_CIPHER_SUITE_CCMP:
243 *ar_cipher = AES_CRYPT;
244 *ar_cipher_len = 0;
245 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200246 case WLAN_CIPHER_SUITE_SMS4:
247 *ar_cipher = WAPI_CRYPT;
248 *ar_cipher_len = 0;
249 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300250 default:
251 ath6kl_err("cipher 0x%x not supported\n", cipher);
252 return -ENOTSUPP;
253 }
254
255 return 0;
256}
257
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530258static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300259{
260 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
261
262 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530263 if (vif->auth_mode == WPA_AUTH)
264 vif->auth_mode = WPA_PSK_AUTH;
265 else if (vif->auth_mode == WPA2_AUTH)
266 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300267 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530268 if (vif->auth_mode == WPA_AUTH)
269 vif->auth_mode = WPA_AUTH_CCKM;
270 else if (vif->auth_mode == WPA2_AUTH)
271 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300272 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530273 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300274 }
275}
276
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530277static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300278{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530279 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530280
Kalle Valobdcd8172011-07-18 00:22:30 +0300281 if (!test_bit(WMI_READY, &ar->flag)) {
282 ath6kl_err("wmi is not ready\n");
283 return false;
284 }
285
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530286 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300287 ath6kl_err("wlan disabled\n");
288 return false;
289 }
290
291 return true;
292}
293
Kevin Fang6981ffd2011-10-07 08:51:19 +0800294static bool ath6kl_is_wpa_ie(const u8 *pos)
295{
296 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
297 pos[2] == 0x00 && pos[3] == 0x50 &&
298 pos[4] == 0xf2 && pos[5] == 0x01;
299}
300
301static bool ath6kl_is_rsn_ie(const u8 *pos)
302{
303 return pos[0] == WLAN_EID_RSN;
304}
305
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700306static bool ath6kl_is_wps_ie(const u8 *pos)
307{
308 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
309 pos[1] >= 4 &&
310 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
311 pos[5] == 0x04);
312}
313
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530314static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
315 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800316{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530317 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800318 const u8 *pos;
319 u8 *buf = NULL;
320 size_t len = 0;
321 int ret;
322
323 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700324 * Clear previously set flag
325 */
326
327 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
328
329 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800330 * Filter out RSN/WPA IE(s)
331 */
332
333 if (ies && ies_len) {
334 buf = kmalloc(ies_len, GFP_KERNEL);
335 if (buf == NULL)
336 return -ENOMEM;
337 pos = ies;
338
339 while (pos + 1 < ies + ies_len) {
340 if (pos + 2 + pos[1] > ies + ies_len)
341 break;
342 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
343 memcpy(buf + len, pos, 2 + pos[1]);
344 len += 2 + pos[1];
345 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700346
347 if (ath6kl_is_wps_ie(pos))
348 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
349
Kevin Fang6981ffd2011-10-07 08:51:19 +0800350 pos += 2 + pos[1];
351 }
352 }
353
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530354 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
355 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800356 kfree(buf);
357 return ret;
358}
359
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530360static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
361{
362 switch (type) {
363 case NL80211_IFTYPE_STATION:
364 *nw_type = INFRA_NETWORK;
365 break;
366 case NL80211_IFTYPE_ADHOC:
367 *nw_type = ADHOC_NETWORK;
368 break;
369 case NL80211_IFTYPE_AP:
370 *nw_type = AP_NETWORK;
371 break;
372 case NL80211_IFTYPE_P2P_CLIENT:
373 *nw_type = INFRA_NETWORK;
374 break;
375 case NL80211_IFTYPE_P2P_GO:
376 *nw_type = AP_NETWORK;
377 break;
378 default:
379 ath6kl_err("invalid interface type %u\n", type);
380 return -ENOTSUPP;
381 }
382
383 return 0;
384}
385
386static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
387 u8 *if_idx, u8 *nw_type)
388{
389 int i;
390
391 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
392 return false;
393
394 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
Kalle Valo96f1fad2012-03-07 20:03:57 +0200395 ar->num_vif))
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530396 return false;
397
398 if (type == NL80211_IFTYPE_STATION ||
399 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200400 for (i = 0; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530401 if ((ar->avail_idx_map >> i) & BIT(0)) {
402 *if_idx = i;
403 return true;
404 }
405 }
406 }
407
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530408 if (type == NL80211_IFTYPE_P2P_CLIENT ||
409 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200410 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530411 if ((ar->avail_idx_map >> i) & BIT(0)) {
412 *if_idx = i;
413 return true;
414 }
415 }
416 }
417
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530418 return false;
419}
420
Kalle Valo8c9bb052012-03-07 20:04:00 +0200421static bool ath6kl_is_tx_pending(struct ath6kl *ar)
422{
423 return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
424}
425
426
Kalle Valobdcd8172011-07-18 00:22:30 +0300427static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
428 struct cfg80211_connect_params *sme)
429{
430 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530431 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300432 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800433 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Raja Manice0dc0c2012-02-20 19:08:08 +0530434 u16 interval;
Kalle Valobdcd8172011-07-18 00:22:30 +0300435
Kalle Valo10509f92011-12-13 14:52:07 +0200436 ath6kl_cfg80211_sscan_disable(vif);
437
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530438 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300439
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530440 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300441 return -EIO;
442
443 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
444 ath6kl_err("destroy in progress\n");
445 return -EBUSY;
446 }
447
448 if (test_bit(SKIP_SCAN, &ar->flag) &&
449 ((sme->channel && sme->channel->center_freq == 0) ||
450 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
451 ath6kl_err("SkipScan: channel or bssid invalid\n");
452 return -EINVAL;
453 }
454
455 if (down_interruptible(&ar->sem)) {
456 ath6kl_err("busy, couldn't get access\n");
457 return -ERESTARTSYS;
458 }
459
460 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
461 ath6kl_err("busy, destroy in progress\n");
462 up(&ar->sem);
463 return -EBUSY;
464 }
465
466 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
467 /*
468 * sleep until the command queue drains
469 */
470 wait_event_interruptible_timeout(ar->event_wq,
Kalle Valo8c9bb052012-03-07 20:04:00 +0200471 ath6kl_is_tx_pending(ar),
472 WMI_TIMEOUT);
Kalle Valobdcd8172011-07-18 00:22:30 +0300473 if (signal_pending(current)) {
474 ath6kl_err("cmd queue drain timeout\n");
475 up(&ar->sem);
476 return -EINTR;
477 }
478 }
479
Jouni Malinen6e786cb2011-12-15 14:16:00 +0200480 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
481 if (status) {
482 up(&ar->sem);
483 return status;
484 }
485
486 if (sme->ie == NULL || sme->ie_len == 0)
Raja Mani542c5192011-11-15 14:14:56 +0530487 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800488
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530489 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530490 vif->ssid_len == sme->ssid_len &&
491 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530492 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530493 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
494 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530495 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300496
497 up(&ar->sem);
498 if (status) {
499 ath6kl_err("wmi_reconnect_cmd failed\n");
500 return -EIO;
501 }
502 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530503 } else if (vif->ssid_len == sme->ssid_len &&
504 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530505 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300506 }
507
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530508 memset(vif->ssid, 0, sizeof(vif->ssid));
509 vif->ssid_len = sme->ssid_len;
510 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300511
512 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530513 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300514
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530515 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300516 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530517 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300518
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530519 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300520
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530521 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300522 if (status) {
523 up(&ar->sem);
524 return status;
525 }
526
527 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530528 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300529 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530530 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300531
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530532 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300533
534 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530535 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300536
537 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530538 (vif->auth_mode == NONE_AUTH) &&
539 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300540 struct ath6kl_key *key = NULL;
541
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530542 if (sme->key_idx > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300543 ath6kl_err("key index %d out of bounds\n",
544 sme->key_idx);
545 up(&ar->sem);
546 return -ENOENT;
547 }
548
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530549 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300550 key->key_len = sme->key_len;
551 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530552 key->cipher = vif->prwise_crypto;
553 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300554
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530555 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530556 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300557 GROUP_USAGE | TX_USAGE,
558 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200559 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300560 key->key, KEY_OP_INIT_VAL, NULL,
561 NO_SYNC_WMIFLAG);
562 }
563
564 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530565 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530566 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200567 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300568 ath6kl_err("couldn't set bss filtering\n");
569 up(&ar->sem);
570 return -EIO;
571 }
572 }
573
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530574 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300575
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800576 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
577 nw_subtype = SUBTYPE_P2PCLIENT;
578
Kalle Valobdcd8172011-07-18 00:22:30 +0300579 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
580 "%s: connect called with authmode %d dot11 auth %d"
581 " PW crypto %d PW crypto len %d GRP crypto %d"
582 " GRP crypto len %d channel hint %u\n",
583 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
585 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530586 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300587
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530588 vif->reconnect_flag = 0;
Raja Manice0dc0c2012-02-20 19:08:08 +0530589
590 if (vif->nw_type == INFRA_NETWORK) {
Kalle Valob5283872012-03-12 13:23:23 +0200591 interval = max_t(u16, vif->listen_intvl_t,
592 ATH6KL_MAX_WOW_LISTEN_INTL);
Raja Manice0dc0c2012-02-20 19:08:08 +0530593 status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
594 interval,
595 0);
596 if (status) {
597 ath6kl_err("couldn't set listen intervel\n");
598 up(&ar->sem);
599 return status;
600 }
601 }
602
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530603 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530604 vif->dot11_auth_mode, vif->auth_mode,
605 vif->prwise_crypto,
606 vif->prwise_crypto_len,
607 vif->grp_crypto, vif->grp_crypto_len,
608 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530609 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800610 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300611
Bala Shanmugamf5993592012-03-27 12:17:32 +0530612 /* disable background scan if period is 0 */
613 if (sme->bg_scan_period == 0)
614 sme->bg_scan_period = 0xffff;
615
616 /* configure default value if not specified */
617 if (sme->bg_scan_period == -1)
618 sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
619
620 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
621 sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
622
Kalle Valobdcd8172011-07-18 00:22:30 +0300623 up(&ar->sem);
624
625 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530626 memset(vif->ssid, 0, sizeof(vif->ssid));
627 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300628 ath6kl_err("invalid request\n");
629 return -ENOENT;
630 } else if (status) {
631 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
632 return -EIO;
633 }
634
635 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Kalle Valoddc3d772012-03-07 20:03:58 +0200636 ((vif->auth_mode == WPA_PSK_AUTH) ||
637 (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530638 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300639 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
640 }
641
642 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530643 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300644
645 return 0;
646}
647
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530648static struct cfg80211_bss *
649ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
650 enum network_type nw_type,
651 const u8 *bssid,
652 struct ieee80211_channel *chan,
653 const u8 *beacon_ie,
654 size_t beacon_ie_len)
Jouni Malinen01cac472011-09-19 19:14:59 +0300655{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530656 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300657 struct cfg80211_bss *bss;
Raja Mani4eab6f42011-11-09 17:02:23 +0530658 u16 cap_mask, cap_val;
Jouni Malinen01cac472011-09-19 19:14:59 +0300659 u8 *ie;
660
Raja Mani4eab6f42011-11-09 17:02:23 +0530661 if (nw_type & ADHOC_NETWORK) {
662 cap_mask = WLAN_CAPABILITY_IBSS;
663 cap_val = WLAN_CAPABILITY_IBSS;
664 } else {
665 cap_mask = WLAN_CAPABILITY_ESS;
666 cap_val = WLAN_CAPABILITY_ESS;
667 }
668
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530669 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530670 vif->ssid, vif->ssid_len,
671 cap_mask, cap_val);
Jouni Malinen01cac472011-09-19 19:14:59 +0300672 if (bss == NULL) {
673 /*
674 * Since cfg80211 may not yet know about the BSS,
675 * generate a partial entry until the first BSS info
676 * event becomes available.
677 *
678 * Prepend SSID element since it is not included in the Beacon
679 * IEs from the target.
680 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530681 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300682 if (ie == NULL)
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530683 return NULL;
Jouni Malinen01cac472011-09-19 19:14:59 +0300684 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530685 ie[1] = vif->ssid_len;
686 memcpy(ie + 2, vif->ssid, vif->ssid_len);
687 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530688 bss = cfg80211_inform_bss(ar->wiphy, chan,
Raja Mani4eab6f42011-11-09 17:02:23 +0530689 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530690 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300691 0, GFP_KERNEL);
692 if (bss)
Raja Mani4eab6f42011-11-09 17:02:23 +0530693 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
694 "cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300695 kfree(ie);
696 } else
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530697 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
Jouni Malinen01cac472011-09-19 19:14:59 +0300698
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530699 return bss;
Jouni Malinen01cac472011-09-19 19:14:59 +0300700}
701
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530702void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300703 u8 *bssid, u16 listen_intvl,
704 u16 beacon_intvl,
705 enum network_type nw_type,
706 u8 beacon_ie_len, u8 assoc_req_len,
707 u8 assoc_resp_len, u8 *assoc_info)
708{
Jouni Malinen01cac472011-09-19 19:14:59 +0300709 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530710 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530711 struct cfg80211_bss *bss;
Kalle Valobdcd8172011-07-18 00:22:30 +0300712
713 /* capinfo + listen interval */
714 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
715
716 /* capinfo + status code + associd */
717 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
718
719 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
720 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
721 assoc_resp_ie_offset;
722
723 assoc_req_len -= assoc_req_ie_offset;
724 assoc_resp_len -= assoc_resp_ie_offset;
725
Jouni Malinen32c10872011-09-19 19:15:07 +0300726 /*
727 * Store Beacon interval here; DTIM period will be available only once
728 * a Beacon frame from the AP is seen.
729 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530730 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530731 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300732
Kalle Valobdcd8172011-07-18 00:22:30 +0300733 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530734 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300735 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
736 "%s: ath6k not in ibss mode\n", __func__);
737 return;
738 }
739 }
740
741 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530742 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
743 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300744 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
745 "%s: ath6k not in station mode\n", __func__);
746 return;
747 }
748 }
749
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530750 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300751
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530752 bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
753 assoc_info, beacon_ie_len);
754 if (!bss) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530755 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300756 return;
757 }
758
Raja Mani4eab6f42011-11-09 17:02:23 +0530759 if (nw_type & ADHOC_NETWORK) {
760 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
761 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
762 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530763 cfg80211_put_bss(bss);
Jouni Malinen01cac472011-09-19 19:14:59 +0300764 return;
765 }
766
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530767 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530769 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530770 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300771 assoc_req_ie, assoc_req_len,
772 assoc_resp_ie, assoc_resp_len,
773 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530774 cfg80211_put_bss(bss);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530775 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300776 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530777 cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
778 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300779 }
780}
781
782static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
783 struct net_device *dev, u16 reason_code)
784{
Kalle Valod6d5c062011-11-25 13:17:37 +0200785 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530786 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300787
788 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
789 reason_code);
790
Kalle Valo10509f92011-12-13 14:52:07 +0200791 ath6kl_cfg80211_sscan_disable(vif);
792
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530793 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300794 return -EIO;
795
796 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
797 ath6kl_err("busy, destroy in progress\n");
798 return -EBUSY;
799 }
800
801 if (down_interruptible(&ar->sem)) {
802 ath6kl_err("busy, couldn't get access\n");
803 return -ERESTARTSYS;
804 }
805
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530806 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530807 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530808 memset(vif->ssid, 0, sizeof(vif->ssid));
809 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300810
811 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530812 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300813
814 up(&ar->sem);
815
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530816 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530817
Kalle Valobdcd8172011-07-18 00:22:30 +0300818 return 0;
819}
820
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530821void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300822 u8 *bssid, u8 assoc_resp_len,
823 u8 *assoc_info, u16 proto_reason)
824{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530825 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530826
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530827 if (vif->scan_req) {
828 cfg80211_scan_done(vif->scan_req, true);
829 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300830 }
831
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530832 if (vif->nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530833 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300834 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
835 "%s: ath6k not in ibss mode\n", __func__);
836 return;
837 }
838 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530839 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300840 return;
841 }
842
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530843 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530844 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
845 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300846 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
847 "%s: ath6k not in station mode\n", __func__);
848 return;
849 }
850 }
851
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530852 /*
853 * Send a disconnect command to target when a disconnect event is
854 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
855 * request from host) to make the firmware stop trying to connect even
856 * after giving disconnect event. There will be one more disconnect
857 * event for this disconnect command with reason code DISCONNECT_CMD
858 * which will be notified to cfg80211.
859 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300860
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530861 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530862 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300863 return;
864 }
865
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530866 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300867
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530868 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530869 cfg80211_connect_result(vif->ndev,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200870 bssid, NULL, 0,
871 NULL, 0,
872 WLAN_STATUS_UNSPECIFIED_FAILURE,
873 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530874 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530875 cfg80211_disconnected(vif->ndev, reason,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200876 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300877 }
878
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530879 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300880}
881
Kalle Valobdcd8172011-07-18 00:22:30 +0300882static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
883 struct cfg80211_scan_request *request)
884{
Kalle Valod6d5c062011-11-25 13:17:37 +0200885 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530886 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300887 s8 n_channels = 0;
888 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300889 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530890 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300891
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530892 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300893 return -EIO;
894
Kalle Valo10509f92011-12-13 14:52:07 +0200895 ath6kl_cfg80211_sscan_disable(vif);
896
Kalle Valobdcd8172011-07-18 00:22:30 +0300897 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530898 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300899 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530900 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530901 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300902 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
903 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300904 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300905 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300906 }
907 }
908
909 if (request->n_ssids && request->ssids[0].ssid_len) {
910 u8 i;
911
912 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
913 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
914
915 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530916 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
917 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300918 request->ssids[i].ssid_len,
919 request->ssids[i].ssid);
920 }
921
Aarthi Thiruvengadam080eec42012-02-28 09:17:04 -0800922 /* this also clears IE in fw if it's not set */
923 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
924 WMI_FRAME_PROBE_REQ,
925 request->ie, request->ie_len);
926 if (ret) {
927 ath6kl_err("failed to set Probe Request appie for "
928 "scan");
929 return ret;
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300930 }
931
Jouni Malinen11869be2011-09-02 20:07:06 +0300932 /*
933 * Scan only the requested channels if the request specifies a set of
934 * channels. If the list is longer than the target supports, do not
935 * configure the list and instead, scan all available channels.
936 */
937 if (request->n_channels > 0 &&
938 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300939 u8 i;
940
Jouni Malinen11869be2011-09-02 20:07:06 +0300941 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300942
943 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
944 if (channels == NULL) {
945 ath6kl_warn("failed to set scan channels, "
946 "scan all channels");
947 n_channels = 0;
948 }
949
950 for (i = 0; i < n_channels; i++)
951 channels[i] = request->channels[i]->center_freq;
952 }
953
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530954 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530955 force_fg_scan = 1;
956
Raja Mani5b35dff2012-03-28 18:50:35 +0530957 vif->scan_req = request;
958
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800959 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200960 ar->fw_capabilities)) {
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800961 /*
962 * If capable of doing P2P mgmt operations using
963 * station interface, send additional information like
964 * supported rates to advertise and xmit rates for
965 * probe requests
966 */
967 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
968 WMI_LONG_SCAN, force_fg_scan,
Vasanthakumar Thiagarajan13423c32012-02-21 15:30:42 +0530969 false, 0,
970 ATH6KL_FG_SCAN_INTERVAL,
971 n_channels, channels,
972 request->no_cck,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800973 request->rates);
974 } else {
975 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
976 WMI_LONG_SCAN, force_fg_scan,
Vasanthakumar Thiagarajan13423c32012-02-21 15:30:42 +0530977 false, 0,
978 ATH6KL_FG_SCAN_INTERVAL,
979 n_channels, channels);
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800980 }
Raja Mani5b35dff2012-03-28 18:50:35 +0530981 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300982 ath6kl_err("wmi_startscan_cmd failed\n");
Raja Mani5b35dff2012-03-28 18:50:35 +0530983 vif->scan_req = NULL;
984 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300985
Edward Lu1276c9e2011-08-30 21:58:00 +0300986 kfree(channels);
987
Kalle Valobdcd8172011-07-18 00:22:30 +0300988 return ret;
989}
990
Kalle Valo1c17d312011-11-01 08:43:56 +0200991void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +0300992{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530993 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300994 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300995
Kalle Valo1c17d312011-11-01 08:43:56 +0200996 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
997 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +0300998
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530999 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001000 return;
Kalle Valobdcd8172011-07-18 00:22:30 +03001001
Kalle Valo1c17d312011-11-01 08:43:56 +02001002 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001003 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001004
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301005 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
1006 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301007 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
1008 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001009 0, NULL);
1010 }
1011 }
1012
1013out:
Kalle Valocb938212011-10-27 18:47:46 +03001014 cfg80211_scan_done(vif->scan_req, aborted);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301015 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001016}
1017
1018static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1019 u8 key_index, bool pairwise,
1020 const u8 *mac_addr,
1021 struct key_params *params)
1022{
Kalle Valod6d5c062011-11-25 13:17:37 +02001023 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301024 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001025 struct ath6kl_key *key = NULL;
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301026 int seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +03001027 u8 key_usage;
1028 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001029
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301030 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001031 return -EIO;
1032
Jouni Malinen837cb972011-10-11 17:31:57 +03001033 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
1034 if (params->key_len != WMI_KRK_LEN)
1035 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301036 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
1037 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +03001038 }
1039
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301040 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001041 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1042 "%s: key index %d out of bounds\n", __func__,
1043 key_index);
1044 return -ENOENT;
1045 }
1046
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301047 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001048 memset(key, 0, sizeof(struct ath6kl_key));
1049
1050 if (pairwise)
1051 key_usage = PAIRWISE_USAGE;
1052 else
1053 key_usage = GROUP_USAGE;
1054
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301055 seq_len = params->seq_len;
1056 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1057 seq_len > ATH6KL_KEY_SEQ_LEN) {
1058 /* Only first half of the WPI PN is configured */
1059 seq_len = ATH6KL_KEY_SEQ_LEN;
Kalle Valobdcd8172011-07-18 00:22:30 +03001060 }
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301061 if (params->key_len > WLAN_MAX_KEY_LEN ||
1062 seq_len > sizeof(key->seq))
1063 return -EINVAL;
1064
1065 key->key_len = params->key_len;
1066 memcpy(key->key, params->key, key->key_len);
1067 key->seq_len = seq_len;
1068 memcpy(key->seq, params->seq, key->seq_len);
1069 key->cipher = params->cipher;
Kalle Valobdcd8172011-07-18 00:22:30 +03001070
1071 switch (key->cipher) {
1072 case WLAN_CIPHER_SUITE_WEP40:
1073 case WLAN_CIPHER_SUITE_WEP104:
1074 key_type = WEP_CRYPT;
1075 break;
1076
1077 case WLAN_CIPHER_SUITE_TKIP:
1078 key_type = TKIP_CRYPT;
1079 break;
1080
1081 case WLAN_CIPHER_SUITE_CCMP:
1082 key_type = AES_CRYPT;
1083 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001084 case WLAN_CIPHER_SUITE_SMS4:
1085 key_type = WAPI_CRYPT;
1086 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001087
1088 default:
1089 return -ENOTSUPP;
1090 }
1091
Kalle Valoddc3d772012-03-07 20:03:58 +02001092 if (((vif->auth_mode == WPA_PSK_AUTH) ||
1093 (vif->auth_mode == WPA2_PSK_AUTH)) &&
1094 (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301095 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001096
1097 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1098 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1099 __func__, key_index, key->key_len, key_type,
1100 key_usage, key->seq_len);
1101
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301102 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001103 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
Vasanthakumar Thiagarajancc4d6232012-02-14 20:33:00 +05301104 key_type == WAPI_CRYPT)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001105 ar->ap_mode_bkey.valid = true;
1106 ar->ap_mode_bkey.key_index = key_index;
1107 ar->ap_mode_bkey.key_type = key_type;
1108 ar->ap_mode_bkey.key_len = key->key_len;
1109 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301110 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001111 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
1112 "key configuration until AP mode has been "
1113 "started\n");
1114 /*
1115 * The key will be set in ath6kl_connect_ap_mode() once
1116 * the connected event is received from the target.
1117 */
1118 return 0;
1119 }
1120 }
1121
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301122 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301123 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001124 /*
1125 * Store the key locally so that it can be re-configured after
1126 * the AP mode has properly started
1127 * (ath6kl_install_statioc_wep_keys).
1128 */
1129 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
1130 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301131 vif->wep_key_list[key_index].key_len = key->key_len;
1132 memcpy(vif->wep_key_list[key_index].key, key->key,
1133 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001134 return 0;
1135 }
1136
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301137 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001138 key_type, key_usage, key->key_len,
1139 key->seq, key->seq_len, key->key,
1140 KEY_OP_INIT_VAL,
1141 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001142}
1143
1144static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1145 u8 key_index, bool pairwise,
1146 const u8 *mac_addr)
1147{
Kalle Valod6d5c062011-11-25 13:17:37 +02001148 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301149 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001150
1151 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1152
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301153 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001154 return -EIO;
1155
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301156 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001157 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1158 "%s: key index %d out of bounds\n", __func__,
1159 key_index);
1160 return -ENOENT;
1161 }
1162
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301163 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001164 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1165 "%s: index %d is empty\n", __func__, key_index);
1166 return 0;
1167 }
1168
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301169 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001170
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301171 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001172}
1173
1174static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1175 u8 key_index, bool pairwise,
1176 const u8 *mac_addr, void *cookie,
1177 void (*callback) (void *cookie,
1178 struct key_params *))
1179{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301180 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001181 struct ath6kl_key *key = NULL;
1182 struct key_params params;
1183
1184 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1185
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301186 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001187 return -EIO;
1188
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301189 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001190 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1191 "%s: key index %d out of bounds\n", __func__,
1192 key_index);
1193 return -ENOENT;
1194 }
1195
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301196 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001197 memset(&params, 0, sizeof(params));
1198 params.cipher = key->cipher;
1199 params.key_len = key->key_len;
1200 params.seq_len = key->seq_len;
1201 params.seq = key->seq;
1202 params.key = key->key;
1203
1204 callback(cookie, &params);
1205
1206 return key->key_len ? 0 : -ENOENT;
1207}
1208
1209static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1210 struct net_device *ndev,
1211 u8 key_index, bool unicast,
1212 bool multicast)
1213{
Kalle Valod6d5c062011-11-25 13:17:37 +02001214 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301215 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001216 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001217 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001218 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001219
1220 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1221
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301222 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001223 return -EIO;
1224
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301225 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001226 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1227 "%s: key index %d out of bounds\n",
1228 __func__, key_index);
1229 return -ENOENT;
1230 }
1231
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301232 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001233 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1234 __func__, key_index);
1235 return -EINVAL;
1236 }
1237
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301238 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301239 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001240 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301241 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001242 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001243 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301244 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001245 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301246 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001247
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301248 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001249 return 0; /* Delay until AP mode has been started */
1250
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001251 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1252 vif->def_txkey_index,
1253 key_type, key_usage,
1254 key->key_len, key->seq, key->seq_len,
1255 key->key,
1256 KEY_OP_INIT_VAL, NULL,
1257 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001258}
1259
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301260void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001261 bool ismcast)
1262{
1263 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1264 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1265
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301266 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001267 (ismcast ? NL80211_KEYTYPE_GROUP :
1268 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1269 GFP_KERNEL);
1270}
1271
1272static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1273{
1274 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301275 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001276 int ret;
1277
1278 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1279 changed);
1280
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301281 vif = ath6kl_vif_first(ar);
1282 if (!vif)
1283 return -EIO;
1284
1285 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001286 return -EIO;
1287
1288 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1289 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1290 if (ret != 0) {
1291 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1292 return -EIO;
1293 }
1294 }
1295
1296 return 0;
1297}
1298
1299/*
1300 * The type nl80211_tx_power_setting replaces the following
1301 * data type from 2.6.36 onwards
1302*/
1303static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1304 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001305 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001306{
1307 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301308 struct ath6kl_vif *vif;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001309 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001310
1311 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1312 type, dbm);
1313
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301314 vif = ath6kl_vif_first(ar);
1315 if (!vif)
1316 return -EIO;
1317
1318 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001319 return -EIO;
1320
1321 switch (type) {
1322 case NL80211_TX_POWER_AUTOMATIC:
1323 return 0;
1324 case NL80211_TX_POWER_LIMITED:
Kalle Valod0d670a2012-03-07 20:03:58 +02001325 ar->tx_pwr = dbm;
Kalle Valobdcd8172011-07-18 00:22:30 +03001326 break;
1327 default:
1328 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1329 __func__, type);
1330 return -EOPNOTSUPP;
1331 }
1332
Kalle Valod0d670a2012-03-07 20:03:58 +02001333 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001334
1335 return 0;
1336}
1337
1338static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1339{
1340 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301341 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001342
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301343 vif = ath6kl_vif_first(ar);
1344 if (!vif)
1345 return -EIO;
1346
1347 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001348 return -EIO;
1349
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301350 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001351 ar->tx_pwr = 0;
1352
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301353 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001354 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1355 return -EIO;
1356 }
1357
1358 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1359 5 * HZ);
1360
1361 if (signal_pending(current)) {
1362 ath6kl_err("target did not respond\n");
1363 return -EINTR;
1364 }
1365 }
1366
1367 *dbm = ar->tx_pwr;
1368 return 0;
1369}
1370
1371static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1372 struct net_device *dev,
1373 bool pmgmt, int timeout)
1374{
1375 struct ath6kl *ar = ath6kl_priv(dev);
1376 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301377 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001378
1379 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1380 __func__, pmgmt, timeout);
1381
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301382 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001383 return -EIO;
1384
1385 if (pmgmt) {
1386 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1387 mode.pwr_mode = REC_POWER;
1388 } else {
1389 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1390 mode.pwr_mode = MAX_PERF_POWER;
1391 }
1392
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301393 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +02001394 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001395 ath6kl_err("wmi_powermode_cmd failed\n");
1396 return -EIO;
1397 }
1398
1399 return 0;
1400}
1401
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301402static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1403 char *name,
1404 enum nl80211_iftype type,
1405 u32 *flags,
1406 struct vif_params *params)
1407{
1408 struct ath6kl *ar = wiphy_priv(wiphy);
1409 struct net_device *ndev;
1410 u8 if_idx, nw_type;
1411
Kalle Valo71f96ee2011-11-14 19:31:30 +02001412 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301413 ath6kl_err("Reached maximum number of supported vif\n");
1414 return ERR_PTR(-EINVAL);
1415 }
1416
1417 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1418 ath6kl_err("Not a supported interface type\n");
1419 return ERR_PTR(-EINVAL);
1420 }
1421
1422 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1423 if (!ndev)
1424 return ERR_PTR(-ENOMEM);
1425
1426 ar->num_vif++;
1427
1428 return ndev;
1429}
1430
1431static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1432 struct net_device *ndev)
1433{
1434 struct ath6kl *ar = wiphy_priv(wiphy);
1435 struct ath6kl_vif *vif = netdev_priv(ndev);
1436
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301437 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301438 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301439 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301440
1441 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1442
Kalle Valoc25889e2012-01-17 20:08:27 +02001443 ath6kl_cfg80211_vif_cleanup(vif);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301444
1445 return 0;
1446}
1447
Kalle Valobdcd8172011-07-18 00:22:30 +03001448static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1449 struct net_device *ndev,
1450 enum nl80211_iftype type, u32 *flags,
1451 struct vif_params *params)
1452{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301453 struct ath6kl_vif *vif = netdev_priv(ndev);
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301454 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +03001455
1456 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1457
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301458 /*
1459 * Don't bring up p2p on an interface which is not initialized
1460 * for p2p operation where fw does not have capability to switch
1461 * dynamically between non-p2p and p2p type interface.
1462 */
1463 if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
1464 vif->ar->fw_capabilities) &&
1465 (type == NL80211_IFTYPE_P2P_CLIENT ||
1466 type == NL80211_IFTYPE_P2P_GO)) {
1467 if (vif->ar->vif_max == 1) {
1468 if (vif->fw_vif_idx != 0)
1469 return -EINVAL;
1470 else
1471 goto set_iface_type;
1472 }
1473
1474 for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
1475 if (i == vif->fw_vif_idx)
1476 break;
1477 }
1478
1479 if (i == vif->ar->vif_max) {
1480 ath6kl_err("Invalid interface to bring up P2P\n");
1481 return -EINVAL;
1482 }
1483 }
1484
1485set_iface_type:
Kalle Valobdcd8172011-07-18 00:22:30 +03001486 switch (type) {
1487 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301488 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001489 break;
1490 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301491 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001492 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001493 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301494 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001495 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001496 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301497 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001498 break;
1499 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301500 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001501 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001502 default:
1503 ath6kl_err("invalid interface type %u\n", type);
1504 return -EOPNOTSUPP;
1505 }
1506
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301507 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001508
1509 return 0;
1510}
1511
1512static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1513 struct net_device *dev,
1514 struct cfg80211_ibss_params *ibss_param)
1515{
1516 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301517 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518 int status;
1519
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301520 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001521 return -EIO;
1522
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301523 vif->ssid_len = ibss_param->ssid_len;
1524 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001525
1526 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301527 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001528
1529 if (ibss_param->channel_fixed) {
1530 /*
1531 * TODO: channel_fixed: The channel should be fixed, do not
1532 * search for IBSSs to join on other channels. Target
1533 * firmware does not support this feature, needs to be
1534 * updated.
1535 */
1536 return -EOPNOTSUPP;
1537 }
1538
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301539 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001540 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301541 memcpy(vif->req_bssid, ibss_param->bssid,
1542 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001543
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301544 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001545
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301546 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001547 if (status)
1548 return status;
1549
1550 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301551 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1552 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001553 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301554 ath6kl_set_cipher(vif, 0, true);
1555 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001556 }
1557
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301558 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001559
1560 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1561 "%s: connect called with authmode %d dot11 auth %d"
1562 " PW crypto %d PW crypto len %d GRP crypto %d"
1563 " GRP crypto len %d channel hint %u\n",
1564 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301565 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1566 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301567 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001568
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301569 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301570 vif->dot11_auth_mode, vif->auth_mode,
1571 vif->prwise_crypto,
1572 vif->prwise_crypto_len,
1573 vif->grp_crypto, vif->grp_crypto_len,
1574 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301575 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001576 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301577 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001578
1579 return 0;
1580}
1581
1582static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1583 struct net_device *dev)
1584{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301585 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001586
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301587 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001588 return -EIO;
1589
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301590 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301591 memset(vif->ssid, 0, sizeof(vif->ssid));
1592 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001593
1594 return 0;
1595}
1596
1597static const u32 cipher_suites[] = {
1598 WLAN_CIPHER_SUITE_WEP40,
1599 WLAN_CIPHER_SUITE_WEP104,
1600 WLAN_CIPHER_SUITE_TKIP,
1601 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001602 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001603 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001604};
1605
1606static bool is_rate_legacy(s32 rate)
1607{
1608 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1609 6000, 9000, 12000, 18000, 24000,
1610 36000, 48000, 54000
1611 };
1612 u8 i;
1613
1614 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1615 if (rate == legacy[i])
1616 return true;
1617
1618 return false;
1619}
1620
1621static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1622{
1623 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1624 52000, 58500, 65000, 72200
1625 };
1626 u8 i;
1627
1628 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1629 if (rate == ht20[i]) {
1630 if (i == ARRAY_SIZE(ht20) - 1)
1631 /* last rate uses sgi */
1632 *sgi = true;
1633 else
1634 *sgi = false;
1635
1636 *mcs = i;
1637 return true;
1638 }
1639 }
1640 return false;
1641}
1642
1643static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1644{
1645 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1646 81000, 108000, 121500, 135000,
1647 150000
1648 };
1649 u8 i;
1650
1651 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1652 if (rate == ht40[i]) {
1653 if (i == ARRAY_SIZE(ht40) - 1)
1654 /* last rate uses sgi */
1655 *sgi = true;
1656 else
1657 *sgi = false;
1658
1659 *mcs = i;
1660 return true;
1661 }
1662 }
1663
1664 return false;
1665}
1666
1667static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1668 u8 *mac, struct station_info *sinfo)
1669{
1670 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301671 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001672 long left;
1673 bool sgi;
1674 s32 rate;
1675 int ret;
1676 u8 mcs;
1677
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301678 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001679 return -ENOENT;
1680
1681 if (down_interruptible(&ar->sem))
1682 return -EBUSY;
1683
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301684 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001685
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301686 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001687
1688 if (ret != 0) {
1689 up(&ar->sem);
1690 return -EIO;
1691 }
1692
1693 left = wait_event_interruptible_timeout(ar->event_wq,
1694 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301695 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001696 WMI_TIMEOUT);
1697
1698 up(&ar->sem);
1699
1700 if (left == 0)
1701 return -ETIMEDOUT;
1702 else if (left < 0)
1703 return left;
1704
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301705 if (vif->target_stats.rx_byte) {
1706 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001707 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301708 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001709 sinfo->filled |= STATION_INFO_RX_PACKETS;
1710 }
1711
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301712 if (vif->target_stats.tx_byte) {
1713 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001714 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301715 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001716 sinfo->filled |= STATION_INFO_TX_PACKETS;
1717 }
1718
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301719 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001720 sinfo->filled |= STATION_INFO_SIGNAL;
1721
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301722 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001723
1724 if (is_rate_legacy(rate)) {
1725 sinfo->txrate.legacy = rate / 100;
1726 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1727 if (sgi) {
1728 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1729 sinfo->txrate.mcs = mcs - 1;
1730 } else {
1731 sinfo->txrate.mcs = mcs;
1732 }
1733
1734 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1735 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1736 if (sgi) {
1737 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1738 sinfo->txrate.mcs = mcs - 1;
1739 } else {
1740 sinfo->txrate.mcs = mcs;
1741 }
1742
1743 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1744 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1745 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001746 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1747 "invalid rate from stats: %d\n", rate);
1748 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001749 return 0;
1750 }
1751
1752 sinfo->filled |= STATION_INFO_TX_BITRATE;
1753
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301754 if (test_bit(CONNECTED, &vif->flags) &&
1755 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301756 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001757 sinfo->filled |= STATION_INFO_BSS_PARAM;
1758 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301759 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1760 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001761 }
1762
Kalle Valobdcd8172011-07-18 00:22:30 +03001763 return 0;
1764}
1765
1766static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1767 struct cfg80211_pmksa *pmksa)
1768{
1769 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301770 struct ath6kl_vif *vif = netdev_priv(netdev);
1771
1772 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001773 pmksa->pmkid, true);
1774}
1775
1776static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1777 struct cfg80211_pmksa *pmksa)
1778{
1779 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301780 struct ath6kl_vif *vif = netdev_priv(netdev);
1781
1782 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001783 pmksa->pmkid, false);
1784}
1785
1786static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1787{
1788 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301789 struct ath6kl_vif *vif = netdev_priv(netdev);
1790
1791 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301792 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1793 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001794 return 0;
1795}
1796
Raja Manid91e8ee2012-01-30 17:13:10 +05301797static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
1798 struct cfg80211_wowlan *wow, u32 *filter)
Raja Mani6cb3c712011-11-07 22:52:45 +02001799{
Raja Manid91e8ee2012-01-30 17:13:10 +05301800 int ret, pos;
1801 u8 mask[WOW_MASK_SIZE];
Raja Mani6cb3c712011-11-07 22:52:45 +02001802 u16 i;
Raja Mani6cb3c712011-11-07 22:52:45 +02001803
Raja Manid91e8ee2012-01-30 17:13:10 +05301804 /* Configure the patterns that we received from the user. */
Raja Mani6cb3c712011-11-07 22:52:45 +02001805 for (i = 0; i < wow->n_patterns; i++) {
1806
1807 /*
1808 * Convert given nl80211 specific mask value to equivalent
1809 * driver specific mask value and send it to the chip along
1810 * with patterns. For example, If the mask value defined in
1811 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1812 * then equivalent driver specific mask value is
1813 * "0xFF 0x00 0xFF 0x00".
1814 */
1815 memset(&mask, 0, sizeof(mask));
1816 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1817 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1818 mask[pos] = 0xFF;
1819 }
1820 /*
1821 * Note: Pattern's offset is not passed as part of wowlan
1822 * parameter from CFG layer. So it's always passed as ZERO
1823 * to the firmware. It means, given WOW patterns are always
1824 * matched from the first byte of received pkt in the firmware.
1825 */
1826 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
Raja Manid91e8ee2012-01-30 17:13:10 +05301827 vif->fw_vif_idx, WOW_LIST_ID,
1828 wow->patterns[i].pattern_len,
1829 0 /* pattern offset */,
1830 wow->patterns[i].pattern, mask);
Raja Mani6cb3c712011-11-07 22:52:45 +02001831 if (ret)
1832 return ret;
1833 }
1834
Raja Manid91e8ee2012-01-30 17:13:10 +05301835 if (wow->disconnect)
1836 *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1837
1838 if (wow->magic_pkt)
1839 *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1840
1841 if (wow->gtk_rekey_failure)
1842 *filter |= WOW_FILTER_OPTION_GTK_ERROR;
1843
1844 if (wow->eap_identity_req)
1845 *filter |= WOW_FILTER_OPTION_EAP_REQ;
1846
1847 if (wow->four_way_handshake)
1848 *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1849
1850 return 0;
1851}
1852
1853static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif)
1854{
1855 static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00,
1856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1858 0x00, 0x08 };
1859 static const u8 unicst_mask[] = { 0x01, 0x00, 0x00,
1860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1862 0x00, 0x7f };
1863 u8 unicst_offset = 0;
1864 static const u8 arp_pattern[] = { 0x08, 0x06 };
1865 static const u8 arp_mask[] = { 0xff, 0xff };
1866 u8 arp_offset = 20;
1867 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
1868 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
1869 u8 discvr_offset = 38;
1870 static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff,
1871 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
1873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1874 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1875 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
1876 static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff,
1877 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
1879 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1880 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1881 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ };
1882 u8 dhcp_offset = 0;
1883 int ret;
1884
1885 /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
1886 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1887 vif->fw_vif_idx, WOW_LIST_ID,
1888 sizeof(unicst_pattern), unicst_offset,
1889 unicst_pattern, unicst_mask);
1890 if (ret) {
1891 ath6kl_err("failed to add WOW unicast IP pattern\n");
1892 return ret;
1893 }
1894
1895 /* Setup all ARP pkt pattern */
1896 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1897 vif->fw_vif_idx, WOW_LIST_ID,
1898 sizeof(arp_pattern), arp_offset,
1899 arp_pattern, arp_mask);
1900 if (ret) {
1901 ath6kl_err("failed to add WOW ARP pattern\n");
1902 return ret;
1903 }
1904
1905 /*
1906 * Setup multicast pattern for mDNS 224.0.0.251,
1907 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
1908 */
1909 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1910 vif->fw_vif_idx, WOW_LIST_ID,
1911 sizeof(discvr_pattern), discvr_offset,
1912 discvr_pattern, discvr_mask);
1913 if (ret) {
1914 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
1915 return ret;
1916 }
1917
1918 /* Setup all DHCP broadcast pkt pattern */
1919 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1920 vif->fw_vif_idx, WOW_LIST_ID,
1921 sizeof(dhcp_pattern), dhcp_offset,
1922 dhcp_pattern, dhcp_mask);
1923 if (ret) {
1924 ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
1925 return ret;
1926 }
1927
1928 return 0;
1929}
1930
1931static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
1932{
1933 struct net_device *ndev = vif->ndev;
1934 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
1935 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
1936 u8 discvr_offset = 38;
1937 u8 mac_mask[ETH_ALEN];
1938 int ret;
1939
1940 /* Setup unicast pkt pattern */
1941 memset(mac_mask, 0xff, ETH_ALEN);
1942 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1943 vif->fw_vif_idx, WOW_LIST_ID,
1944 ETH_ALEN, 0, ndev->dev_addr,
1945 mac_mask);
1946 if (ret) {
1947 ath6kl_err("failed to add WOW unicast pattern\n");
1948 return ret;
1949 }
1950
1951 /*
1952 * Setup multicast pattern for mDNS 224.0.0.251,
1953 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
1954 */
1955 if ((ndev->flags & IFF_ALLMULTI) ||
1956 (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
1957 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1958 vif->fw_vif_idx, WOW_LIST_ID,
1959 sizeof(discvr_pattern), discvr_offset,
1960 discvr_pattern, discvr_mask);
1961 if (ret) {
1962 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
1963 "pattern\n");
1964 return ret;
1965 }
1966 }
1967
1968 return 0;
1969}
1970
Raja Mani055bde42012-03-21 15:03:37 +05301971static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
1972{
1973 return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
1974}
1975
1976static bool is_ctrl_ep_empty(struct ath6kl *ar)
1977{
1978 return !ar->tx_pending[ar->ctrl_ep];
1979}
1980
1981static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
1982{
1983 int ret, left;
1984
1985 clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
1986
1987 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1988 ATH6KL_HOST_MODE_ASLEEP);
1989 if (ret)
1990 return ret;
1991
1992 left = wait_event_interruptible_timeout(ar->event_wq,
1993 is_hsleep_mode_procsed(vif),
1994 WMI_TIMEOUT);
1995 if (left == 0) {
1996 ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
1997 ret = -ETIMEDOUT;
1998 } else if (left < 0) {
1999 ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
2000 left);
2001 ret = left;
2002 }
2003
2004 if (ar->tx_pending[ar->ctrl_ep]) {
2005 left = wait_event_interruptible_timeout(ar->event_wq,
2006 is_ctrl_ep_empty(ar),
2007 WMI_TIMEOUT);
2008 if (left == 0) {
2009 ath6kl_warn("clear wmi ctrl data timeout\n");
2010 ret = -ETIMEDOUT;
2011 } else if (left < 0) {
2012 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
2013 ret = left;
2014 }
2015 }
2016
2017 return ret;
2018}
2019
Raja Manid91e8ee2012-01-30 17:13:10 +05302020static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
2021{
2022 struct in_device *in_dev;
2023 struct in_ifaddr *ifa;
2024 struct ath6kl_vif *vif;
Raja Mani055bde42012-03-21 15:03:37 +05302025 int ret;
Raja Manid91e8ee2012-01-30 17:13:10 +05302026 u32 filter = 0;
Raja Manice0dc0c2012-02-20 19:08:08 +05302027 u16 i, bmiss_time;
Raja Manid91e8ee2012-01-30 17:13:10 +05302028 u8 index = 0;
2029 __be32 ips[MAX_IP_ADDRS];
2030
2031 vif = ath6kl_vif_first(ar);
2032 if (!vif)
2033 return -EIO;
2034
2035 if (!ath6kl_cfg80211_ready(vif))
2036 return -EIO;
2037
2038 if (!test_bit(CONNECTED, &vif->flags))
Raja Mani3c411a42012-01-30 17:13:12 +05302039 return -ENOTCONN;
Raja Manid91e8ee2012-01-30 17:13:10 +05302040
2041 if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
2042 return -EINVAL;
2043
2044 /* Clear existing WOW patterns */
2045 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
2046 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
2047 WOW_LIST_ID, i);
2048
2049 /*
2050 * Skip the default WOW pattern configuration
2051 * if the driver receives any WOW patterns from
2052 * the user.
2053 */
2054 if (wow)
2055 ret = ath6kl_wow_usr(ar, vif, wow, &filter);
2056 else if (vif->nw_type == AP_NETWORK)
2057 ret = ath6kl_wow_ap(ar, vif);
2058 else
2059 ret = ath6kl_wow_sta(ar, vif);
2060
2061 if (ret)
2062 return ret;
2063
Raja Mani390a8c82012-03-07 11:35:04 +05302064 netif_stop_queue(vif->ndev);
2065
Raja Manice0dc0c2012-02-20 19:08:08 +05302066 if (vif->nw_type != AP_NETWORK) {
2067 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2068 ATH6KL_MAX_WOW_LISTEN_INTL,
2069 0);
2070 if (ret)
2071 return ret;
2072
2073 /* Set listen interval x 15 times as bmiss time */
2074 bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
2075 if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
2076 bmiss_time = ATH6KL_MAX_BMISS_TIME;
2077
2078 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2079 bmiss_time, 0);
2080 if (ret)
2081 return ret;
2082
2083 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2084 0xFFFF, 0, 0xFFFF, 0, 0, 0,
2085 0, 0, 0, 0);
2086 if (ret)
2087 return ret;
2088 }
2089
Raja Mani390a8c82012-03-07 11:35:04 +05302090 ar->state = ATH6KL_STATE_SUSPENDING;
2091
Raja Manic08631c2011-12-16 14:24:24 +05302092 /* Setup own IP addr for ARP agent. */
2093 in_dev = __in_dev_get_rtnl(vif->ndev);
2094 if (!in_dev)
2095 goto skip_arp;
2096
2097 ifa = in_dev->ifa_list;
2098 memset(&ips, 0, sizeof(ips));
2099
2100 /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
2101 while (index < MAX_IP_ADDRS && ifa) {
2102 ips[index] = ifa->ifa_local;
2103 ifa = ifa->ifa_next;
2104 index++;
2105 }
2106
2107 if (ifa) {
2108 ath6kl_err("total IP addr count is exceeding fw limit\n");
2109 return -EINVAL;
2110 }
2111
2112 ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
2113 if (ret) {
2114 ath6kl_err("fail to setup ip for arp agent\n");
2115 return ret;
2116 }
2117
2118skip_arp:
Raja Mani6cb3c712011-11-07 22:52:45 +02002119 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2120 ATH6KL_WOW_MODE_ENABLE,
2121 filter,
2122 WOW_HOST_REQ_DELAY);
2123 if (ret)
2124 return ret;
2125
Raja Mani055bde42012-03-21 15:03:37 +05302126 ret = ath6kl_cfg80211_host_sleep(ar, vif);
Raja Mani6cb3c712011-11-07 22:52:45 +02002127 if (ret)
2128 return ret;
2129
Raja Mani055bde42012-03-21 15:03:37 +05302130 return 0;
Raja Mani6cb3c712011-11-07 22:52:45 +02002131}
2132
2133static int ath6kl_wow_resume(struct ath6kl *ar)
2134{
2135 struct ath6kl_vif *vif;
2136 int ret;
2137
2138 vif = ath6kl_vif_first(ar);
2139 if (!vif)
2140 return -EIO;
2141
Raja Mani390a8c82012-03-07 11:35:04 +05302142 ar->state = ATH6KL_STATE_RESUMING;
2143
Raja Mani6cb3c712011-11-07 22:52:45 +02002144 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2145 ATH6KL_HOST_MODE_AWAKE);
Raja Mani390a8c82012-03-07 11:35:04 +05302146 if (ret) {
2147 ath6kl_warn("Failed to configure host sleep mode for "
2148 "wow resume: %d\n", ret);
2149 ar->state = ATH6KL_STATE_WOW;
2150 return ret;
2151 }
2152
Raja Manice0dc0c2012-02-20 19:08:08 +05302153 if (vif->nw_type != AP_NETWORK) {
2154 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2155 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2156 if (ret)
2157 return ret;
2158
2159 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2160 vif->listen_intvl_t, 0);
2161 if (ret)
2162 return ret;
2163
2164 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2165 vif->bmiss_time_t, 0);
2166 if (ret)
2167 return ret;
2168 }
2169
Raja Mani390a8c82012-03-07 11:35:04 +05302170 ar->state = ATH6KL_STATE_ON;
2171
2172 netif_wake_queue(vif->ndev);
2173
2174 return 0;
Raja Mani6cb3c712011-11-07 22:52:45 +02002175}
2176
Raja Mani40abc2d2012-03-21 15:03:38 +05302177static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
2178{
2179 struct ath6kl_vif *vif;
2180 int ret;
2181
2182 vif = ath6kl_vif_first(ar);
2183 if (!vif)
2184 return -EIO;
2185
2186 if (!ath6kl_cfg80211_ready(vif))
2187 return -EIO;
2188
2189 ath6kl_cfg80211_stop_all(ar);
2190
2191 /* Save the current power mode before enabling power save */
2192 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2193
2194 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
2195 if (ret)
2196 return ret;
2197
2198 /* Disable WOW mode */
2199 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2200 ATH6KL_WOW_MODE_DISABLE,
2201 0, 0);
2202 if (ret)
2203 return ret;
2204
2205 /* Flush all non control pkts in TX path */
2206 ath6kl_tx_data_cleanup(ar);
2207
2208 ret = ath6kl_cfg80211_host_sleep(ar, vif);
2209 if (ret)
2210 return ret;
2211
2212 return 0;
2213}
2214
2215static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
2216{
2217 struct ath6kl_vif *vif;
2218 int ret;
2219
2220 vif = ath6kl_vif_first(ar);
2221
2222 if (!vif)
2223 return -EIO;
2224
2225 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
2226 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
2227 ar->wmi->saved_pwr_mode);
2228 if (ret)
2229 return ret;
2230 }
2231
2232 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2233 ATH6KL_HOST_MODE_AWAKE);
2234 if (ret)
2235 return ret;
2236
2237 ar->state = ATH6KL_STATE_ON;
2238
2239 /* Reset scan parameter to default values */
2240 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2241 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2242 if (ret)
2243 return ret;
2244
2245 return 0;
2246}
2247
Kalle Valo52d81a62011-11-01 08:44:21 +02002248int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02002249 enum ath6kl_cfg_suspend_mode mode,
2250 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02002251{
Vivek Natarajan3d794992012-03-28 19:21:26 +05302252 struct ath6kl_vif *vif;
Raja Mani390a8c82012-03-07 11:35:04 +05302253 enum ath6kl_state prev_state;
Kalle Valo52d81a62011-11-01 08:44:21 +02002254 int ret;
2255
Kalle Valo52d81a62011-11-01 08:44:21 +02002256 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02002257 case ATH6KL_CFG_SUSPEND_WOW:
2258
2259 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
2260
2261 /* Flush all non control pkts in TX path */
2262 ath6kl_tx_data_cleanup(ar);
2263
Raja Mani390a8c82012-03-07 11:35:04 +05302264 prev_state = ar->state;
2265
Raja Manid7c44e02011-11-07 22:52:46 +02002266 ret = ath6kl_wow_suspend(ar, wow);
Raja Mani390a8c82012-03-07 11:35:04 +05302267 if (ret) {
2268 ar->state = prev_state;
Raja Manid7c44e02011-11-07 22:52:46 +02002269 return ret;
Raja Mani390a8c82012-03-07 11:35:04 +05302270 }
Raja Mani1e9a9052012-03-06 15:03:59 +05302271
Raja Manid7c44e02011-11-07 22:52:46 +02002272 ar->state = ATH6KL_STATE_WOW;
2273 break;
2274
Kalle Valo52d81a62011-11-01 08:44:21 +02002275 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02002276
Raja Mani40abc2d2012-03-21 15:03:38 +05302277 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n");
Raja Mani524441e2011-11-07 22:52:46 +02002278
Raja Mani40abc2d2012-03-21 15:03:38 +05302279 ret = ath6kl_cfg80211_deepsleep_suspend(ar);
Kalle Valo52d81a62011-11-01 08:44:21 +02002280 if (ret) {
Raja Mani40abc2d2012-03-21 15:03:38 +05302281 ath6kl_err("deepsleep suspend failed: %d\n", ret);
2282 return ret;
Kalle Valo52d81a62011-11-01 08:44:21 +02002283 }
2284
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002285 ar->state = ATH6KL_STATE_DEEPSLEEP;
2286
Kalle Valo52d81a62011-11-01 08:44:21 +02002287 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002288
2289 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02002290
Kalle Valo7125f012011-12-13 14:51:37 +02002291 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02002292
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002293 if (ar->state == ATH6KL_STATE_OFF) {
2294 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
2295 "suspend hw off, no action for cutpower\n");
2296 break;
2297 }
2298
2299 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
2300
2301 ret = ath6kl_init_hw_stop(ar);
2302 if (ret) {
2303 ath6kl_warn("failed to stop hw during suspend: %d\n",
2304 ret);
2305 }
2306
2307 ar->state = ATH6KL_STATE_CUTPOWER;
2308
2309 break;
2310
Kalle Valo10509f92011-12-13 14:52:07 +02002311 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
2312 /*
2313 * Nothing needed for schedule scan, firmware is already in
2314 * wow mode and sleeping most of the time.
2315 */
2316 break;
2317
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002318 default:
2319 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002320 }
2321
Vivek Natarajan3d794992012-03-28 19:21:26 +05302322 list_for_each_entry(vif, &ar->vif_list, list)
2323 ath6kl_cfg80211_scan_complete_event(vif, true);
2324
Kalle Valo52d81a62011-11-01 08:44:21 +02002325 return 0;
2326}
Kalle Valod6a434d2012-01-17 20:09:36 +02002327EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
Kalle Valo52d81a62011-11-01 08:44:21 +02002328
2329int ath6kl_cfg80211_resume(struct ath6kl *ar)
2330{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002331 int ret;
2332
2333 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02002334 case ATH6KL_STATE_WOW:
2335 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
2336
2337 ret = ath6kl_wow_resume(ar);
2338 if (ret) {
2339 ath6kl_warn("wow mode resume failed: %d\n", ret);
2340 return ret;
2341 }
2342
Raja Manid7c44e02011-11-07 22:52:46 +02002343 break;
2344
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002345 case ATH6KL_STATE_DEEPSLEEP:
Raja Mani40abc2d2012-03-21 15:03:38 +05302346 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
2347
2348 ret = ath6kl_cfg80211_deepsleep_resume(ar);
2349 if (ret) {
2350 ath6kl_warn("deep sleep resume failed: %d\n", ret);
2351 return ret;
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002352 }
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002353 break;
2354
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002355 case ATH6KL_STATE_CUTPOWER:
2356 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
2357
2358 ret = ath6kl_init_hw_start(ar);
2359 if (ret) {
2360 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
2361 return ret;
2362 }
Raja Manid7c44e02011-11-07 22:52:46 +02002363 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002364
Kalle Valo10509f92011-12-13 14:52:07 +02002365 case ATH6KL_STATE_SCHED_SCAN:
2366 break;
2367
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002368 default:
2369 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002370 }
2371
2372 return 0;
2373}
Kalle Valod6a434d2012-01-17 20:09:36 +02002374EXPORT_SYMBOL(ath6kl_cfg80211_resume);
Kalle Valo52d81a62011-11-01 08:44:21 +02002375
Kalle Valoabcb3442011-07-22 08:26:20 +03002376#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002377
2378/* hif layer decides what suspend mode to use */
2379static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03002380 struct cfg80211_wowlan *wow)
2381{
2382 struct ath6kl *ar = wiphy_priv(wiphy);
2383
Raja Mani0f60e9f2011-11-07 22:52:45 +02002384 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03002385}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002386
Kalle Valo52d81a62011-11-01 08:44:21 +02002387static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002388{
2389 struct ath6kl *ar = wiphy_priv(wiphy);
2390
2391 return ath6kl_hif_resume(ar);
2392}
Raja Mania918fb32011-11-07 22:52:46 +02002393
2394/*
2395 * FIXME: WOW suspend mode is selected if the host sdio controller supports
2396 * both sdio irq wake up and keep power. The target pulls sdio data line to
2397 * wake up the host when WOW pattern matches. This causes sdio irq handler
2398 * is being called in the host side which internally hits ath6kl's RX path.
2399 *
2400 * Since sdio interrupt is not disabled, RX path executes even before
2401 * the host executes the actual resume operation from PM module.
2402 *
2403 * In the current scenario, WOW resume should happen before start processing
2404 * any data from the target. So It's required to perform WOW resume in RX path.
2405 * Ideally we should perform WOW resume only in the actual platform
2406 * resume path. This area needs bit rework to avoid WOW resume in RX path.
2407 *
2408 * ath6kl_check_wow_status() is called from ath6kl_rx().
2409 */
2410void ath6kl_check_wow_status(struct ath6kl *ar)
2411{
Raja Mani390a8c82012-03-07 11:35:04 +05302412 if (ar->state == ATH6KL_STATE_SUSPENDING)
2413 return;
2414
Raja Mania918fb32011-11-07 22:52:46 +02002415 if (ar->state == ATH6KL_STATE_WOW)
2416 ath6kl_cfg80211_resume(ar);
2417}
2418
2419#else
2420
2421void ath6kl_check_wow_status(struct ath6kl *ar)
2422{
2423}
Kalle Valoabcb3442011-07-22 08:26:20 +03002424#endif
2425
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002426static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
2427 struct ieee80211_channel *chan,
2428 enum nl80211_channel_type channel_type)
2429{
Sujith Manoharane68f6752011-12-22 12:15:27 +05302430 struct ath6kl_vif *vif;
2431
2432 /*
2433 * 'dev' could be NULL if a channel change is required for the hardware
2434 * device itself, instead of a particular VIF.
2435 *
2436 * FIXME: To be handled properly when monitor mode is supported.
2437 */
2438 if (!dev)
2439 return -EBUSY;
2440
2441 vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002442
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302443 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002444 return -EIO;
2445
2446 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
2447 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302448 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002449
2450 return 0;
2451}
2452
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002453static bool ath6kl_is_p2p_ie(const u8 *pos)
2454{
2455 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2456 pos[2] == 0x50 && pos[3] == 0x6f &&
2457 pos[4] == 0x9a && pos[5] == 0x09;
2458}
2459
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302460static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2461 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002462{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302463 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002464 const u8 *pos;
2465 u8 *buf = NULL;
2466 size_t len = 0;
2467 int ret;
2468
2469 /*
2470 * Filter out P2P IE(s) since they will be included depending on
2471 * the Probe Request frame in ath6kl_send_go_probe_resp().
2472 */
2473
2474 if (ies && ies_len) {
2475 buf = kmalloc(ies_len, GFP_KERNEL);
2476 if (buf == NULL)
2477 return -ENOMEM;
2478 pos = ies;
2479 while (pos + 1 < ies + ies_len) {
2480 if (pos + 2 + pos[1] > ies + ies_len)
2481 break;
2482 if (!ath6kl_is_p2p_ie(pos)) {
2483 memcpy(buf + len, pos, 2 + pos[1]);
2484 len += 2 + pos[1];
2485 }
2486 pos += 2 + pos[1];
2487 }
2488 }
2489
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302490 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2491 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002492 kfree(buf);
2493 return ret;
2494}
2495
Johannes Berg88600202012-02-13 15:17:18 +01002496static int ath6kl_set_ies(struct ath6kl_vif *vif,
2497 struct cfg80211_beacon_data *info)
2498{
2499 struct ath6kl *ar = vif->ar;
2500 int res;
2501
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002502 /* this also clears IE in fw if it's not set */
2503 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2504 WMI_FRAME_BEACON,
2505 info->beacon_ies,
2506 info->beacon_ies_len);
2507 if (res)
2508 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002509
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002510 /* this also clears IE in fw if it's not set */
2511 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
2512 info->proberesp_ies_len);
2513 if (res)
2514 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002515
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002516 /* this also clears IE in fw if it's not set */
2517 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2518 WMI_FRAME_ASSOC_RESP,
2519 info->assocresp_ies,
2520 info->assocresp_ies_len);
2521 if (res)
2522 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002523
2524 return 0;
2525}
2526
2527static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2528 struct cfg80211_ap_settings *info)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002529{
2530 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302531 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002532 struct ieee80211_mgmt *mgmt;
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002533 bool hidden = false;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002534 u8 *ies;
2535 int ies_len;
2536 struct wmi_connect_cmd p;
2537 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302538 int i, ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002539
Johannes Berg88600202012-02-13 15:17:18 +01002540 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002541
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302542 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002543 return -EIO;
2544
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302545 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002546 return -EOPNOTSUPP;
2547
Johannes Berg88600202012-02-13 15:17:18 +01002548 res = ath6kl_set_ies(vif, &info->beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002549
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002550 ar->ap_mode_bkey.valid = false;
2551
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002552 /* TODO:
2553 * info->interval
2554 * info->dtim_period
2555 */
2556
Johannes Berg88600202012-02-13 15:17:18 +01002557 if (info->beacon.head == NULL)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002558 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002559 mgmt = (struct ieee80211_mgmt *) info->beacon.head;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002560 ies = mgmt->u.beacon.variable;
Johannes Berg88600202012-02-13 15:17:18 +01002561 if (ies > info->beacon.head + info->beacon.head_len)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002562 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002563 ies_len = info->beacon.head + info->beacon.head_len - ies;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002564
2565 if (info->ssid == NULL)
2566 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302567 memcpy(vif->ssid, info->ssid, info->ssid_len);
2568 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002569 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002570 hidden = true;
2571
2572 res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
2573 if (res)
2574 return res;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002575
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302576 ret = ath6kl_set_auth_type(vif, info->auth_type);
2577 if (ret)
2578 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002579
2580 memset(&p, 0, sizeof(p));
2581
2582 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2583 switch (info->crypto.akm_suites[i]) {
2584 case WLAN_AKM_SUITE_8021X:
2585 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2586 p.auth_mode |= WPA_AUTH;
2587 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2588 p.auth_mode |= WPA2_AUTH;
2589 break;
2590 case WLAN_AKM_SUITE_PSK:
2591 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2592 p.auth_mode |= WPA_PSK_AUTH;
2593 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2594 p.auth_mode |= WPA2_PSK_AUTH;
2595 break;
2596 }
2597 }
2598 if (p.auth_mode == 0)
2599 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302600 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002601
2602 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2603 switch (info->crypto.ciphers_pairwise[i]) {
2604 case WLAN_CIPHER_SUITE_WEP40:
2605 case WLAN_CIPHER_SUITE_WEP104:
2606 p.prwise_crypto_type |= WEP_CRYPT;
2607 break;
2608 case WLAN_CIPHER_SUITE_TKIP:
2609 p.prwise_crypto_type |= TKIP_CRYPT;
2610 break;
2611 case WLAN_CIPHER_SUITE_CCMP:
2612 p.prwise_crypto_type |= AES_CRYPT;
2613 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002614 case WLAN_CIPHER_SUITE_SMS4:
2615 p.prwise_crypto_type |= WAPI_CRYPT;
2616 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002617 }
2618 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002619 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002620 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302621 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03002622 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302623 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002624
2625 switch (info->crypto.cipher_group) {
2626 case WLAN_CIPHER_SUITE_WEP40:
2627 case WLAN_CIPHER_SUITE_WEP104:
2628 p.grp_crypto_type = WEP_CRYPT;
2629 break;
2630 case WLAN_CIPHER_SUITE_TKIP:
2631 p.grp_crypto_type = TKIP_CRYPT;
2632 break;
2633 case WLAN_CIPHER_SUITE_CCMP:
2634 p.grp_crypto_type = AES_CRYPT;
2635 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002636 case WLAN_CIPHER_SUITE_SMS4:
2637 p.grp_crypto_type = WAPI_CRYPT;
2638 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002639 default:
2640 p.grp_crypto_type = NONE_CRYPT;
2641 break;
2642 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302643 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002644
2645 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302646 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002647
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302648 p.ssid_len = vif->ssid_len;
2649 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2650 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302651 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002652
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302653 /* Enable uAPSD support by default */
2654 res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
2655 if (res < 0)
2656 return res;
2657
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002658 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2659 p.nw_subtype = SUBTYPE_P2PGO;
2660 } else {
2661 /*
2662 * Due to firmware limitation, it is not possible to
2663 * do P2P mgmt operations in AP mode
2664 */
2665 p.nw_subtype = SUBTYPE_NONE;
2666 }
2667
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302668 if (info->inactivity_timeout) {
2669 res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
2670 info->inactivity_timeout);
2671 if (res < 0)
2672 return res;
2673 }
2674
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302675 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002676 if (res < 0)
2677 return res;
2678
2679 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002680}
2681
Johannes Berg88600202012-02-13 15:17:18 +01002682static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
2683 struct cfg80211_beacon_data *beacon)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002684{
Johannes Berg88600202012-02-13 15:17:18 +01002685 struct ath6kl_vif *vif = netdev_priv(dev);
2686
2687 if (!ath6kl_cfg80211_ready(vif))
2688 return -EIO;
2689
2690 if (vif->next_mode != AP_NETWORK)
2691 return -EOPNOTSUPP;
2692
2693 return ath6kl_set_ies(vif, beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002694}
2695
Johannes Berg88600202012-02-13 15:17:18 +01002696static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002697{
2698 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302699 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002700
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302701 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002702 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302703 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002704 return -ENOTCONN;
2705
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302706 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302707 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002708
2709 return 0;
2710}
2711
Jouni Malinen33e53082011-12-27 11:02:56 +02002712static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2713
2714static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
2715 u8 *mac)
2716{
2717 struct ath6kl *ar = ath6kl_priv(dev);
2718 struct ath6kl_vif *vif = netdev_priv(dev);
2719 const u8 *addr = mac ? mac : bcast_addr;
2720
2721 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
2722 addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
2723}
2724
Jouni Malinen23875132011-08-30 21:57:53 +03002725static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
2726 u8 *mac, struct station_parameters *params)
2727{
2728 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302729 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03002730
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302731 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03002732 return -EOPNOTSUPP;
2733
2734 /* Use this only for authorizing/unauthorizing a station */
2735 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
2736 return -EOPNOTSUPP;
2737
2738 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302739 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2740 WMI_AP_MLME_AUTHORIZE, mac, 0);
2741 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
2742 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03002743}
2744
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002745static int ath6kl_remain_on_channel(struct wiphy *wiphy,
2746 struct net_device *dev,
2747 struct ieee80211_channel *chan,
2748 enum nl80211_channel_type channel_type,
2749 unsigned int duration,
2750 u64 *cookie)
2751{
2752 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302753 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen10522612011-10-27 16:00:13 +03002754 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002755
2756 /* TODO: if already pending or ongoing remain-on-channel,
2757 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03002758 id = ++vif->last_roc_id;
2759 if (id == 0) {
2760 /* Do not use 0 as the cookie value */
2761 id = ++vif->last_roc_id;
2762 }
2763 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002764
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302765 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
2766 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002767}
2768
2769static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
2770 struct net_device *dev,
2771 u64 cookie)
2772{
2773 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302774 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002775
Jouni Malinen10522612011-10-27 16:00:13 +03002776 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002777 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03002778 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002779
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302780 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002781}
2782
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302783static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
2784 const u8 *buf, size_t len,
2785 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002786{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302787 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002788 const u8 *pos;
2789 u8 *p2p;
2790 int p2p_len;
2791 int ret;
2792 const struct ieee80211_mgmt *mgmt;
2793
2794 mgmt = (const struct ieee80211_mgmt *) buf;
2795
2796 /* Include P2P IE(s) from the frame generated in user space. */
2797
2798 p2p = kmalloc(len, GFP_KERNEL);
2799 if (p2p == NULL)
2800 return -ENOMEM;
2801 p2p_len = 0;
2802
2803 pos = mgmt->u.probe_resp.variable;
2804 while (pos + 1 < buf + len) {
2805 if (pos + 2 + pos[1] > buf + len)
2806 break;
2807 if (ath6kl_is_p2p_ie(pos)) {
2808 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
2809 p2p_len += 2 + pos[1];
2810 }
2811 pos += 2 + pos[1];
2812 }
2813
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302814 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
2815 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002816 kfree(p2p);
2817 return ret;
2818}
2819
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08002820static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
2821 u32 id,
2822 u32 freq,
2823 u32 wait,
2824 const u8 *buf,
2825 size_t len,
2826 bool *more_data,
2827 bool no_cck)
2828{
2829 struct ieee80211_mgmt *mgmt;
2830 struct ath6kl_sta *conn;
2831 bool is_psq_empty = false;
2832 struct ath6kl_mgmt_buff *mgmt_buf;
2833 size_t mgmt_buf_size;
2834 struct ath6kl *ar = vif->ar;
2835
2836 mgmt = (struct ieee80211_mgmt *) buf;
2837 if (is_multicast_ether_addr(mgmt->da))
2838 return false;
2839
2840 conn = ath6kl_find_sta(vif, mgmt->da);
2841 if (!conn)
2842 return false;
2843
2844 if (conn->sta_flags & STA_PS_SLEEP) {
2845 if (!(conn->sta_flags & STA_PS_POLLED)) {
2846 /* Queue the frames if the STA is sleeping */
2847 mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
2848 mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
2849 if (!mgmt_buf)
2850 return false;
2851
2852 INIT_LIST_HEAD(&mgmt_buf->list);
2853 mgmt_buf->id = id;
2854 mgmt_buf->freq = freq;
2855 mgmt_buf->wait = wait;
2856 mgmt_buf->len = len;
2857 mgmt_buf->no_cck = no_cck;
2858 memcpy(mgmt_buf->buf, buf, len);
2859 spin_lock_bh(&conn->psq_lock);
2860 is_psq_empty = skb_queue_empty(&conn->psq) &&
2861 (conn->mgmt_psq_len == 0);
2862 list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
2863 conn->mgmt_psq_len++;
2864 spin_unlock_bh(&conn->psq_lock);
2865
2866 /*
2867 * If this is the first pkt getting queued
2868 * for this STA, update the PVB for this
2869 * STA.
2870 */
2871 if (is_psq_empty)
2872 ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
2873 conn->aid, 1);
2874 return true;
2875 }
2876
2877 /*
2878 * This tx is because of a PsPoll.
2879 * Determine if MoreData bit has to be set.
2880 */
2881 spin_lock_bh(&conn->psq_lock);
2882 if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
2883 *more_data = true;
2884 spin_unlock_bh(&conn->psq_lock);
2885 }
2886
2887 return false;
2888}
2889
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07002890/* Check if SSID length is greater than DIRECT- */
2891static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
2892{
2893 const struct ieee80211_mgmt *mgmt;
2894 mgmt = (const struct ieee80211_mgmt *) buf;
2895
2896 /* variable[1] contains the SSID tag length */
2897 if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
2898 (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
2899 return true;
2900 }
2901
2902 return false;
2903}
2904
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002905static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2906 struct ieee80211_channel *chan, bool offchan,
2907 enum nl80211_channel_type channel_type,
2908 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01002909 const u8 *buf, size_t len, bool no_cck,
2910 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002911{
2912 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302913 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002914 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002915 const struct ieee80211_mgmt *mgmt;
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08002916 bool more_data, queued;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002917
2918 mgmt = (const struct ieee80211_mgmt *) buf;
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07002919 if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
2920 ieee80211_is_probe_resp(mgmt->frame_control) &&
2921 ath6kl_is_p2p_go_ssid(buf, len)) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002922 /*
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07002923 * Send Probe Response frame in GO mode using a separate WMI
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002924 * command to allow the target to fill in the generic IEs.
2925 */
2926 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302927 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002928 chan->center_freq);
2929 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002930
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302931 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002932 if (id == 0) {
2933 /*
2934 * 0 is a reserved value in the WMI command and shall not be
2935 * used for the command.
2936 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302937 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002938 }
2939
2940 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002941
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08002942 /* AP mode Power saving processing */
2943 if (vif->nw_type == AP_NETWORK) {
2944 queued = ath6kl_mgmt_powersave_ap(vif,
2945 id, chan->center_freq,
2946 wait, buf,
2947 len, &more_data, no_cck);
2948 if (queued)
2949 return 0;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002950 }
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08002951
2952 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
2953 chan->center_freq, wait,
2954 buf, len, no_cck);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002955}
2956
Jouni Malinenae32c302011-08-30 21:58:01 +03002957static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2958 struct net_device *dev,
2959 u16 frame_type, bool reg)
2960{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302961 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002962
2963 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2964 __func__, frame_type, reg);
2965 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2966 /*
2967 * Note: This notification callback is not allowed to sleep, so
2968 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2969 * hardcode target to report Probe Request frames all the time.
2970 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302971 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002972 }
2973}
2974
Kalle Valo10509f92011-12-13 14:52:07 +02002975static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2976 struct net_device *dev,
2977 struct cfg80211_sched_scan_request *request)
2978{
2979 struct ath6kl *ar = ath6kl_priv(dev);
2980 struct ath6kl_vif *vif = netdev_priv(dev);
2981 u16 interval;
2982 int ret;
2983 u8 i;
2984
2985 if (ar->state != ATH6KL_STATE_ON)
2986 return -EIO;
2987
2988 if (vif->sme_state != SME_DISCONNECTED)
2989 return -EBUSY;
2990
Kalle Valob4d13d32012-03-21 10:01:09 +02002991 ath6kl_cfg80211_scan_complete_event(vif, true);
2992
Kalle Valo10509f92011-12-13 14:52:07 +02002993 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2994 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2995 i, DISABLE_SSID_FLAG,
2996 0, NULL);
2997 }
2998
2999 /* fw uses seconds, also make sure that it's >0 */
3000 interval = max_t(u16, 1, request->interval / 1000);
3001
3002 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
3003 interval, interval,
3004 10, 0, 0, 0, 3, 0, 0, 0);
3005
3006 if (request->n_ssids && request->ssids[0].ssid_len) {
3007 for (i = 0; i < request->n_ssids; i++) {
3008 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
3009 i, SPECIFIC_SSID_FLAG,
3010 request->ssids[i].ssid_len,
3011 request->ssids[i].ssid);
3012 }
3013 }
3014
3015 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
3016 ATH6KL_WOW_MODE_ENABLE,
3017 WOW_FILTER_SSID,
3018 WOW_HOST_REQ_DELAY);
3019 if (ret) {
3020 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
3021 return ret;
3022 }
3023
3024 /* this also clears IE in fw if it's not set */
3025 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
3026 WMI_FRAME_PROBE_REQ,
3027 request->ie, request->ie_len);
3028 if (ret) {
3029 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
3030 ret);
3031 return ret;
3032 }
3033
3034 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
3035 ATH6KL_HOST_MODE_ASLEEP);
3036 if (ret) {
3037 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
3038 ret);
3039 return ret;
3040 }
3041
3042 ar->state = ATH6KL_STATE_SCHED_SCAN;
3043
3044 return ret;
3045}
3046
3047static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
3048 struct net_device *dev)
3049{
3050 struct ath6kl_vif *vif = netdev_priv(dev);
3051 bool stopped;
3052
3053 stopped = __ath6kl_cfg80211_sscan_stop(vif);
3054
3055 if (!stopped)
3056 return -EIO;
3057
3058 return 0;
3059}
3060
Jouni Malinenf80574a2011-08-30 21:58:04 +03003061static const struct ieee80211_txrx_stypes
3062ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
3063 [NL80211_IFTYPE_STATION] = {
3064 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3065 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3066 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3067 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3068 },
Jouni Malinenba1f6fe2011-12-27 11:03:53 +02003069 [NL80211_IFTYPE_AP] = {
3070 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3071 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3072 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3073 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3074 },
Jouni Malinenf80574a2011-08-30 21:58:04 +03003075 [NL80211_IFTYPE_P2P_CLIENT] = {
3076 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3077 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3078 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3079 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3080 },
3081 [NL80211_IFTYPE_P2P_GO] = {
3082 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3083 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3084 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3085 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3086 },
3087};
3088
Kalle Valobdcd8172011-07-18 00:22:30 +03003089static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303090 .add_virtual_intf = ath6kl_cfg80211_add_iface,
3091 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03003092 .change_virtual_intf = ath6kl_cfg80211_change_iface,
3093 .scan = ath6kl_cfg80211_scan,
3094 .connect = ath6kl_cfg80211_connect,
3095 .disconnect = ath6kl_cfg80211_disconnect,
3096 .add_key = ath6kl_cfg80211_add_key,
3097 .get_key = ath6kl_cfg80211_get_key,
3098 .del_key = ath6kl_cfg80211_del_key,
3099 .set_default_key = ath6kl_cfg80211_set_default_key,
3100 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
3101 .set_tx_power = ath6kl_cfg80211_set_txpower,
3102 .get_tx_power = ath6kl_cfg80211_get_txpower,
3103 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
3104 .join_ibss = ath6kl_cfg80211_join_ibss,
3105 .leave_ibss = ath6kl_cfg80211_leave_ibss,
3106 .get_station = ath6kl_get_station,
3107 .set_pmksa = ath6kl_set_pmksa,
3108 .del_pmksa = ath6kl_del_pmksa,
3109 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03003110 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03003111#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02003112 .suspend = __ath6kl_cfg80211_suspend,
3113 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03003114#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03003115 .set_channel = ath6kl_set_channel,
Johannes Berg88600202012-02-13 15:17:18 +01003116 .start_ap = ath6kl_start_ap,
3117 .change_beacon = ath6kl_change_beacon,
3118 .stop_ap = ath6kl_stop_ap,
Jouni Malinen33e53082011-12-27 11:02:56 +02003119 .del_station = ath6kl_del_station,
Jouni Malinen23875132011-08-30 21:57:53 +03003120 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003121 .remain_on_channel = ath6kl_remain_on_channel,
3122 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003123 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03003124 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valo10509f92011-12-13 14:52:07 +02003125 .sched_scan_start = ath6kl_cfg80211_sscan_start,
3126 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Kalle Valobdcd8172011-07-18 00:22:30 +03003127};
3128
Kalle Valo7125f012011-12-13 14:51:37 +02003129void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02003130{
Kalle Valo10509f92011-12-13 14:52:07 +02003131 ath6kl_cfg80211_sscan_disable(vif);
3132
Kalle Valoec4b7f62011-11-01 08:44:04 +02003133 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02003134 case SME_DISCONNECTED:
3135 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02003136 case SME_CONNECTING:
3137 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
3138 NULL, 0,
3139 WLAN_STATUS_UNSPECIFIED_FAILURE,
3140 GFP_KERNEL);
3141 break;
3142 case SME_CONNECTED:
Kalle Valoec4b7f62011-11-01 08:44:04 +02003143 cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
3144 break;
3145 }
3146
3147 if (test_bit(CONNECTED, &vif->flags) ||
3148 test_bit(CONNECT_PEND, &vif->flags))
Kalle Valo7125f012011-12-13 14:51:37 +02003149 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003150
3151 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02003152 clear_bit(CONNECTED, &vif->flags);
3153 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003154
3155 /* disable scanning */
Kalle Valo7125f012011-12-13 14:51:37 +02003156 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
3157 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
3158 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02003159
3160 ath6kl_cfg80211_scan_complete_event(vif, true);
3161}
3162
Kalle Valo7125f012011-12-13 14:51:37 +02003163void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
3164{
3165 struct ath6kl_vif *vif;
3166
3167 vif = ath6kl_vif_first(ar);
3168 if (!vif) {
3169 /* save the current power mode before enabling power save */
3170 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
3171
3172 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
3173 ath6kl_warn("ath6kl_deep_sleep_enable: "
3174 "wmi_powermode_cmd failed\n");
3175 return;
3176 }
3177
3178 /*
3179 * FIXME: we should take ar->list_lock to protect changes in the
3180 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
3181 * sleeps.
3182 */
3183 list_for_each_entry(vif, &ar->vif_list, list)
3184 ath6kl_cfg80211_stop(vif);
3185}
3186
Kalle Valoc25889e2012-01-17 20:08:27 +02003187static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03003188{
Vasanthakumar Thiagarajan7baef812012-01-21 15:22:50 +05303189 vif->aggr_cntxt = aggr_init(vif);
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303190 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303191 ath6kl_err("failed to initialize aggr\n");
3192 return -ENOMEM;
3193 }
Kalle Valobdcd8172011-07-18 00:22:30 +03003194
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303195 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303196 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02003197 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
3198 (unsigned long) vif);
3199
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303200 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05303201 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303202
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303203 INIT_LIST_HEAD(&vif->mc_filter);
3204
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303205 return 0;
3206}
3207
Kalle Valoc25889e2012-01-17 20:08:27 +02003208void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303209{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303210 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303211 struct ath6kl_mc_filter *mc_filter, *tmp;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303212
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303213 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303214
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303215 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
3216
3217 if (vif->nw_type == ADHOC_NETWORK)
3218 ar->ibss_if_active = false;
3219
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303220 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
3221 list_del(&mc_filter->list);
3222 kfree(mc_filter);
3223 }
3224
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303225 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303226
3227 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303228}
3229
3230struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303231 enum nl80211_iftype type, u8 fw_vif_idx,
3232 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303233{
3234 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303235 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303236
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303237 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303238 if (!ndev)
3239 return NULL;
3240
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303241 vif = netdev_priv(ndev);
3242 ndev->ieee80211_ptr = &vif->wdev;
3243 vif->wdev.wiphy = ar->wiphy;
3244 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303245 vif->ndev = ndev;
3246 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
3247 vif->wdev.netdev = ndev;
3248 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303249 vif->fw_vif_idx = fw_vif_idx;
Kalle Valod0d670a2012-03-07 20:03:58 +02003250 vif->nw_type = nw_type;
3251 vif->next_mode = nw_type;
Raja Mani8f46fcc2012-02-20 19:08:07 +05303252 vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
Raja Manice0dc0c2012-02-20 19:08:08 +05303253 vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303254
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303255 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
3256 if (fw_vif_idx != 0)
3257 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
3258 0x2;
3259
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303260 init_netdev(ndev);
3261
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05303262 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303263
Kalle Valoc25889e2012-01-17 20:08:27 +02003264 if (ath6kl_cfg80211_vif_init(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303265 goto err;
3266
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303267 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303268 goto err;
3269
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303270 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05303271 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05303272 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303273 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05303274 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303275
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303276 if (type == NL80211_IFTYPE_ADHOC)
3277 ar->ibss_if_active = true;
3278
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303279 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303280 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303281 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303282
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303283 return ndev;
3284
3285err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303286 aggr_module_destroy(vif->aggr_cntxt);
3287 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303288 return NULL;
3289}
3290
Kalle Valo46d33a22012-01-17 20:08:40 +02003291int ath6kl_cfg80211_init(struct ath6kl *ar)
3292{
3293 struct wiphy *wiphy = ar->wiphy;
3294 int ret;
3295
3296 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
3297
3298 wiphy->max_remain_on_channel_duration = 5000;
3299
3300 /* set device pointer for wiphy */
3301 set_wiphy_dev(wiphy, ar->dev);
3302
3303 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3304 BIT(NL80211_IFTYPE_ADHOC) |
3305 BIT(NL80211_IFTYPE_AP);
3306 if (ar->p2p) {
3307 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
3308 BIT(NL80211_IFTYPE_P2P_CLIENT);
3309 }
3310
3311 /* max num of ssids that can be probed during scanning */
3312 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
3313 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
3314 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
3315 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
3316 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3317
3318 wiphy->cipher_suites = cipher_suites;
3319 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3320
3321 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
3322 WIPHY_WOWLAN_DISCONNECT |
3323 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
3324 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
3325 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
3326 WIPHY_WOWLAN_4WAY_HANDSHAKE;
3327 wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
3328 wiphy->wowlan.pattern_min_len = 1;
3329 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
3330
3331 wiphy->max_sched_scan_ssids = 10;
3332
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303333 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
3334 WIPHY_FLAG_HAVE_AP_SME |
3335 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
3336 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
3337
3338 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
3339 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
3340
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05303341 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
3342 ar->fw_capabilities))
3343 ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
3344
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303345 ar->wiphy->probe_resp_offload =
3346 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
3347 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
3348 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
3349 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
3350
Kalle Valo46d33a22012-01-17 20:08:40 +02003351 ret = wiphy_register(wiphy);
3352 if (ret < 0) {
3353 ath6kl_err("couldn't register wiphy device\n");
3354 return ret;
3355 }
3356
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05303357 ar->wiphy_registered = true;
3358
Kalle Valo46d33a22012-01-17 20:08:40 +02003359 return 0;
3360}
3361
3362void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303363{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05303364 wiphy_unregister(ar->wiphy);
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05303365
3366 ar->wiphy_registered = false;
Kalle Valo45eaa782012-01-17 20:09:05 +02003367}
Kalle Valo46d33a22012-01-17 20:08:40 +02003368
Kalle Valo45eaa782012-01-17 20:09:05 +02003369struct ath6kl *ath6kl_cfg80211_create(void)
3370{
3371 struct ath6kl *ar;
3372 struct wiphy *wiphy;
3373
3374 /* create a new wiphy for use with cfg80211 */
3375 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
3376
3377 if (!wiphy) {
3378 ath6kl_err("couldn't allocate wiphy device\n");
3379 return NULL;
3380 }
3381
3382 ar = wiphy_priv(wiphy);
3383 ar->wiphy = wiphy;
3384
3385 return ar;
3386}
3387
3388/* Note: ar variable must not be accessed after calling this! */
3389void ath6kl_cfg80211_destroy(struct ath6kl *ar)
3390{
Vasanthakumar Thiagarajan1d2a4452012-01-21 15:22:53 +05303391 int i;
3392
3393 for (i = 0; i < AP_MAX_NUM_STA; i++)
3394 kfree(ar->sta_list[i].aggr_conn);
3395
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05303396 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03003397}
Kalle Valo45eaa782012-01-17 20:09:05 +02003398