blob: 07dcb826fde1aca166a77b4e2aaa14095eb65f03 [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
Joe Perches516304b2012-03-18 17:30:52 -070018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040020#include <linux/moduleparam.h>
Raja Manic08631c2011-12-16 14:24:24 +053021#include <linux/inetdevice.h>
Kalle Valod6a434d2012-01-17 20:09:36 +020022#include <linux/export.h>
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040023
Kalle Valobdcd8172011-07-18 00:22:30 +030024#include "core.h"
25#include "cfg80211.h"
26#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030027#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030028#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030029
30#define RATETAB_ENT(_rate, _rateid, _flags) { \
31 .bitrate = (_rate), \
32 .flags = (_flags), \
33 .hw_value = (_rateid), \
34}
35
36#define CHAN2G(_channel, _freq, _flags) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +020037 .band = NL80211_BAND_2GHZ, \
Kalle Valobdcd8172011-07-18 00:22:30 +030038 .hw_value = (_channel), \
39 .center_freq = (_freq), \
40 .flags = (_flags), \
41 .max_antenna_gain = 0, \
42 .max_power = 30, \
43}
44
45#define CHAN5G(_channel, _flags) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +020046 .band = NL80211_BAND_5GHZ, \
Kalle Valobdcd8172011-07-18 00:22:30 +030047 .hw_value = (_channel), \
48 .center_freq = 5000 + (5 * (_channel)), \
49 .flags = (_flags), \
50 .max_antenna_gain = 0, \
51 .max_power = 30, \
52}
53
Bala Shanmugamf5993592012-03-27 12:17:32 +053054#define DEFAULT_BG_SCAN_PERIOD 60
55
Naveen Singhdd45b752012-05-16 13:29:00 +030056struct ath6kl_cfg80211_match_probe_ssid {
57 struct cfg80211_ssid ssid;
58 u8 flag;
59};
60
Kalle Valobdcd8172011-07-18 00:22:30 +030061static struct ieee80211_rate ath6kl_rates[] = {
62 RATETAB_ENT(10, 0x1, 0),
63 RATETAB_ENT(20, 0x2, 0),
64 RATETAB_ENT(55, 0x4, 0),
65 RATETAB_ENT(110, 0x8, 0),
66 RATETAB_ENT(60, 0x10, 0),
67 RATETAB_ENT(90, 0x20, 0),
68 RATETAB_ENT(120, 0x40, 0),
69 RATETAB_ENT(180, 0x80, 0),
70 RATETAB_ENT(240, 0x100, 0),
71 RATETAB_ENT(360, 0x200, 0),
72 RATETAB_ENT(480, 0x400, 0),
73 RATETAB_ENT(540, 0x800, 0),
74};
75
76#define ath6kl_a_rates (ath6kl_rates + 4)
77#define ath6kl_a_rates_size 8
78#define ath6kl_g_rates (ath6kl_rates + 0)
79#define ath6kl_g_rates_size 12
80
Vasanthakumar Thiagarajanbed56e32012-04-09 19:03:57 +053081#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20
82#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +053083 IEEE80211_HT_CAP_SGI_20 | \
84 IEEE80211_HT_CAP_SGI_40)
85
Kalle Valobdcd8172011-07-18 00:22:30 +030086static struct ieee80211_channel ath6kl_2ghz_channels[] = {
87 CHAN2G(1, 2412, 0),
88 CHAN2G(2, 2417, 0),
89 CHAN2G(3, 2422, 0),
90 CHAN2G(4, 2427, 0),
91 CHAN2G(5, 2432, 0),
92 CHAN2G(6, 2437, 0),
93 CHAN2G(7, 2442, 0),
94 CHAN2G(8, 2447, 0),
95 CHAN2G(9, 2452, 0),
96 CHAN2G(10, 2457, 0),
97 CHAN2G(11, 2462, 0),
98 CHAN2G(12, 2467, 0),
99 CHAN2G(13, 2472, 0),
100 CHAN2G(14, 2484, 0),
101};
102
103static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
104 CHAN5G(34, 0), CHAN5G(36, 0),
105 CHAN5G(38, 0), CHAN5G(40, 0),
106 CHAN5G(42, 0), CHAN5G(44, 0),
107 CHAN5G(46, 0), CHAN5G(48, 0),
108 CHAN5G(52, 0), CHAN5G(56, 0),
109 CHAN5G(60, 0), CHAN5G(64, 0),
110 CHAN5G(100, 0), CHAN5G(104, 0),
111 CHAN5G(108, 0), CHAN5G(112, 0),
112 CHAN5G(116, 0), CHAN5G(120, 0),
113 CHAN5G(124, 0), CHAN5G(128, 0),
114 CHAN5G(132, 0), CHAN5G(136, 0),
115 CHAN5G(140, 0), CHAN5G(149, 0),
116 CHAN5G(153, 0), CHAN5G(157, 0),
117 CHAN5G(161, 0), CHAN5G(165, 0),
118 CHAN5G(184, 0), CHAN5G(188, 0),
119 CHAN5G(192, 0), CHAN5G(196, 0),
120 CHAN5G(200, 0), CHAN5G(204, 0),
121 CHAN5G(208, 0), CHAN5G(212, 0),
122 CHAN5G(216, 0),
123};
124
125static struct ieee80211_supported_band ath6kl_band_2ghz = {
126 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
127 .channels = ath6kl_2ghz_channels,
128 .n_bitrates = ath6kl_g_rates_size,
129 .bitrates = ath6kl_g_rates,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530130 .ht_cap.cap = ath6kl_g_htcap,
131 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300132};
133
134static struct ieee80211_supported_band ath6kl_band_5ghz = {
135 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
136 .channels = ath6kl_5ghz_a_channels,
137 .n_bitrates = ath6kl_a_rates_size,
138 .bitrates = ath6kl_a_rates,
Vasanthakumar Thiagarajanbed56e32012-04-09 19:03:57 +0530139 .ht_cap.cap = ath6kl_a_htcap,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530140 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300141};
142
Jouni Malinen837cb972011-10-11 17:31:57 +0300143#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
144
Kalle Valo10509f92011-12-13 14:52:07 +0200145/* returns true if scheduled scan was stopped */
146static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
147{
148 struct ath6kl *ar = vif->ar;
149
Thomas Pedersenb1f47e32012-08-15 16:51:24 -0700150 if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))
Kalle Valo10509f92011-12-13 14:52:07 +0200151 return false;
152
153 del_timer_sync(&vif->sched_scan_timer);
154
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +0530155 if (ar->state == ATH6KL_STATE_RECOVERY)
156 return true;
Kalle Valo10509f92011-12-13 14:52:07 +0200157
Thomas Pedersenb1f47e32012-08-15 16:51:24 -0700158 ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
Kalle Valo10509f92011-12-13 14:52:07 +0200159
160 return true;
161}
162
163static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
164{
165 struct ath6kl *ar = vif->ar;
166 bool stopped;
167
168 stopped = __ath6kl_cfg80211_sscan_stop(vif);
169
170 if (!stopped)
171 return;
172
173 cfg80211_sched_scan_stopped(ar->wiphy);
174}
175
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530176static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300177 enum nl80211_wpa_versions wpa_version)
178{
179 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
180
181 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530182 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300183 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530184 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300185 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530186 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300187 } else {
188 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
189 return -ENOTSUPP;
190 }
191
192 return 0;
193}
194
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530195static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300196 enum nl80211_auth_type auth_type)
197{
Kalle Valobdcd8172011-07-18 00:22:30 +0300198 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
199
200 switch (auth_type) {
201 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530202 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300203 break;
204 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530205 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300206 break;
207 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530208 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300209 break;
210
211 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530212 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300213 break;
214
215 default:
Masanari Iida3c325fb2012-01-31 23:32:55 +0900216 ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300217 return -ENOTSUPP;
218 }
219
220 return 0;
221}
222
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530223static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300224{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530225 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
226 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
227 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300228
229 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
230 __func__, cipher, ucast);
231
232 switch (cipher) {
233 case 0:
234 /* our own hack to use value 0 as no crypto used */
235 *ar_cipher = NONE_CRYPT;
236 *ar_cipher_len = 0;
237 break;
238 case WLAN_CIPHER_SUITE_WEP40:
239 *ar_cipher = WEP_CRYPT;
240 *ar_cipher_len = 5;
241 break;
242 case WLAN_CIPHER_SUITE_WEP104:
243 *ar_cipher = WEP_CRYPT;
244 *ar_cipher_len = 13;
245 break;
246 case WLAN_CIPHER_SUITE_TKIP:
247 *ar_cipher = TKIP_CRYPT;
248 *ar_cipher_len = 0;
249 break;
250 case WLAN_CIPHER_SUITE_CCMP:
251 *ar_cipher = AES_CRYPT;
252 *ar_cipher_len = 0;
253 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200254 case WLAN_CIPHER_SUITE_SMS4:
255 *ar_cipher = WAPI_CRYPT;
256 *ar_cipher_len = 0;
257 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300258 default:
259 ath6kl_err("cipher 0x%x not supported\n", cipher);
260 return -ENOTSUPP;
261 }
262
263 return 0;
264}
265
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530266static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300267{
268 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
269
270 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530271 if (vif->auth_mode == WPA_AUTH)
272 vif->auth_mode = WPA_PSK_AUTH;
273 else if (vif->auth_mode == WPA2_AUTH)
274 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300275 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530276 if (vif->auth_mode == WPA_AUTH)
277 vif->auth_mode = WPA_AUTH_CCKM;
278 else if (vif->auth_mode == WPA2_AUTH)
279 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300280 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530281 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300282 }
283}
284
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530285static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300286{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530287 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530288
Kalle Valobdcd8172011-07-18 00:22:30 +0300289 if (!test_bit(WMI_READY, &ar->flag)) {
290 ath6kl_err("wmi is not ready\n");
291 return false;
292 }
293
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530294 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300295 ath6kl_err("wlan disabled\n");
296 return false;
297 }
298
299 return true;
300}
301
Kevin Fang6981ffd2011-10-07 08:51:19 +0800302static bool ath6kl_is_wpa_ie(const u8 *pos)
303{
Arend van Spriel04b23122012-10-12 12:28:14 +0200304 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
Kevin Fang6981ffd2011-10-07 08:51:19 +0800305 pos[2] == 0x00 && pos[3] == 0x50 &&
306 pos[4] == 0xf2 && pos[5] == 0x01;
307}
308
309static bool ath6kl_is_rsn_ie(const u8 *pos)
310{
311 return pos[0] == WLAN_EID_RSN;
312}
313
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700314static bool ath6kl_is_wps_ie(const u8 *pos)
315{
316 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
317 pos[1] >= 4 &&
318 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
319 pos[5] == 0x04);
320}
321
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530322static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
323 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800324{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530325 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800326 const u8 *pos;
327 u8 *buf = NULL;
328 size_t len = 0;
329 int ret;
330
331 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700332 * Clear previously set flag
333 */
334
335 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
336
337 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800338 * Filter out RSN/WPA IE(s)
339 */
340
341 if (ies && ies_len) {
342 buf = kmalloc(ies_len, GFP_KERNEL);
343 if (buf == NULL)
344 return -ENOMEM;
345 pos = ies;
346
347 while (pos + 1 < ies + ies_len) {
348 if (pos + 2 + pos[1] > ies + ies_len)
349 break;
350 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
351 memcpy(buf + len, pos, 2 + pos[1]);
352 len += 2 + pos[1];
353 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700354
355 if (ath6kl_is_wps_ie(pos))
356 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
357
Kevin Fang6981ffd2011-10-07 08:51:19 +0800358 pos += 2 + pos[1];
359 }
360 }
361
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530362 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
363 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800364 kfree(buf);
365 return ret;
366}
367
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530368static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
369{
370 switch (type) {
371 case NL80211_IFTYPE_STATION:
Mohammed Shafi Shajakhan38142642012-08-24 19:53:28 +0530372 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530373 *nw_type = INFRA_NETWORK;
374 break;
375 case NL80211_IFTYPE_ADHOC:
376 *nw_type = ADHOC_NETWORK;
377 break;
378 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530379 case NL80211_IFTYPE_P2P_GO:
380 *nw_type = AP_NETWORK;
381 break;
382 default:
383 ath6kl_err("invalid interface type %u\n", type);
384 return -ENOTSUPP;
385 }
386
387 return 0;
388}
389
390static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
391 u8 *if_idx, u8 *nw_type)
392{
393 int i;
394
395 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
396 return false;
397
398 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
Kalle Valo96f1fad2012-03-07 20:03:57 +0200399 ar->num_vif))
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530400 return false;
401
402 if (type == NL80211_IFTYPE_STATION ||
403 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200404 for (i = 0; i < ar->vif_max; i++) {
Mohammed Shafi Shajakhan0db96de2013-02-22 20:19:55 +0530405 if ((ar->avail_idx_map) & BIT(i)) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530406 *if_idx = i;
407 return true;
408 }
409 }
410 }
411
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530412 if (type == NL80211_IFTYPE_P2P_CLIENT ||
413 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200414 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Mohammed Shafi Shajakhan0db96de2013-02-22 20:19:55 +0530415 if ((ar->avail_idx_map) & BIT(i)) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530416 *if_idx = i;
417 return true;
418 }
419 }
420 }
421
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530422 return false;
423}
424
Kalle Valo8c9bb052012-03-07 20:04:00 +0200425static bool ath6kl_is_tx_pending(struct ath6kl *ar)
426{
427 return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
428}
429
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +0530430static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif,
431 bool enable)
432{
433 int err;
434
435 if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
436 return;
437
438 if (vif->nw_type != INFRA_NETWORK)
439 return;
440
441 if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
442 vif->ar->fw_capabilities))
443 return;
444
445 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
446 enable ? "enable" : "disable");
447
448 err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
449 vif->fw_vif_idx, enable);
450 if (err)
451 ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
452 enable ? "enable" : "disable", err);
453}
Kalle Valo8c9bb052012-03-07 20:04:00 +0200454
Kalle Valobdcd8172011-07-18 00:22:30 +0300455static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
456 struct cfg80211_connect_params *sme)
457{
458 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530459 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300460 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800461 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Raja Manice0dc0c2012-02-20 19:08:08 +0530462 u16 interval;
Kalle Valobdcd8172011-07-18 00:22:30 +0300463
Kalle Valo10509f92011-12-13 14:52:07 +0200464 ath6kl_cfg80211_sscan_disable(vif);
465
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530466 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300467
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530468 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300469 return -EIO;
470
471 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
472 ath6kl_err("destroy in progress\n");
473 return -EBUSY;
474 }
475
476 if (test_bit(SKIP_SCAN, &ar->flag) &&
477 ((sme->channel && sme->channel->center_freq == 0) ||
478 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
479 ath6kl_err("SkipScan: channel or bssid invalid\n");
480 return -EINVAL;
481 }
482
483 if (down_interruptible(&ar->sem)) {
484 ath6kl_err("busy, couldn't get access\n");
485 return -ERESTARTSYS;
486 }
487
488 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
489 ath6kl_err("busy, destroy in progress\n");
490 up(&ar->sem);
491 return -EBUSY;
492 }
493
494 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
495 /*
496 * sleep until the command queue drains
497 */
498 wait_event_interruptible_timeout(ar->event_wq,
Kalle Valo8c9bb052012-03-07 20:04:00 +0200499 ath6kl_is_tx_pending(ar),
500 WMI_TIMEOUT);
Kalle Valobdcd8172011-07-18 00:22:30 +0300501 if (signal_pending(current)) {
502 ath6kl_err("cmd queue drain timeout\n");
503 up(&ar->sem);
504 return -EINTR;
505 }
506 }
507
Jouni Malinen6e786cb2011-12-15 14:16:00 +0200508 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
509 if (status) {
510 up(&ar->sem);
511 return status;
512 }
513
514 if (sme->ie == NULL || sme->ie_len == 0)
Raja Mani542c5192011-11-15 14:14:56 +0530515 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800516
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530517 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530518 vif->ssid_len == sme->ssid_len &&
519 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530520 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530521 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
522 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530523 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300524
525 up(&ar->sem);
526 if (status) {
527 ath6kl_err("wmi_reconnect_cmd failed\n");
528 return -EIO;
529 }
530 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530531 } else if (vif->ssid_len == sme->ssid_len &&
532 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530533 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300534 }
535
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530536 memset(vif->ssid, 0, sizeof(vif->ssid));
537 vif->ssid_len = sme->ssid_len;
538 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300539
540 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530541 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300542
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530543 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300544 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530545 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300546
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530547 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300548
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530549 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300550 if (status) {
551 up(&ar->sem);
552 return status;
553 }
554
555 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530556 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300557 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530558 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300559
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530560 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300561
562 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530563 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300564
565 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530566 (vif->auth_mode == NONE_AUTH) &&
567 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300568 struct ath6kl_key *key = NULL;
569
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530570 if (sme->key_idx > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300571 ath6kl_err("key index %d out of bounds\n",
572 sme->key_idx);
573 up(&ar->sem);
574 return -ENOENT;
575 }
576
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530577 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300578 key->key_len = sme->key_len;
579 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530580 key->cipher = vif->prwise_crypto;
581 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300582
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530583 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530584 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300585 GROUP_USAGE | TX_USAGE,
586 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200587 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300588 key->key, KEY_OP_INIT_VAL, NULL,
589 NO_SYNC_WMIFLAG);
590 }
591
592 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530593 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530594 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200595 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300596 ath6kl_err("couldn't set bss filtering\n");
597 up(&ar->sem);
598 return -EIO;
599 }
600 }
601
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530602 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300603
Thomas Pedersenc422d52d2012-05-15 00:09:23 -0700604 /* enable enhanced bmiss detection if applicable */
605 ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
606
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800607 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
608 nw_subtype = SUBTYPE_P2PCLIENT;
609
Kalle Valobdcd8172011-07-18 00:22:30 +0300610 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
611 "%s: connect called with authmode %d dot11 auth %d"
612 " PW crypto %d PW crypto len %d GRP crypto %d"
613 " GRP crypto len %d channel hint %u\n",
614 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530615 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
616 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530617 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300618
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530619 vif->reconnect_flag = 0;
Raja Manice0dc0c2012-02-20 19:08:08 +0530620
621 if (vif->nw_type == INFRA_NETWORK) {
Kalle Valob5283872012-03-12 13:23:23 +0200622 interval = max_t(u16, vif->listen_intvl_t,
623 ATH6KL_MAX_WOW_LISTEN_INTL);
Raja Manice0dc0c2012-02-20 19:08:08 +0530624 status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
625 interval,
626 0);
627 if (status) {
628 ath6kl_err("couldn't set listen intervel\n");
629 up(&ar->sem);
630 return status;
631 }
632 }
633
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530634 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530635 vif->dot11_auth_mode, vif->auth_mode,
636 vif->prwise_crypto,
637 vif->prwise_crypto_len,
638 vif->grp_crypto, vif->grp_crypto_len,
639 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530640 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800641 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300642
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530643 if (sme->bg_scan_period == 0) {
644 /* disable background scan if period is 0 */
Bala Shanmugamf5993592012-03-27 12:17:32 +0530645 sme->bg_scan_period = 0xffff;
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530646 } else if (sme->bg_scan_period == -1) {
647 /* configure default value if not specified */
Bala Shanmugamf5993592012-03-27 12:17:32 +0530648 sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530649 }
Bala Shanmugamf5993592012-03-27 12:17:32 +0530650
651 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
652 sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
653
Kalle Valobdcd8172011-07-18 00:22:30 +0300654 up(&ar->sem);
655
656 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530657 memset(vif->ssid, 0, sizeof(vif->ssid));
658 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300659 ath6kl_err("invalid request\n");
660 return -ENOENT;
661 } else if (status) {
662 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
663 return -EIO;
664 }
665
666 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Kalle Valoddc3d772012-03-07 20:03:58 +0200667 ((vif->auth_mode == WPA_PSK_AUTH) ||
668 (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530669 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300670 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
671 }
672
673 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530674 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300675
676 return 0;
677}
678
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530679static struct cfg80211_bss *
680ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
681 enum network_type nw_type,
682 const u8 *bssid,
683 struct ieee80211_channel *chan,
684 const u8 *beacon_ie,
685 size_t beacon_ie_len)
Jouni Malinen01cac472011-09-19 19:14:59 +0300686{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530687 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300688 struct cfg80211_bss *bss;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200689 u16 cap_val;
690 enum ieee80211_bss_type bss_type;
Jouni Malinen01cac472011-09-19 19:14:59 +0300691 u8 *ie;
692
Raja Mani4eab6f42011-11-09 17:02:23 +0530693 if (nw_type & ADHOC_NETWORK) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530694 cap_val = WLAN_CAPABILITY_IBSS;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200695 bss_type = IEEE80211_BSS_TYPE_IBSS;
Raja Mani4eab6f42011-11-09 17:02:23 +0530696 } else {
Raja Mani4eab6f42011-11-09 17:02:23 +0530697 cap_val = WLAN_CAPABILITY_ESS;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200698 bss_type = IEEE80211_BSS_TYPE_ESS;
Raja Mani4eab6f42011-11-09 17:02:23 +0530699 }
700
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530701 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530702 vif->ssid, vif->ssid_len,
Dedy Lansky6eb18132015-02-08 15:52:03 +0200703 bss_type, IEEE80211_PRIVACY_ANY);
Jouni Malinen01cac472011-09-19 19:14:59 +0300704 if (bss == NULL) {
705 /*
706 * Since cfg80211 may not yet know about the BSS,
707 * generate a partial entry until the first BSS info
708 * event becomes available.
709 *
710 * Prepend SSID element since it is not included in the Beacon
711 * IEs from the target.
712 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530713 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300714 if (ie == NULL)
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530715 return NULL;
Jouni Malinen01cac472011-09-19 19:14:59 +0300716 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530717 ie[1] = vif->ssid_len;
718 memcpy(ie + 2, vif->ssid, vif->ssid_len);
719 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530720 bss = cfg80211_inform_bss(ar->wiphy, chan,
Johannes Berg5bc8c1f2014-08-12 21:01:28 +0200721 CFG80211_BSS_FTYPE_UNKNOWN,
Raja Mani4eab6f42011-11-09 17:02:23 +0530722 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530723 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300724 0, GFP_KERNEL);
725 if (bss)
Kalle Valocdeb8602012-04-12 11:02:18 +0300726 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
727 "added bss %pM to cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300728 kfree(ie);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +0200729 } else {
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530730 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
Kalle Valoa5d8f9d2014-03-11 12:58:01 +0200731 }
Jouni Malinen01cac472011-09-19 19:14:59 +0300732
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530733 return bss;
Jouni Malinen01cac472011-09-19 19:14:59 +0300734}
735
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530736void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300737 u8 *bssid, u16 listen_intvl,
738 u16 beacon_intvl,
739 enum network_type nw_type,
740 u8 beacon_ie_len, u8 assoc_req_len,
741 u8 assoc_resp_len, u8 *assoc_info)
742{
Jouni Malinen01cac472011-09-19 19:14:59 +0300743 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530745 struct cfg80211_bss *bss;
Kalle Valobdcd8172011-07-18 00:22:30 +0300746
747 /* capinfo + listen interval */
748 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
749
750 /* capinfo + status code + associd */
751 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
752
753 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
754 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
755 assoc_resp_ie_offset;
756
757 assoc_req_len -= assoc_req_ie_offset;
758 assoc_resp_len -= assoc_resp_ie_offset;
759
Jouni Malinen32c10872011-09-19 19:15:07 +0300760 /*
761 * Store Beacon interval here; DTIM period will be available only once
762 * a Beacon frame from the AP is seen.
763 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530764 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530765 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300766
Kalle Valobdcd8172011-07-18 00:22:30 +0300767 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530768 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300769 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
770 "%s: ath6k not in ibss mode\n", __func__);
771 return;
772 }
773 }
774
775 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530776 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
777 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300778 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
779 "%s: ath6k not in station mode\n", __func__);
780 return;
781 }
782 }
783
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530784 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300785
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530786 bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
787 assoc_info, beacon_ie_len);
788 if (!bss) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530789 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300790 return;
791 }
792
Raja Mani4eab6f42011-11-09 17:02:23 +0530793 if (nw_type & ADHOC_NETWORK) {
794 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
795 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
Antonio Quartullife94f3a2014-01-29 17:53:43 +0100796 cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
Johannes Berg5b112d32013-02-01 01:49:58 +0100797 cfg80211_put_bss(ar->wiphy, bss);
Jouni Malinen01cac472011-09-19 19:14:59 +0300798 return;
799 }
800
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530801 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300802 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530803 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530804 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300805 assoc_req_ie, assoc_req_len,
806 assoc_resp_ie, assoc_resp_len,
807 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Johannes Berg5b112d32013-02-01 01:49:58 +0100808 cfg80211_put_bss(ar->wiphy, bss);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530809 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300810 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530811 cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
812 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300813 }
814}
815
816static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
817 struct net_device *dev, u16 reason_code)
818{
Kalle Valod6d5c062011-11-25 13:17:37 +0200819 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530820 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300821
822 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
823 reason_code);
824
Kalle Valo10509f92011-12-13 14:52:07 +0200825 ath6kl_cfg80211_sscan_disable(vif);
826
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530827 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300828 return -EIO;
829
830 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
831 ath6kl_err("busy, destroy in progress\n");
832 return -EBUSY;
833 }
834
835 if (down_interruptible(&ar->sem)) {
836 ath6kl_err("busy, couldn't get access\n");
837 return -ERESTARTSYS;
838 }
839
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530840 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530841 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530842 memset(vif->ssid, 0, sizeof(vif->ssid));
843 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300844
845 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530846 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300847
848 up(&ar->sem);
849
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530850 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530851
Kalle Valobdcd8172011-07-18 00:22:30 +0300852 return 0;
853}
854
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530855void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300856 u8 *bssid, u8 assoc_resp_len,
857 u8 *assoc_info, u16 proto_reason)
858{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530859 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530860
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530861 if (vif->scan_req) {
Avraham Stern1d762502016-07-05 17:10:13 +0300862 struct cfg80211_scan_info info = {
863 .aborted = true,
864 };
865
866 cfg80211_scan_done(vif->scan_req, &info);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530867 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300868 }
869
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530870 if (vif->nw_type & ADHOC_NETWORK) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +0100871 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
Kalle Valobdcd8172011-07-18 00:22:30 +0300872 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
873 "%s: ath6k not in ibss mode\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +0300874 return;
875 }
876
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530877 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530878 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
879 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300880 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
881 "%s: ath6k not in station mode\n", __func__);
882 return;
883 }
884 }
885
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530886 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300887
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530888 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530889 cfg80211_connect_result(vif->ndev,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200890 bssid, NULL, 0,
891 NULL, 0,
892 WLAN_STATUS_UNSPECIFIED_FAILURE,
893 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530894 } else if (vif->sme_state == SME_CONNECTED) {
Thomas Pedersen33a66642012-05-16 13:41:13 -0700895 cfg80211_disconnected(vif->ndev, proto_reason,
Johannes Berg80279fb2015-05-22 16:22:20 +0200896 NULL, 0, false, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300897 }
898
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530899 vif->sme_state = SME_DISCONNECTED;
Thomas Pedersen33a66642012-05-16 13:41:13 -0700900
901 /*
902 * Send a disconnect command to target when a disconnect event is
903 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
904 * request from host) to make the firmware stop trying to connect even
905 * after giving disconnect event. There will be one more disconnect
906 * event for this disconnect command with reason code DISCONNECT_CMD
907 * which won't be notified to cfg80211.
908 */
909 if (reason != DISCONNECT_CMD)
910 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300911}
912
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300913static int ath6kl_set_probed_ssids(struct ath6kl *ar,
914 struct ath6kl_vif *vif,
Naveen Singhdd45b752012-05-16 13:29:00 +0300915 struct cfg80211_ssid *ssids, int n_ssids,
916 struct cfg80211_match_set *match_set,
917 int n_match_ssid)
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300918{
Naveen Singhdd45b752012-05-16 13:29:00 +0300919 u8 i, j, index_to_add, ssid_found = false;
920 struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300921
Naveen Singhdd45b752012-05-16 13:29:00 +0300922 memset(ssid_list, 0, sizeof(ssid_list));
923
924 if (n_ssids > MAX_PROBED_SSIDS ||
925 n_match_ssid > MAX_PROBED_SSIDS)
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300926 return -EINVAL;
927
928 for (i = 0; i < n_ssids; i++) {
Naveen Singhdd45b752012-05-16 13:29:00 +0300929 memcpy(ssid_list[i].ssid.ssid,
930 ssids[i].ssid,
931 ssids[i].ssid_len);
932 ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
933
934 if (ssids[i].ssid_len)
935 ssid_list[i].flag = SPECIFIC_SSID_FLAG;
936 else
937 ssid_list[i].flag = ANY_SSID_FLAG;
938
939 if (n_match_ssid == 0)
940 ssid_list[i].flag |= MATCH_SSID_FLAG;
941 }
942
943 index_to_add = i;
944
945 for (i = 0; i < n_match_ssid; i++) {
946 ssid_found = false;
947
948 for (j = 0; j < n_ssids; j++) {
949 if ((match_set[i].ssid.ssid_len ==
950 ssid_list[j].ssid.ssid_len) &&
951 (!memcmp(ssid_list[j].ssid.ssid,
952 match_set[i].ssid.ssid,
953 match_set[i].ssid.ssid_len))) {
954 ssid_list[j].flag |= MATCH_SSID_FLAG;
955 ssid_found = true;
956 break;
957 }
958 }
959
960 if (ssid_found)
961 continue;
962
963 if (index_to_add >= MAX_PROBED_SSIDS)
964 continue;
965
966 ssid_list[index_to_add].ssid.ssid_len =
967 match_set[i].ssid.ssid_len;
968 memcpy(ssid_list[index_to_add].ssid.ssid,
969 match_set[i].ssid.ssid,
970 match_set[i].ssid.ssid_len);
971 ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
972 index_to_add++;
973 }
974
975 for (i = 0; i < index_to_add; i++) {
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300976 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
Naveen Singhdd45b752012-05-16 13:29:00 +0300977 ssid_list[i].flag,
978 ssid_list[i].ssid.ssid_len,
979 ssid_list[i].ssid.ssid);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300980 }
981
982 /* Make sure no old entries are left behind */
Naveen Singhdd45b752012-05-16 13:29:00 +0300983 for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300984 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
985 DISABLE_SSID_FLAG, 0, NULL);
986 }
987
988 return 0;
989}
990
Johannes Bergfd014282012-06-18 19:17:03 +0200991static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
Kalle Valobdcd8172011-07-18 00:22:30 +0300992 struct cfg80211_scan_request *request)
993{
Johannes Bergfd014282012-06-18 19:17:03 +0200994 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev);
995 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300996 s8 n_channels = 0;
997 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300998 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530999 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001000
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301001 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001002 return -EIO;
1003
Kalle Valo10509f92011-12-13 14:52:07 +02001004 ath6kl_cfg80211_sscan_disable(vif);
1005
Kalle Valobdcd8172011-07-18 00:22:30 +03001006 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301007 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan954e6ce2012-04-25 12:39:06 +05301008 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
1009 ALL_BSS_FILTER, 0);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +03001010 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001011 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +03001012 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03001013 }
1014 }
1015
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03001016 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
Naveen Singhdd45b752012-05-16 13:29:00 +03001017 request->n_ssids, NULL, 0);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03001018 if (ret < 0)
1019 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03001020
Aarthi Thiruvengadam080eec42012-02-28 09:17:04 -08001021 /* this also clears IE in fw if it's not set */
1022 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1023 WMI_FRAME_PROBE_REQ,
1024 request->ie, request->ie_len);
1025 if (ret) {
Joe Perchesf1ff32e2012-05-30 01:58:39 -07001026 ath6kl_err("failed to set Probe Request appie for scan\n");
Aarthi Thiruvengadam080eec42012-02-28 09:17:04 -08001027 return ret;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001028 }
1029
Jouni Malinen11869be2011-09-02 20:07:06 +03001030 /*
1031 * Scan only the requested channels if the request specifies a set of
1032 * channels. If the list is longer than the target supports, do not
1033 * configure the list and instead, scan all available channels.
1034 */
1035 if (request->n_channels > 0 &&
1036 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +03001037 u8 i;
1038
Jouni Malinen11869be2011-09-02 20:07:06 +03001039 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +03001040
1041 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
1042 if (channels == NULL) {
Kalle Valocdeb8602012-04-12 11:02:18 +03001043 ath6kl_warn("failed to set scan channels, scan all channels");
Edward Lu1276c9e2011-08-30 21:58:00 +03001044 n_channels = 0;
1045 }
1046
1047 for (i = 0; i < n_channels; i++)
1048 channels[i] = request->channels[i]->center_freq;
1049 }
1050
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301051 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +05301052 force_fg_scan = 1;
1053
Raja Mani5b35dff2012-03-28 18:50:35 +05301054 vif->scan_req = request;
1055
Kalle Valo11f0bfc2012-07-19 16:00:48 +03001056 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
1057 WMI_LONG_SCAN, force_fg_scan,
1058 false, 0,
1059 ATH6KL_FG_SCAN_INTERVAL,
1060 n_channels, channels,
1061 request->no_cck,
1062 request->rates);
Raja Mani5b35dff2012-03-28 18:50:35 +05301063 if (ret) {
Kalle Valo11f0bfc2012-07-19 16:00:48 +03001064 ath6kl_err("failed to start scan: %d\n", ret);
Raja Mani5b35dff2012-03-28 18:50:35 +05301065 vif->scan_req = NULL;
1066 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001067
Edward Lu1276c9e2011-08-30 21:58:00 +03001068 kfree(channels);
1069
Kalle Valobdcd8172011-07-18 00:22:30 +03001070 return ret;
1071}
1072
Kalle Valo1c17d312011-11-01 08:43:56 +02001073void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +03001074{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301075 struct ath6kl *ar = vif->ar;
Avraham Stern1d762502016-07-05 17:10:13 +03001076 struct cfg80211_scan_info info = {
1077 .aborted = aborted,
1078 };
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001079 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +03001080
Kalle Valo1c17d312011-11-01 08:43:56 +02001081 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
1082 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +03001083
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301084 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001085 return;
Kalle Valobdcd8172011-07-18 00:22:30 +03001086
Kalle Valo1c17d312011-11-01 08:43:56 +02001087 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001088 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001089
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301090 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
1091 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301092 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
1093 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001094 0, NULL);
1095 }
1096 }
1097
1098out:
Avraham Stern1d762502016-07-05 17:10:13 +03001099 cfg80211_scan_done(vif->scan_req, &info);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301100 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001101}
1102
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001103void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
1104 enum wmi_phy_mode mode)
1105{
Johannes Berg683b6d32012-11-08 21:25:48 +01001106 struct cfg80211_chan_def chandef;
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001107
1108 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1109 "channel switch notify nw_type %d freq %d mode %d\n",
1110 vif->nw_type, freq, mode);
1111
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001112 cfg80211_chandef_create(&chandef,
1113 ieee80211_get_channel(vif->ar->wiphy, freq),
Pierre Le Magourouf3651ba2016-07-18 23:22:19 +03001114 (mode == WMI_11G_HT20 &&
1115 ath6kl_band_2ghz.ht_cap.ht_supported) ?
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001116 NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001117
Simon Wunderliche487eae2013-11-21 18:19:51 +01001118 mutex_lock(&vif->wdev.mtx);
Johannes Berg683b6d32012-11-08 21:25:48 +01001119 cfg80211_ch_switch_notify(vif->ndev, &chandef);
Simon Wunderliche487eae2013-11-21 18:19:51 +01001120 mutex_unlock(&vif->wdev.mtx);
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001121}
1122
Kalle Valobdcd8172011-07-18 00:22:30 +03001123static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1124 u8 key_index, bool pairwise,
1125 const u8 *mac_addr,
1126 struct key_params *params)
1127{
Kalle Valod6d5c062011-11-25 13:17:37 +02001128 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301129 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001130 struct ath6kl_key *key = NULL;
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301131 int seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +03001132 u8 key_usage;
1133 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001134
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301135 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001136 return -EIO;
1137
Jouni Malinen837cb972011-10-11 17:31:57 +03001138 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
1139 if (params->key_len != WMI_KRK_LEN)
1140 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301141 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
1142 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +03001143 }
1144
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301145 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001146 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1147 "%s: key index %d out of bounds\n", __func__,
1148 key_index);
1149 return -ENOENT;
1150 }
1151
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301152 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001153 memset(key, 0, sizeof(struct ath6kl_key));
1154
1155 if (pairwise)
1156 key_usage = PAIRWISE_USAGE;
1157 else
1158 key_usage = GROUP_USAGE;
1159
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301160 seq_len = params->seq_len;
1161 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1162 seq_len > ATH6KL_KEY_SEQ_LEN) {
1163 /* Only first half of the WPI PN is configured */
1164 seq_len = ATH6KL_KEY_SEQ_LEN;
Kalle Valobdcd8172011-07-18 00:22:30 +03001165 }
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301166 if (params->key_len > WLAN_MAX_KEY_LEN ||
1167 seq_len > sizeof(key->seq))
1168 return -EINVAL;
1169
1170 key->key_len = params->key_len;
1171 memcpy(key->key, params->key, key->key_len);
1172 key->seq_len = seq_len;
1173 memcpy(key->seq, params->seq, key->seq_len);
1174 key->cipher = params->cipher;
Kalle Valobdcd8172011-07-18 00:22:30 +03001175
1176 switch (key->cipher) {
1177 case WLAN_CIPHER_SUITE_WEP40:
1178 case WLAN_CIPHER_SUITE_WEP104:
1179 key_type = WEP_CRYPT;
1180 break;
1181
1182 case WLAN_CIPHER_SUITE_TKIP:
1183 key_type = TKIP_CRYPT;
1184 break;
1185
1186 case WLAN_CIPHER_SUITE_CCMP:
1187 key_type = AES_CRYPT;
1188 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001189 case WLAN_CIPHER_SUITE_SMS4:
1190 key_type = WAPI_CRYPT;
1191 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001192
1193 default:
1194 return -ENOTSUPP;
1195 }
1196
Kalle Valoddc3d772012-03-07 20:03:58 +02001197 if (((vif->auth_mode == WPA_PSK_AUTH) ||
1198 (vif->auth_mode == WPA2_PSK_AUTH)) &&
1199 (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301200 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001201
1202 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1203 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1204 __func__, key_index, key->key_len, key_type,
1205 key_usage, key->seq_len);
1206
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301207 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001208 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
Vasanthakumar Thiagarajancc4d6232012-02-14 20:33:00 +05301209 key_type == WAPI_CRYPT)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001210 ar->ap_mode_bkey.valid = true;
1211 ar->ap_mode_bkey.key_index = key_index;
1212 ar->ap_mode_bkey.key_type = key_type;
1213 ar->ap_mode_bkey.key_len = key->key_len;
1214 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301215 if (!test_bit(CONNECTED, &vif->flags)) {
Kalle Valocdeb8602012-04-12 11:02:18 +03001216 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1217 "Delay initial group key configuration until AP mode has been started\n");
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001218 /*
1219 * The key will be set in ath6kl_connect_ap_mode() once
1220 * the connected event is received from the target.
1221 */
1222 return 0;
1223 }
1224 }
1225
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301226 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301227 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001228 /*
1229 * Store the key locally so that it can be re-configured after
1230 * the AP mode has properly started
1231 * (ath6kl_install_statioc_wep_keys).
1232 */
Kalle Valocdeb8602012-04-12 11:02:18 +03001233 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1234 "Delay WEP key configuration until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301235 vif->wep_key_list[key_index].key_len = key->key_len;
1236 memcpy(vif->wep_key_list[key_index].key, key->key,
1237 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001238 return 0;
1239 }
1240
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301241 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001242 key_type, key_usage, key->key_len,
1243 key->seq, key->seq_len, key->key,
1244 KEY_OP_INIT_VAL,
1245 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001246}
1247
1248static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1249 u8 key_index, bool pairwise,
1250 const u8 *mac_addr)
1251{
Kalle Valod6d5c062011-11-25 13:17:37 +02001252 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301253 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001254
1255 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1256
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301257 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001258 return -EIO;
1259
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301260 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001261 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1262 "%s: key index %d out of bounds\n", __func__,
1263 key_index);
1264 return -ENOENT;
1265 }
1266
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301267 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001268 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1269 "%s: index %d is empty\n", __func__, key_index);
1270 return 0;
1271 }
1272
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301273 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001274
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301275 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001276}
1277
1278static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1279 u8 key_index, bool pairwise,
1280 const u8 *mac_addr, void *cookie,
1281 void (*callback) (void *cookie,
1282 struct key_params *))
1283{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301284 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001285 struct ath6kl_key *key = NULL;
1286 struct key_params params;
1287
1288 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1289
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301290 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001291 return -EIO;
1292
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301293 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001294 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1295 "%s: key index %d out of bounds\n", __func__,
1296 key_index);
1297 return -ENOENT;
1298 }
1299
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301300 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001301 memset(&params, 0, sizeof(params));
1302 params.cipher = key->cipher;
1303 params.key_len = key->key_len;
1304 params.seq_len = key->seq_len;
1305 params.seq = key->seq;
1306 params.key = key->key;
1307
1308 callback(cookie, &params);
1309
1310 return key->key_len ? 0 : -ENOENT;
1311}
1312
1313static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1314 struct net_device *ndev,
1315 u8 key_index, bool unicast,
1316 bool multicast)
1317{
Kalle Valod6d5c062011-11-25 13:17:37 +02001318 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301319 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001320 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001321 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001322 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001323
1324 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1325
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301326 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001327 return -EIO;
1328
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301329 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001330 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1331 "%s: key index %d out of bounds\n",
1332 __func__, key_index);
1333 return -ENOENT;
1334 }
1335
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301336 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001337 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1338 __func__, key_index);
1339 return -EINVAL;
1340 }
1341
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301342 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301343 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001344 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301345 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001346 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001347 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301348 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001349 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301350 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001351
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301352 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001353 return 0; /* Delay until AP mode has been started */
1354
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001355 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1356 vif->def_txkey_index,
1357 key_type, key_usage,
1358 key->key_len, key->seq, key->seq_len,
1359 key->key,
1360 KEY_OP_INIT_VAL, NULL,
1361 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001362}
1363
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301364void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001365 bool ismcast)
1366{
1367 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1368 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1369
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301370 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001371 (ismcast ? NL80211_KEYTYPE_GROUP :
1372 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1373 GFP_KERNEL);
1374}
1375
1376static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1377{
1378 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301379 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001380 int ret;
1381
1382 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1383 changed);
1384
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301385 vif = ath6kl_vif_first(ar);
1386 if (!vif)
1387 return -EIO;
1388
1389 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001390 return -EIO;
1391
1392 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1393 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1394 if (ret != 0) {
1395 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1396 return -EIO;
1397 }
1398 }
1399
1400 return 0;
1401}
1402
Kalle Valobdcd8172011-07-18 00:22:30 +03001403static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
Johannes Bergc8442112012-10-24 10:17:18 +02001404 struct wireless_dev *wdev,
Kalle Valobdcd8172011-07-18 00:22:30 +03001405 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001406 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001407{
1408 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301409 struct ath6kl_vif *vif;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001410 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001411
1412 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1413 type, dbm);
1414
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301415 vif = ath6kl_vif_first(ar);
1416 if (!vif)
1417 return -EIO;
1418
1419 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001420 return -EIO;
1421
1422 switch (type) {
1423 case NL80211_TX_POWER_AUTOMATIC:
1424 return 0;
1425 case NL80211_TX_POWER_LIMITED:
Kalle Valod0d670a2012-03-07 20:03:58 +02001426 ar->tx_pwr = dbm;
Kalle Valobdcd8172011-07-18 00:22:30 +03001427 break;
1428 default:
1429 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1430 __func__, type);
1431 return -EOPNOTSUPP;
1432 }
1433
Kalle Valod0d670a2012-03-07 20:03:58 +02001434 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001435
1436 return 0;
1437}
1438
Johannes Bergc8442112012-10-24 10:17:18 +02001439static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
1440 struct wireless_dev *wdev,
1441 int *dbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001442{
1443 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301444 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001445
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301446 vif = ath6kl_vif_first(ar);
1447 if (!vif)
1448 return -EIO;
1449
1450 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001451 return -EIO;
1452
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301453 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001454 ar->tx_pwr = 0;
1455
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301456 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001457 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1458 return -EIO;
1459 }
1460
1461 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1462 5 * HZ);
1463
1464 if (signal_pending(current)) {
1465 ath6kl_err("target did not respond\n");
1466 return -EINTR;
1467 }
1468 }
1469
1470 *dbm = ar->tx_pwr;
1471 return 0;
1472}
1473
1474static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1475 struct net_device *dev,
1476 bool pmgmt, int timeout)
1477{
1478 struct ath6kl *ar = ath6kl_priv(dev);
1479 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301480 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001481
1482 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1483 __func__, pmgmt, timeout);
1484
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301485 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001486 return -EIO;
1487
1488 if (pmgmt) {
Mohammed Shafi Shajakhanf0ed67e2012-10-12 17:40:41 +05301489 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +03001490 mode.pwr_mode = REC_POWER;
1491 } else {
Mohammed Shafi Shajakhanf0ed67e2012-10-12 17:40:41 +05301492 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +03001493 mode.pwr_mode = MAX_PERF_POWER;
1494 }
1495
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301496 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +02001497 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001498 ath6kl_err("wmi_powermode_cmd failed\n");
1499 return -EIO;
1500 }
1501
1502 return 0;
1503}
1504
Johannes Berg84efbb82012-06-16 00:00:26 +02001505static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
Johannes Berg552bff02012-09-19 09:26:06 +02001506 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +01001507 unsigned char name_assign_type,
Johannes Berg84efbb82012-06-16 00:00:26 +02001508 enum nl80211_iftype type,
1509 u32 *flags,
1510 struct vif_params *params)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301511{
1512 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg84efbb82012-06-16 00:00:26 +02001513 struct wireless_dev *wdev;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301514 u8 if_idx, nw_type;
1515
Kalle Valo71f96ee2011-11-14 19:31:30 +02001516 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301517 ath6kl_err("Reached maximum number of supported vif\n");
1518 return ERR_PTR(-EINVAL);
1519 }
1520
1521 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1522 ath6kl_err("Not a supported interface type\n");
1523 return ERR_PTR(-EINVAL);
1524 }
1525
Tom Gundersen6bab2e192015-03-18 11:13:39 +01001526 wdev = ath6kl_interface_add(ar, name, name_assign_type, type, if_idx, nw_type);
Johannes Berg84efbb82012-06-16 00:00:26 +02001527 if (!wdev)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301528 return ERR_PTR(-ENOMEM);
1529
1530 ar->num_vif++;
1531
Johannes Berg84efbb82012-06-16 00:00:26 +02001532 return wdev;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301533}
1534
1535static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
Johannes Berg84efbb82012-06-16 00:00:26 +02001536 struct wireless_dev *wdev)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301537{
1538 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg84efbb82012-06-16 00:00:26 +02001539 struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301540
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301541 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301542 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301543 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301544
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05301545 ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301546
Mohammed Shafi Shajakhanbc52aab2013-02-22 20:20:09 +05301547 rtnl_lock();
Kalle Valoc25889e2012-01-17 20:08:27 +02001548 ath6kl_cfg80211_vif_cleanup(vif);
Mohammed Shafi Shajakhanbc52aab2013-02-22 20:20:09 +05301549 rtnl_unlock();
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301550
1551 return 0;
1552}
1553
Kalle Valobdcd8172011-07-18 00:22:30 +03001554static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1555 struct net_device *ndev,
1556 enum nl80211_iftype type, u32 *flags,
1557 struct vif_params *params)
1558{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301559 struct ath6kl_vif *vif = netdev_priv(ndev);
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301560 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +03001561
1562 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1563
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301564 /*
1565 * Don't bring up p2p on an interface which is not initialized
1566 * for p2p operation where fw does not have capability to switch
1567 * dynamically between non-p2p and p2p type interface.
1568 */
1569 if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
1570 vif->ar->fw_capabilities) &&
1571 (type == NL80211_IFTYPE_P2P_CLIENT ||
1572 type == NL80211_IFTYPE_P2P_GO)) {
1573 if (vif->ar->vif_max == 1) {
1574 if (vif->fw_vif_idx != 0)
1575 return -EINVAL;
1576 else
1577 goto set_iface_type;
1578 }
1579
1580 for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
1581 if (i == vif->fw_vif_idx)
1582 break;
1583 }
1584
1585 if (i == vif->ar->vif_max) {
1586 ath6kl_err("Invalid interface to bring up P2P\n");
1587 return -EINVAL;
1588 }
1589 }
1590
Thomas Pedersenc422d52d2012-05-15 00:09:23 -07001591 /* need to clean up enhanced bmiss detection fw state */
1592 ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
1593
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301594set_iface_type:
Kalle Valobdcd8172011-07-18 00:22:30 +03001595 switch (type) {
1596 case NL80211_IFTYPE_STATION:
Mohammed Shafi Shajakhan8aa659d2012-11-16 18:22:57 +05301597 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301598 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001599 break;
1600 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301601 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001602 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001603 case NL80211_IFTYPE_AP:
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001604 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301605 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001606 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001607 default:
1608 ath6kl_err("invalid interface type %u\n", type);
1609 return -EOPNOTSUPP;
1610 }
1611
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301612 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001613
1614 return 0;
1615}
1616
1617static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1618 struct net_device *dev,
1619 struct cfg80211_ibss_params *ibss_param)
1620{
1621 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301622 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001623 int status;
1624
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301625 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001626 return -EIO;
1627
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301628 vif->ssid_len = ibss_param->ssid_len;
1629 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001630
Johannes Berg683b6d32012-11-08 21:25:48 +01001631 if (ibss_param->chandef.chan)
1632 vif->ch_hint = ibss_param->chandef.chan->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001633
1634 if (ibss_param->channel_fixed) {
1635 /*
1636 * TODO: channel_fixed: The channel should be fixed, do not
1637 * search for IBSSs to join on other channels. Target
1638 * firmware does not support this feature, needs to be
1639 * updated.
1640 */
1641 return -EOPNOTSUPP;
1642 }
1643
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301644 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001645 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301646 memcpy(vif->req_bssid, ibss_param->bssid,
1647 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001648
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301649 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001650
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301651 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001652 if (status)
1653 return status;
1654
1655 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301656 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1657 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001658 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301659 ath6kl_set_cipher(vif, 0, true);
1660 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001661 }
1662
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301663 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001664
1665 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1666 "%s: connect called with authmode %d dot11 auth %d"
1667 " PW crypto %d PW crypto len %d GRP crypto %d"
1668 " GRP crypto len %d channel hint %u\n",
1669 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301670 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1671 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301672 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001673
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301674 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301675 vif->dot11_auth_mode, vif->auth_mode,
1676 vif->prwise_crypto,
1677 vif->prwise_crypto_len,
1678 vif->grp_crypto, vif->grp_crypto_len,
1679 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301680 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001681 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301682 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001683
1684 return 0;
1685}
1686
1687static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1688 struct net_device *dev)
1689{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301690 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001691
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301692 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001693 return -EIO;
1694
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301695 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301696 memset(vif->ssid, 0, sizeof(vif->ssid));
1697 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001698
1699 return 0;
1700}
1701
1702static const u32 cipher_suites[] = {
1703 WLAN_CIPHER_SUITE_WEP40,
1704 WLAN_CIPHER_SUITE_WEP104,
1705 WLAN_CIPHER_SUITE_TKIP,
1706 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001707 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001708 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001709};
1710
1711static bool is_rate_legacy(s32 rate)
1712{
1713 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1714 6000, 9000, 12000, 18000, 24000,
1715 36000, 48000, 54000
1716 };
1717 u8 i;
1718
1719 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1720 if (rate == legacy[i])
1721 return true;
1722
1723 return false;
1724}
1725
1726static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1727{
1728 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1729 52000, 58500, 65000, 72200
1730 };
1731 u8 i;
1732
1733 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1734 if (rate == ht20[i]) {
1735 if (i == ARRAY_SIZE(ht20) - 1)
1736 /* last rate uses sgi */
1737 *sgi = true;
1738 else
1739 *sgi = false;
1740
1741 *mcs = i;
1742 return true;
1743 }
1744 }
1745 return false;
1746}
1747
1748static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1749{
1750 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1751 81000, 108000, 121500, 135000,
1752 150000
1753 };
1754 u8 i;
1755
1756 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1757 if (rate == ht40[i]) {
1758 if (i == ARRAY_SIZE(ht40) - 1)
1759 /* last rate uses sgi */
1760 *sgi = true;
1761 else
1762 *sgi = false;
1763
1764 *mcs = i;
1765 return true;
1766 }
1767 }
1768
1769 return false;
1770}
1771
1772static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02001773 const u8 *mac, struct station_info *sinfo)
Kalle Valobdcd8172011-07-18 00:22:30 +03001774{
1775 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301776 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001777 long left;
1778 bool sgi;
1779 s32 rate;
1780 int ret;
1781 u8 mcs;
1782
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301783 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001784 return -ENOENT;
1785
1786 if (down_interruptible(&ar->sem))
1787 return -EBUSY;
1788
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301789 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001790
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301791 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001792
1793 if (ret != 0) {
1794 up(&ar->sem);
1795 return -EIO;
1796 }
1797
1798 left = wait_event_interruptible_timeout(ar->event_wq,
1799 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301800 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001801 WMI_TIMEOUT);
1802
1803 up(&ar->sem);
1804
1805 if (left == 0)
1806 return -ETIMEDOUT;
1807 else if (left < 0)
1808 return left;
1809
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301810 if (vif->target_stats.rx_byte) {
1811 sinfo->rx_bytes = vif->target_stats.rx_byte;
Johannes Berg319090b2014-11-17 14:08:11 +01001812 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301813 sinfo->rx_packets = vif->target_stats.rx_pkt;
Johannes Berg319090b2014-11-17 14:08:11 +01001814 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
Kalle Valobdcd8172011-07-18 00:22:30 +03001815 }
1816
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301817 if (vif->target_stats.tx_byte) {
1818 sinfo->tx_bytes = vif->target_stats.tx_byte;
Johannes Berg319090b2014-11-17 14:08:11 +01001819 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301820 sinfo->tx_packets = vif->target_stats.tx_pkt;
Johannes Berg319090b2014-11-17 14:08:11 +01001821 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
Kalle Valobdcd8172011-07-18 00:22:30 +03001822 }
1823
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301824 sinfo->signal = vif->target_stats.cs_rssi;
Johannes Berg319090b2014-11-17 14:08:11 +01001825 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
Kalle Valobdcd8172011-07-18 00:22:30 +03001826
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301827 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001828
1829 if (is_rate_legacy(rate)) {
1830 sinfo->txrate.legacy = rate / 100;
1831 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1832 if (sgi) {
1833 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1834 sinfo->txrate.mcs = mcs - 1;
1835 } else {
1836 sinfo->txrate.mcs = mcs;
1837 }
1838
1839 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Johannes Bergb51f3be2015-01-15 16:14:02 +01001840 sinfo->txrate.bw = RATE_INFO_BW_20;
Kalle Valobdcd8172011-07-18 00:22:30 +03001841 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1842 if (sgi) {
1843 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1844 sinfo->txrate.mcs = mcs - 1;
1845 } else {
1846 sinfo->txrate.mcs = mcs;
1847 }
1848
Johannes Bergb51f3be2015-01-15 16:14:02 +01001849 sinfo->txrate.bw = RATE_INFO_BW_40;
Kalle Valobdcd8172011-07-18 00:22:30 +03001850 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1851 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001852 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1853 "invalid rate from stats: %d\n", rate);
1854 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001855 return 0;
1856 }
1857
Johannes Berg319090b2014-11-17 14:08:11 +01001858 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001859
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301860 if (test_bit(CONNECTED, &vif->flags) &&
1861 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301862 vif->nw_type == INFRA_NETWORK) {
Johannes Berg319090b2014-11-17 14:08:11 +01001863 sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
Jouni Malinen32c10872011-09-19 19:15:07 +03001864 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301865 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1866 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001867 }
1868
Kalle Valobdcd8172011-07-18 00:22:30 +03001869 return 0;
1870}
1871
1872static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1873 struct cfg80211_pmksa *pmksa)
1874{
1875 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301876 struct ath6kl_vif *vif = netdev_priv(netdev);
1877
1878 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001879 pmksa->pmkid, true);
1880}
1881
1882static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1883 struct cfg80211_pmksa *pmksa)
1884{
1885 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301886 struct ath6kl_vif *vif = netdev_priv(netdev);
1887
1888 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001889 pmksa->pmkid, false);
1890}
1891
1892static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1893{
1894 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301895 struct ath6kl_vif *vif = netdev_priv(netdev);
1896
1897 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301898 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1899 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001900 return 0;
1901}
1902
Raja Manid91e8ee2012-01-30 17:13:10 +05301903static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
1904 struct cfg80211_wowlan *wow, u32 *filter)
Raja Mani6cb3c712011-11-07 22:52:45 +02001905{
Raja Manid91e8ee2012-01-30 17:13:10 +05301906 int ret, pos;
Thomas Pedersen2c07cf42012-08-20 14:26:50 -07001907 u8 mask[WOW_PATTERN_SIZE];
Raja Mani6cb3c712011-11-07 22:52:45 +02001908 u16 i;
Raja Mani6cb3c712011-11-07 22:52:45 +02001909
Raja Manid91e8ee2012-01-30 17:13:10 +05301910 /* Configure the patterns that we received from the user. */
Raja Mani6cb3c712011-11-07 22:52:45 +02001911 for (i = 0; i < wow->n_patterns; i++) {
Raja Mani6cb3c712011-11-07 22:52:45 +02001912 /*
1913 * Convert given nl80211 specific mask value to equivalent
1914 * driver specific mask value and send it to the chip along
1915 * with patterns. For example, If the mask value defined in
1916 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1917 * then equivalent driver specific mask value is
1918 * "0xFF 0x00 0xFF 0x00".
1919 */
1920 memset(&mask, 0, sizeof(mask));
1921 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1922 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1923 mask[pos] = 0xFF;
1924 }
1925 /*
1926 * Note: Pattern's offset is not passed as part of wowlan
1927 * parameter from CFG layer. So it's always passed as ZERO
1928 * to the firmware. It means, given WOW patterns are always
1929 * matched from the first byte of received pkt in the firmware.
1930 */
1931 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
Raja Manid91e8ee2012-01-30 17:13:10 +05301932 vif->fw_vif_idx, WOW_LIST_ID,
1933 wow->patterns[i].pattern_len,
1934 0 /* pattern offset */,
1935 wow->patterns[i].pattern, mask);
Raja Mani6cb3c712011-11-07 22:52:45 +02001936 if (ret)
1937 return ret;
1938 }
1939
Raja Manid91e8ee2012-01-30 17:13:10 +05301940 if (wow->disconnect)
1941 *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1942
1943 if (wow->magic_pkt)
1944 *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1945
1946 if (wow->gtk_rekey_failure)
1947 *filter |= WOW_FILTER_OPTION_GTK_ERROR;
1948
1949 if (wow->eap_identity_req)
1950 *filter |= WOW_FILTER_OPTION_EAP_REQ;
1951
1952 if (wow->four_way_handshake)
1953 *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1954
1955 return 0;
1956}
1957
1958static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif)
1959{
1960 static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00,
1961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1962 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1963 0x00, 0x08 };
1964 static const u8 unicst_mask[] = { 0x01, 0x00, 0x00,
1965 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1966 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1967 0x00, 0x7f };
1968 u8 unicst_offset = 0;
1969 static const u8 arp_pattern[] = { 0x08, 0x06 };
1970 static const u8 arp_mask[] = { 0xff, 0xff };
1971 u8 arp_offset = 20;
1972 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
1973 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
1974 u8 discvr_offset = 38;
1975 static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff,
1976 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
1978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1980 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
1981 static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff,
1982 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
1984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1986 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ };
1987 u8 dhcp_offset = 0;
1988 int ret;
1989
1990 /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
1991 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1992 vif->fw_vif_idx, WOW_LIST_ID,
1993 sizeof(unicst_pattern), unicst_offset,
1994 unicst_pattern, unicst_mask);
1995 if (ret) {
1996 ath6kl_err("failed to add WOW unicast IP pattern\n");
1997 return ret;
1998 }
1999
2000 /* Setup all ARP pkt pattern */
2001 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2002 vif->fw_vif_idx, WOW_LIST_ID,
2003 sizeof(arp_pattern), arp_offset,
2004 arp_pattern, arp_mask);
2005 if (ret) {
2006 ath6kl_err("failed to add WOW ARP pattern\n");
2007 return ret;
2008 }
2009
2010 /*
2011 * Setup multicast pattern for mDNS 224.0.0.251,
2012 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
2013 */
2014 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2015 vif->fw_vif_idx, WOW_LIST_ID,
2016 sizeof(discvr_pattern), discvr_offset,
2017 discvr_pattern, discvr_mask);
2018 if (ret) {
2019 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
2020 return ret;
2021 }
2022
2023 /* Setup all DHCP broadcast pkt pattern */
2024 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2025 vif->fw_vif_idx, WOW_LIST_ID,
2026 sizeof(dhcp_pattern), dhcp_offset,
2027 dhcp_pattern, dhcp_mask);
2028 if (ret) {
2029 ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
2030 return ret;
2031 }
2032
2033 return 0;
2034}
2035
2036static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
2037{
2038 struct net_device *ndev = vif->ndev;
2039 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
2040 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
2041 u8 discvr_offset = 38;
2042 u8 mac_mask[ETH_ALEN];
2043 int ret;
2044
2045 /* Setup unicast pkt pattern */
Joe Perches93803b32015-03-02 19:54:49 -08002046 eth_broadcast_addr(mac_mask);
Raja Manid91e8ee2012-01-30 17:13:10 +05302047 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2048 vif->fw_vif_idx, WOW_LIST_ID,
2049 ETH_ALEN, 0, ndev->dev_addr,
2050 mac_mask);
2051 if (ret) {
2052 ath6kl_err("failed to add WOW unicast pattern\n");
2053 return ret;
2054 }
2055
2056 /*
2057 * Setup multicast pattern for mDNS 224.0.0.251,
2058 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
2059 */
2060 if ((ndev->flags & IFF_ALLMULTI) ||
2061 (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
2062 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2063 vif->fw_vif_idx, WOW_LIST_ID,
2064 sizeof(discvr_pattern), discvr_offset,
2065 discvr_pattern, discvr_mask);
2066 if (ret) {
Kalle Valocdeb8602012-04-12 11:02:18 +03002067 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
Raja Manid91e8ee2012-01-30 17:13:10 +05302068 return ret;
2069 }
2070 }
2071
2072 return 0;
2073}
2074
Raja Mani055bde42012-03-21 15:03:37 +05302075static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
2076{
2077 return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2078}
2079
2080static bool is_ctrl_ep_empty(struct ath6kl *ar)
2081{
2082 return !ar->tx_pending[ar->ctrl_ep];
2083}
2084
2085static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
2086{
2087 int ret, left;
2088
2089 clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2090
2091 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2092 ATH6KL_HOST_MODE_ASLEEP);
2093 if (ret)
2094 return ret;
2095
2096 left = wait_event_interruptible_timeout(ar->event_wq,
2097 is_hsleep_mode_procsed(vif),
2098 WMI_TIMEOUT);
2099 if (left == 0) {
2100 ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
2101 ret = -ETIMEDOUT;
2102 } else if (left < 0) {
2103 ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
2104 left);
2105 ret = left;
2106 }
2107
2108 if (ar->tx_pending[ar->ctrl_ep]) {
2109 left = wait_event_interruptible_timeout(ar->event_wq,
2110 is_ctrl_ep_empty(ar),
2111 WMI_TIMEOUT);
2112 if (left == 0) {
2113 ath6kl_warn("clear wmi ctrl data timeout\n");
2114 ret = -ETIMEDOUT;
2115 } else if (left < 0) {
2116 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
2117 ret = left;
2118 }
2119 }
2120
2121 return ret;
2122}
2123
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002124static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
2125 struct cfg80211_wowlan *wow, u32 *filter)
Raja Manid91e8ee2012-01-30 17:13:10 +05302126{
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002127 struct ath6kl *ar = vif->ar;
Raja Manid91e8ee2012-01-30 17:13:10 +05302128 struct in_device *in_dev;
2129 struct in_ifaddr *ifa;
Raja Mani055bde42012-03-21 15:03:37 +05302130 int ret;
Raja Manice0dc0c2012-02-20 19:08:08 +05302131 u16 i, bmiss_time;
Raja Manid91e8ee2012-01-30 17:13:10 +05302132 __be32 ips[MAX_IP_ADDRS];
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002133 u8 index = 0;
Raja Manid91e8ee2012-01-30 17:13:10 +05302134
Naveen Gangadharan6821d4f2012-05-11 14:19:09 -07002135 if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
2136 test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
2137 ar->fw_capabilities)) {
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002138 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
2139 vif->fw_vif_idx, false);
2140 if (ret)
2141 return ret;
2142 }
2143
Raja Manid91e8ee2012-01-30 17:13:10 +05302144 /* Clear existing WOW patterns */
2145 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
2146 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
2147 WOW_LIST_ID, i);
2148
2149 /*
2150 * Skip the default WOW pattern configuration
2151 * if the driver receives any WOW patterns from
2152 * the user.
2153 */
2154 if (wow)
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002155 ret = ath6kl_wow_usr(ar, vif, wow, filter);
Raja Manid91e8ee2012-01-30 17:13:10 +05302156 else if (vif->nw_type == AP_NETWORK)
2157 ret = ath6kl_wow_ap(ar, vif);
2158 else
2159 ret = ath6kl_wow_sta(ar, vif);
2160
2161 if (ret)
2162 return ret;
2163
Raja Mani390a8c82012-03-07 11:35:04 +05302164 netif_stop_queue(vif->ndev);
2165
Raja Manice0dc0c2012-02-20 19:08:08 +05302166 if (vif->nw_type != AP_NETWORK) {
2167 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2168 ATH6KL_MAX_WOW_LISTEN_INTL,
2169 0);
2170 if (ret)
2171 return ret;
2172
2173 /* Set listen interval x 15 times as bmiss time */
2174 bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
2175 if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
2176 bmiss_time = ATH6KL_MAX_BMISS_TIME;
2177
2178 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2179 bmiss_time, 0);
2180 if (ret)
2181 return ret;
2182
2183 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2184 0xFFFF, 0, 0xFFFF, 0, 0, 0,
2185 0, 0, 0, 0);
2186 if (ret)
2187 return ret;
2188 }
2189
Raja Manic08631c2011-12-16 14:24:24 +05302190 /* Setup own IP addr for ARP agent. */
2191 in_dev = __in_dev_get_rtnl(vif->ndev);
2192 if (!in_dev)
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002193 return 0;
Raja Manic08631c2011-12-16 14:24:24 +05302194
2195 ifa = in_dev->ifa_list;
2196 memset(&ips, 0, sizeof(ips));
2197
2198 /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
2199 while (index < MAX_IP_ADDRS && ifa) {
2200 ips[index] = ifa->ifa_local;
2201 ifa = ifa->ifa_next;
2202 index++;
2203 }
2204
2205 if (ifa) {
2206 ath6kl_err("total IP addr count is exceeding fw limit\n");
2207 return -EINVAL;
2208 }
2209
2210 ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
2211 if (ret) {
2212 ath6kl_err("fail to setup ip for arp agent\n");
2213 return ret;
2214 }
2215
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002216 return ret;
2217}
2218
2219static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
2220{
2221 struct ath6kl_vif *first_vif, *vif;
2222 int ret = 0;
2223 u32 filter = 0;
2224 bool connected = false;
2225
2226 /* enter / leave wow suspend on first vif always */
2227 first_vif = ath6kl_vif_first(ar);
Geliang Tangbffb7db2015-10-05 20:46:12 +08002228 if (WARN_ON(!first_vif) ||
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002229 !ath6kl_cfg80211_ready(first_vif))
2230 return -EIO;
2231
2232 if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
2233 return -EINVAL;
2234
2235 /* install filters for each connected vif */
2236 spin_lock_bh(&ar->list_lock);
2237 list_for_each_entry(vif, &ar->vif_list, list) {
2238 if (!test_bit(CONNECTED, &vif->flags) ||
2239 !ath6kl_cfg80211_ready(vif))
2240 continue;
2241 connected = true;
2242
2243 ret = ath6kl_wow_suspend_vif(vif, wow, &filter);
2244 if (ret)
2245 break;
2246 }
2247 spin_unlock_bh(&ar->list_lock);
2248
2249 if (!connected)
2250 return -ENOTCONN;
2251 else if (ret)
2252 return ret;
2253
2254 ar->state = ATH6KL_STATE_SUSPENDING;
2255
2256 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,
Raja Mani6cb3c712011-11-07 22:52:45 +02002257 ATH6KL_WOW_MODE_ENABLE,
2258 filter,
2259 WOW_HOST_REQ_DELAY);
2260 if (ret)
2261 return ret;
2262
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002263 return ath6kl_cfg80211_host_sleep(ar, first_vif);
Raja Mani6cb3c712011-11-07 22:52:45 +02002264}
2265
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002266static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)
Raja Mani6cb3c712011-11-07 22:52:45 +02002267{
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002268 struct ath6kl *ar = vif->ar;
Raja Mani6cb3c712011-11-07 22:52:45 +02002269 int ret;
2270
Raja Manice0dc0c2012-02-20 19:08:08 +05302271 if (vif->nw_type != AP_NETWORK) {
2272 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2273 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2274 if (ret)
2275 return ret;
2276
2277 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2278 vif->listen_intvl_t, 0);
2279 if (ret)
2280 return ret;
2281
2282 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2283 vif->bmiss_time_t, 0);
2284 if (ret)
2285 return ret;
2286 }
2287
Naveen Gangadharan6821d4f2012-05-11 14:19:09 -07002288 if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
2289 test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
2290 ar->fw_capabilities)) {
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002291 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002292 vif->fw_vif_idx, true);
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002293 if (ret)
2294 return ret;
2295 }
2296
Raja Mani390a8c82012-03-07 11:35:04 +05302297 netif_wake_queue(vif->ndev);
2298
2299 return 0;
Raja Mani6cb3c712011-11-07 22:52:45 +02002300}
2301
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002302static int ath6kl_wow_resume(struct ath6kl *ar)
2303{
2304 struct ath6kl_vif *vif;
2305 int ret;
2306
2307 vif = ath6kl_vif_first(ar);
Geliang Tangbffb7db2015-10-05 20:46:12 +08002308 if (WARN_ON(!vif) ||
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002309 !ath6kl_cfg80211_ready(vif))
2310 return -EIO;
2311
2312 ar->state = ATH6KL_STATE_RESUMING;
2313
2314 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2315 ATH6KL_HOST_MODE_AWAKE);
2316 if (ret) {
2317 ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
2318 ret);
2319 goto cleanup;
2320 }
2321
2322 spin_lock_bh(&ar->list_lock);
2323 list_for_each_entry(vif, &ar->vif_list, list) {
2324 if (!test_bit(CONNECTED, &vif->flags) ||
2325 !ath6kl_cfg80211_ready(vif))
2326 continue;
2327 ret = ath6kl_wow_resume_vif(vif);
2328 if (ret)
2329 break;
2330 }
2331 spin_unlock_bh(&ar->list_lock);
2332
2333 if (ret)
2334 goto cleanup;
2335
2336 ar->state = ATH6KL_STATE_ON;
2337 return 0;
2338
2339cleanup:
2340 ar->state = ATH6KL_STATE_WOW;
2341 return ret;
2342}
2343
Raja Mani40abc2d2012-03-21 15:03:38 +05302344static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
2345{
2346 struct ath6kl_vif *vif;
2347 int ret;
2348
2349 vif = ath6kl_vif_first(ar);
2350 if (!vif)
2351 return -EIO;
2352
Ming Jiang48f27582012-04-13 21:09:25 +08002353 if (!test_bit(WMI_READY, &ar->flag)) {
2354 ath6kl_err("deepsleep failed as wmi is not ready\n");
Raja Mani40abc2d2012-03-21 15:03:38 +05302355 return -EIO;
Ming Jiang48f27582012-04-13 21:09:25 +08002356 }
Raja Mani40abc2d2012-03-21 15:03:38 +05302357
2358 ath6kl_cfg80211_stop_all(ar);
2359
2360 /* Save the current power mode before enabling power save */
2361 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2362
2363 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
2364 if (ret)
2365 return ret;
2366
2367 /* Disable WOW mode */
2368 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2369 ATH6KL_WOW_MODE_DISABLE,
2370 0, 0);
2371 if (ret)
2372 return ret;
2373
2374 /* Flush all non control pkts in TX path */
2375 ath6kl_tx_data_cleanup(ar);
2376
2377 ret = ath6kl_cfg80211_host_sleep(ar, vif);
2378 if (ret)
2379 return ret;
2380
2381 return 0;
2382}
2383
2384static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
2385{
2386 struct ath6kl_vif *vif;
2387 int ret;
2388
2389 vif = ath6kl_vif_first(ar);
2390
2391 if (!vif)
2392 return -EIO;
2393
2394 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
2395 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
2396 ar->wmi->saved_pwr_mode);
2397 if (ret)
2398 return ret;
2399 }
2400
2401 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2402 ATH6KL_HOST_MODE_AWAKE);
2403 if (ret)
2404 return ret;
2405
2406 ar->state = ATH6KL_STATE_ON;
2407
2408 /* Reset scan parameter to default values */
2409 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2410 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2411 if (ret)
2412 return ret;
2413
2414 return 0;
2415}
2416
Kalle Valo52d81a62011-11-01 08:44:21 +02002417int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02002418 enum ath6kl_cfg_suspend_mode mode,
2419 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02002420{
Vivek Natarajan3d794992012-03-28 19:21:26 +05302421 struct ath6kl_vif *vif;
Raja Mani390a8c82012-03-07 11:35:04 +05302422 enum ath6kl_state prev_state;
Kalle Valo52d81a62011-11-01 08:44:21 +02002423 int ret;
2424
Kalle Valo52d81a62011-11-01 08:44:21 +02002425 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02002426 case ATH6KL_CFG_SUSPEND_WOW:
2427
2428 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
2429
2430 /* Flush all non control pkts in TX path */
2431 ath6kl_tx_data_cleanup(ar);
2432
Raja Mani390a8c82012-03-07 11:35:04 +05302433 prev_state = ar->state;
2434
Raja Manid7c44e02011-11-07 22:52:46 +02002435 ret = ath6kl_wow_suspend(ar, wow);
Raja Mani390a8c82012-03-07 11:35:04 +05302436 if (ret) {
2437 ar->state = prev_state;
Raja Manid7c44e02011-11-07 22:52:46 +02002438 return ret;
Raja Mani390a8c82012-03-07 11:35:04 +05302439 }
Raja Mani1e9a9052012-03-06 15:03:59 +05302440
Raja Manid7c44e02011-11-07 22:52:46 +02002441 ar->state = ATH6KL_STATE_WOW;
2442 break;
2443
Kalle Valo52d81a62011-11-01 08:44:21 +02002444 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02002445
Raja Mani40abc2d2012-03-21 15:03:38 +05302446 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n");
Raja Mani524441e2011-11-07 22:52:46 +02002447
Raja Mani40abc2d2012-03-21 15:03:38 +05302448 ret = ath6kl_cfg80211_deepsleep_suspend(ar);
Kalle Valo52d81a62011-11-01 08:44:21 +02002449 if (ret) {
Raja Mani40abc2d2012-03-21 15:03:38 +05302450 ath6kl_err("deepsleep suspend failed: %d\n", ret);
2451 return ret;
Kalle Valo52d81a62011-11-01 08:44:21 +02002452 }
2453
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002454 ar->state = ATH6KL_STATE_DEEPSLEEP;
2455
Kalle Valo52d81a62011-11-01 08:44:21 +02002456 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002457
2458 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02002459
Kalle Valo7125f012011-12-13 14:51:37 +02002460 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02002461
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002462 if (ar->state == ATH6KL_STATE_OFF) {
2463 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
2464 "suspend hw off, no action for cutpower\n");
2465 break;
2466 }
2467
2468 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
2469
2470 ret = ath6kl_init_hw_stop(ar);
2471 if (ret) {
2472 ath6kl_warn("failed to stop hw during suspend: %d\n",
2473 ret);
2474 }
2475
2476 ar->state = ATH6KL_STATE_CUTPOWER;
2477
2478 break;
2479
2480 default:
2481 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002482 }
2483
Vivek Natarajan3d794992012-03-28 19:21:26 +05302484 list_for_each_entry(vif, &ar->vif_list, list)
2485 ath6kl_cfg80211_scan_complete_event(vif, true);
2486
Kalle Valo52d81a62011-11-01 08:44:21 +02002487 return 0;
2488}
Kalle Valod6a434d2012-01-17 20:09:36 +02002489EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
Kalle Valo52d81a62011-11-01 08:44:21 +02002490
2491int ath6kl_cfg80211_resume(struct ath6kl *ar)
2492{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002493 int ret;
2494
2495 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02002496 case ATH6KL_STATE_WOW:
2497 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
2498
2499 ret = ath6kl_wow_resume(ar);
2500 if (ret) {
2501 ath6kl_warn("wow mode resume failed: %d\n", ret);
2502 return ret;
2503 }
2504
Raja Manid7c44e02011-11-07 22:52:46 +02002505 break;
2506
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002507 case ATH6KL_STATE_DEEPSLEEP:
Raja Mani40abc2d2012-03-21 15:03:38 +05302508 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
2509
2510 ret = ath6kl_cfg80211_deepsleep_resume(ar);
2511 if (ret) {
2512 ath6kl_warn("deep sleep resume failed: %d\n", ret);
2513 return ret;
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002514 }
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002515 break;
2516
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002517 case ATH6KL_STATE_CUTPOWER:
2518 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
2519
2520 ret = ath6kl_init_hw_start(ar);
2521 if (ret) {
2522 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
2523 return ret;
2524 }
Raja Manid7c44e02011-11-07 22:52:46 +02002525 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002526
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002527 default:
2528 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002529 }
2530
2531 return 0;
2532}
Kalle Valod6a434d2012-01-17 20:09:36 +02002533EXPORT_SYMBOL(ath6kl_cfg80211_resume);
Kalle Valo52d81a62011-11-01 08:44:21 +02002534
Kalle Valoabcb3442011-07-22 08:26:20 +03002535#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002536
2537/* hif layer decides what suspend mode to use */
2538static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03002539 struct cfg80211_wowlan *wow)
2540{
2541 struct ath6kl *ar = wiphy_priv(wiphy);
2542
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302543 ath6kl_recovery_suspend(ar);
2544
Raja Mani0f60e9f2011-11-07 22:52:45 +02002545 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03002546}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002547
Kalle Valo52d81a62011-11-01 08:44:21 +02002548static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002549{
2550 struct ath6kl *ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302551 int err;
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002552
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302553 err = ath6kl_hif_resume(ar);
2554 if (err)
2555 return err;
2556
Vasanthakumar Thiagarajan92332992012-08-29 19:40:27 +05302557 ath6kl_recovery_resume(ar);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302558
2559 return 0;
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002560}
Raja Mania918fb32011-11-07 22:52:46 +02002561
2562/*
2563 * FIXME: WOW suspend mode is selected if the host sdio controller supports
2564 * both sdio irq wake up and keep power. The target pulls sdio data line to
2565 * wake up the host when WOW pattern matches. This causes sdio irq handler
2566 * is being called in the host side which internally hits ath6kl's RX path.
2567 *
2568 * Since sdio interrupt is not disabled, RX path executes even before
2569 * the host executes the actual resume operation from PM module.
2570 *
2571 * In the current scenario, WOW resume should happen before start processing
2572 * any data from the target. So It's required to perform WOW resume in RX path.
2573 * Ideally we should perform WOW resume only in the actual platform
2574 * resume path. This area needs bit rework to avoid WOW resume in RX path.
2575 *
2576 * ath6kl_check_wow_status() is called from ath6kl_rx().
2577 */
2578void ath6kl_check_wow_status(struct ath6kl *ar)
2579{
Raja Mani390a8c82012-03-07 11:35:04 +05302580 if (ar->state == ATH6KL_STATE_SUSPENDING)
2581 return;
2582
Raja Mania918fb32011-11-07 22:52:46 +02002583 if (ar->state == ATH6KL_STATE_WOW)
2584 ath6kl_cfg80211_resume(ar);
2585}
2586
2587#else
2588
2589void ath6kl_check_wow_status(struct ath6kl *ar)
2590{
2591}
Kalle Valoabcb3442011-07-22 08:26:20 +03002592#endif
2593
Johannes Berg57fbcce2016-04-12 15:56:15 +02002594static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum nl80211_band band,
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302595 bool ht_enable)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002596{
Kiran Reddy67b3f122012-05-29 11:12:50 -07002597 struct ath6kl_htcap *htcap = &vif->htcap[band];
Sujith Manoharane68f6752011-12-22 12:15:27 +05302598
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302599 if (htcap->ht_enable == ht_enable)
2600 return 0;
Sujith Manoharane68f6752011-12-22 12:15:27 +05302601
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302602 if (ht_enable) {
2603 /* Set default ht capabilities */
2604 htcap->ht_enable = true;
Johannes Berg57fbcce2016-04-12 15:56:15 +02002605 htcap->cap_info = (band == NL80211_BAND_2GHZ) ?
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302606 ath6kl_g_htcap : ath6kl_a_htcap;
2607 htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
2608 } else /* Disable ht */
2609 memset(htcap, 0, sizeof(*htcap));
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002610
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302611 return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx,
2612 band, htcap);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002613}
2614
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002615static int ath6kl_restore_htcap(struct ath6kl_vif *vif)
2616{
2617 struct wiphy *wiphy = vif->ar->wiphy;
2618 int band, ret = 0;
2619
Johannes Berg57fbcce2016-04-12 15:56:15 +02002620 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002621 if (!wiphy->bands[band])
2622 continue;
2623
2624 ret = ath6kl_set_htcap(vif, band,
2625 wiphy->bands[band]->ht_cap.ht_supported);
2626 if (ret)
2627 return ret;
2628 }
2629
2630 return ret;
2631}
2632
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002633static bool ath6kl_is_p2p_ie(const u8 *pos)
2634{
2635 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2636 pos[2] == 0x50 && pos[3] == 0x6f &&
2637 pos[4] == 0x9a && pos[5] == 0x09;
2638}
2639
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302640static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2641 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002642{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302643 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002644 const u8 *pos;
2645 u8 *buf = NULL;
2646 size_t len = 0;
2647 int ret;
2648
2649 /*
2650 * Filter out P2P IE(s) since they will be included depending on
2651 * the Probe Request frame in ath6kl_send_go_probe_resp().
2652 */
2653
2654 if (ies && ies_len) {
2655 buf = kmalloc(ies_len, GFP_KERNEL);
2656 if (buf == NULL)
2657 return -ENOMEM;
2658 pos = ies;
2659 while (pos + 1 < ies + ies_len) {
2660 if (pos + 2 + pos[1] > ies + ies_len)
2661 break;
2662 if (!ath6kl_is_p2p_ie(pos)) {
2663 memcpy(buf + len, pos, 2 + pos[1]);
2664 len += 2 + pos[1];
2665 }
2666 pos += 2 + pos[1];
2667 }
2668 }
2669
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302670 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2671 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002672 kfree(buf);
2673 return ret;
2674}
2675
Johannes Berg88600202012-02-13 15:17:18 +01002676static int ath6kl_set_ies(struct ath6kl_vif *vif,
2677 struct cfg80211_beacon_data *info)
2678{
2679 struct ath6kl *ar = vif->ar;
2680 int res;
2681
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002682 /* this also clears IE in fw if it's not set */
2683 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2684 WMI_FRAME_BEACON,
2685 info->beacon_ies,
2686 info->beacon_ies_len);
2687 if (res)
2688 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002689
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002690 /* this also clears IE in fw if it's not set */
2691 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
2692 info->proberesp_ies_len);
2693 if (res)
2694 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002695
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002696 /* this also clears IE in fw if it's not set */
2697 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2698 WMI_FRAME_ASSOC_RESP,
2699 info->assocresp_ies,
2700 info->assocresp_ies_len);
2701 if (res)
2702 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002703
2704 return 0;
2705}
2706
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302707static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
2708 u8 *rsn_capab)
2709{
2710 const u8 *rsn_ie;
2711 size_t rsn_ie_len;
2712 u16 cnt;
2713
2714 if (!beacon->tail)
2715 return -EINVAL;
2716
2717 rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
2718 if (!rsn_ie)
2719 return -EINVAL;
2720
2721 rsn_ie_len = *(rsn_ie + 1);
2722 /* skip element id and length */
2723 rsn_ie += 2;
2724
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302725 /* skip version */
2726 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302727 return -EINVAL;
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302728 rsn_ie += 2;
2729 rsn_ie_len -= 2;
2730
2731 /* skip group cipher suite */
2732 if (rsn_ie_len < 4)
2733 return 0;
2734 rsn_ie += 4;
2735 rsn_ie_len -= 4;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302736
2737 /* skip pairwise cipher suite */
2738 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302739 return 0;
Vasanthakumar Thiagarajan798985c2012-04-10 13:35:47 +05302740 cnt = get_unaligned_le16(rsn_ie);
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302741 rsn_ie += (2 + cnt * 4);
2742 rsn_ie_len -= (2 + cnt * 4);
2743
2744 /* skip akm suite */
2745 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302746 return 0;
Vasanthakumar Thiagarajan798985c2012-04-10 13:35:47 +05302747 cnt = get_unaligned_le16(rsn_ie);
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302748 rsn_ie += (2 + cnt * 4);
2749 rsn_ie_len -= (2 + cnt * 4);
2750
2751 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302752 return 0;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302753
2754 memcpy(rsn_capab, rsn_ie, 2);
2755
2756 return 0;
2757}
2758
Johannes Berg88600202012-02-13 15:17:18 +01002759static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2760 struct cfg80211_ap_settings *info)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002761{
2762 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302763 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002764 struct ieee80211_mgmt *mgmt;
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002765 bool hidden = false;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002766 u8 *ies;
2767 int ies_len;
2768 struct wmi_connect_cmd p;
2769 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302770 int i, ret;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302771 u16 rsn_capab = 0;
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302772 int inactivity_timeout = 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002773
Johannes Berg88600202012-02-13 15:17:18 +01002774 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002775
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302776 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002777 return -EIO;
2778
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302779 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002780 return -EOPNOTSUPP;
2781
Johannes Berg88600202012-02-13 15:17:18 +01002782 res = ath6kl_set_ies(vif, &info->beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002783
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002784 ar->ap_mode_bkey.valid = false;
2785
Mohammed Shafi Shajakhaneb922e42012-11-16 18:23:15 +05302786 ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx,
2787 info->beacon_interval);
2788
2789 if (ret)
2790 ath6kl_warn("Failed to set beacon interval: %d\n", ret);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002791
Etay Luzd154f322012-05-30 11:35:08 +03002792 ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
2793 info->dtim_period);
2794
2795 /* ignore error, just print a warning and continue normally */
2796 if (ret)
2797 ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
2798
Johannes Berg88600202012-02-13 15:17:18 +01002799 if (info->beacon.head == NULL)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002800 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002801 mgmt = (struct ieee80211_mgmt *) info->beacon.head;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002802 ies = mgmt->u.beacon.variable;
Johannes Berg88600202012-02-13 15:17:18 +01002803 if (ies > info->beacon.head + info->beacon.head_len)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002804 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002805 ies_len = info->beacon.head + info->beacon.head_len - ies;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002806
2807 if (info->ssid == NULL)
2808 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302809 memcpy(vif->ssid, info->ssid, info->ssid_len);
2810 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002811 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002812 hidden = true;
2813
2814 res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
2815 if (res)
2816 return res;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002817
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302818 ret = ath6kl_set_auth_type(vif, info->auth_type);
2819 if (ret)
2820 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002821
2822 memset(&p, 0, sizeof(p));
2823
2824 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2825 switch (info->crypto.akm_suites[i]) {
2826 case WLAN_AKM_SUITE_8021X:
2827 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2828 p.auth_mode |= WPA_AUTH;
2829 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2830 p.auth_mode |= WPA2_AUTH;
2831 break;
2832 case WLAN_AKM_SUITE_PSK:
2833 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2834 p.auth_mode |= WPA_PSK_AUTH;
2835 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2836 p.auth_mode |= WPA2_PSK_AUTH;
2837 break;
2838 }
2839 }
2840 if (p.auth_mode == 0)
2841 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302842 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002843
2844 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2845 switch (info->crypto.ciphers_pairwise[i]) {
2846 case WLAN_CIPHER_SUITE_WEP40:
2847 case WLAN_CIPHER_SUITE_WEP104:
2848 p.prwise_crypto_type |= WEP_CRYPT;
2849 break;
2850 case WLAN_CIPHER_SUITE_TKIP:
2851 p.prwise_crypto_type |= TKIP_CRYPT;
2852 break;
2853 case WLAN_CIPHER_SUITE_CCMP:
2854 p.prwise_crypto_type |= AES_CRYPT;
2855 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002856 case WLAN_CIPHER_SUITE_SMS4:
2857 p.prwise_crypto_type |= WAPI_CRYPT;
2858 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002859 }
2860 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002861 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002862 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302863 ath6kl_set_cipher(vif, 0, true);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +02002864 } else if (info->crypto.n_ciphers_pairwise == 1) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302865 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +02002866 }
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002867
2868 switch (info->crypto.cipher_group) {
2869 case WLAN_CIPHER_SUITE_WEP40:
2870 case WLAN_CIPHER_SUITE_WEP104:
2871 p.grp_crypto_type = WEP_CRYPT;
2872 break;
2873 case WLAN_CIPHER_SUITE_TKIP:
2874 p.grp_crypto_type = TKIP_CRYPT;
2875 break;
2876 case WLAN_CIPHER_SUITE_CCMP:
2877 p.grp_crypto_type = AES_CRYPT;
2878 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002879 case WLAN_CIPHER_SUITE_SMS4:
2880 p.grp_crypto_type = WAPI_CRYPT;
2881 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002882 default:
2883 p.grp_crypto_type = NONE_CRYPT;
2884 break;
2885 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302886 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002887
2888 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302889 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002890
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302891 p.ssid_len = vif->ssid_len;
2892 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2893 p.dot11_auth_mode = vif->dot11_auth_mode;
Johannes Berg683b6d32012-11-08 21:25:48 +01002894 p.ch = cpu_to_le16(info->chandef.chan->center_freq);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002895
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302896 /* Enable uAPSD support by default */
2897 res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
2898 if (res < 0)
2899 return res;
2900
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002901 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2902 p.nw_subtype = SUBTYPE_P2PGO;
2903 } else {
2904 /*
2905 * Due to firmware limitation, it is not possible to
2906 * do P2P mgmt operations in AP mode
2907 */
2908 p.nw_subtype = SUBTYPE_NONE;
2909 }
2910
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302911 if (info->inactivity_timeout) {
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302912 inactivity_timeout = info->inactivity_timeout;
2913
Kalle Valoeba95bc2014-06-17 12:40:52 +03002914 if (test_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS,
2915 ar->fw_capabilities))
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302916 inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
2917 60);
2918
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302919 res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302920 inactivity_timeout);
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302921 if (res < 0)
2922 return res;
2923 }
2924
Johannes Berg683b6d32012-11-08 21:25:48 +01002925 if (ath6kl_set_htcap(vif, info->chandef.chan->band,
2926 cfg80211_get_chandef_type(&info->chandef)
2927 != NL80211_CHAN_NO_HT))
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302928 return -EIO;
2929
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302930 /*
2931 * Get the PTKSA replay counter in the RSN IE. Supplicant
2932 * will use the RSN IE in M3 message and firmware has to
2933 * advertise the same in beacon/probe response. Send
2934 * the complete RSN IE capability field to firmware
2935 */
2936 if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
2937 test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
2938 ar->fw_capabilities)) {
2939 res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
2940 WLAN_EID_RSN, WMI_RSN_IE_CAPB,
2941 (const u8 *) &rsn_capab,
2942 sizeof(rsn_capab));
Thomas Pedersenf21243a2012-07-27 18:13:27 -07002943 vif->rsn_capab = rsn_capab;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302944 if (res < 0)
2945 return res;
2946 }
2947
Thomas Pedersenc4f78632012-04-06 13:35:48 -07002948 memcpy(&vif->profile, &p, sizeof(p));
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302949 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002950 if (res < 0)
2951 return res;
2952
2953 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002954}
2955
Johannes Berg88600202012-02-13 15:17:18 +01002956static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
2957 struct cfg80211_beacon_data *beacon)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002958{
Johannes Berg88600202012-02-13 15:17:18 +01002959 struct ath6kl_vif *vif = netdev_priv(dev);
2960
2961 if (!ath6kl_cfg80211_ready(vif))
2962 return -EIO;
2963
2964 if (vif->next_mode != AP_NETWORK)
2965 return -EOPNOTSUPP;
2966
2967 return ath6kl_set_ies(vif, beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002968}
2969
Johannes Berg88600202012-02-13 15:17:18 +01002970static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002971{
2972 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302973 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002974
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302975 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002976 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302977 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002978 return -ENOTCONN;
2979
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302980 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302981 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002982
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302983 /* Restore ht setting in firmware */
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002984 return ath6kl_restore_htcap(vif);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002985}
2986
Jouni Malinen33e53082011-12-27 11:02:56 +02002987static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2988
2989static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03002990 struct station_del_parameters *params)
Jouni Malinen33e53082011-12-27 11:02:56 +02002991{
2992 struct ath6kl *ar = ath6kl_priv(dev);
2993 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen89c771e2014-10-10 20:52:40 +03002994 const u8 *addr = params->mac ? params->mac : bcast_addr;
Jouni Malinen33e53082011-12-27 11:02:56 +02002995
2996 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
2997 addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
2998}
2999
Jouni Malinen23875132011-08-30 21:57:53 +03003000static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02003001 const u8 *mac,
3002 struct station_parameters *params)
Jouni Malinen23875132011-08-30 21:57:53 +03003003{
3004 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05303005 struct ath6kl_vif *vif = netdev_priv(dev);
Johannes Berg77ee7c82013-02-15 00:48:33 +01003006 int err;
Jouni Malinen23875132011-08-30 21:57:53 +03003007
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05303008 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03003009 return -EOPNOTSUPP;
3010
Johannes Berg77ee7c82013-02-15 00:48:33 +01003011 err = cfg80211_check_station_change(wiphy, params,
3012 CFG80211_STA_AP_MLME_CLIENT);
3013 if (err)
3014 return err;
Jouni Malinen23875132011-08-30 21:57:53 +03003015
3016 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303017 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
3018 WMI_AP_MLME_AUTHORIZE, mac, 0);
3019 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
3020 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03003021}
3022
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003023static int ath6kl_remain_on_channel(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003024 struct wireless_dev *wdev,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003025 struct ieee80211_channel *chan,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003026 unsigned int duration,
3027 u64 *cookie)
3028{
Johannes Berg71bbc992012-06-15 15:30:18 +02003029 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3030 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Jouni Malinen10522612011-10-27 16:00:13 +03003031 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003032
3033 /* TODO: if already pending or ongoing remain-on-channel,
3034 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03003035 id = ++vif->last_roc_id;
3036 if (id == 0) {
3037 /* Do not use 0 as the cookie value */
3038 id = ++vif->last_roc_id;
3039 }
3040 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003041
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303042 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
3043 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003044}
3045
3046static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003047 struct wireless_dev *wdev,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003048 u64 cookie)
3049{
Johannes Berg71bbc992012-06-15 15:30:18 +02003050 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3051 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003052
Jouni Malinen10522612011-10-27 16:00:13 +03003053 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003054 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03003055 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003056
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303057 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003058}
3059
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303060static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
3061 const u8 *buf, size_t len,
3062 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003063{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303064 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003065 const u8 *pos;
3066 u8 *p2p;
3067 int p2p_len;
3068 int ret;
3069 const struct ieee80211_mgmt *mgmt;
3070
3071 mgmt = (const struct ieee80211_mgmt *) buf;
3072
3073 /* Include P2P IE(s) from the frame generated in user space. */
3074
3075 p2p = kmalloc(len, GFP_KERNEL);
3076 if (p2p == NULL)
3077 return -ENOMEM;
3078 p2p_len = 0;
3079
3080 pos = mgmt->u.probe_resp.variable;
3081 while (pos + 1 < buf + len) {
3082 if (pos + 2 + pos[1] > buf + len)
3083 break;
3084 if (ath6kl_is_p2p_ie(pos)) {
3085 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
3086 p2p_len += 2 + pos[1];
3087 }
3088 pos += 2 + pos[1];
3089 }
3090
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303091 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
3092 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003093 kfree(p2p);
3094 return ret;
3095}
3096
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003097static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
3098 u32 id,
3099 u32 freq,
3100 u32 wait,
3101 const u8 *buf,
3102 size_t len,
3103 bool *more_data,
3104 bool no_cck)
3105{
3106 struct ieee80211_mgmt *mgmt;
3107 struct ath6kl_sta *conn;
3108 bool is_psq_empty = false;
3109 struct ath6kl_mgmt_buff *mgmt_buf;
3110 size_t mgmt_buf_size;
3111 struct ath6kl *ar = vif->ar;
3112
3113 mgmt = (struct ieee80211_mgmt *) buf;
3114 if (is_multicast_ether_addr(mgmt->da))
3115 return false;
3116
3117 conn = ath6kl_find_sta(vif, mgmt->da);
3118 if (!conn)
3119 return false;
3120
3121 if (conn->sta_flags & STA_PS_SLEEP) {
3122 if (!(conn->sta_flags & STA_PS_POLLED)) {
3123 /* Queue the frames if the STA is sleeping */
3124 mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
3125 mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
3126 if (!mgmt_buf)
3127 return false;
3128
3129 INIT_LIST_HEAD(&mgmt_buf->list);
3130 mgmt_buf->id = id;
3131 mgmt_buf->freq = freq;
3132 mgmt_buf->wait = wait;
3133 mgmt_buf->len = len;
3134 mgmt_buf->no_cck = no_cck;
3135 memcpy(mgmt_buf->buf, buf, len);
3136 spin_lock_bh(&conn->psq_lock);
3137 is_psq_empty = skb_queue_empty(&conn->psq) &&
3138 (conn->mgmt_psq_len == 0);
3139 list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
3140 conn->mgmt_psq_len++;
3141 spin_unlock_bh(&conn->psq_lock);
3142
3143 /*
3144 * If this is the first pkt getting queued
3145 * for this STA, update the PVB for this
3146 * STA.
3147 */
3148 if (is_psq_empty)
3149 ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
3150 conn->aid, 1);
3151 return true;
3152 }
3153
3154 /*
3155 * This tx is because of a PsPoll.
3156 * Determine if MoreData bit has to be set.
3157 */
3158 spin_lock_bh(&conn->psq_lock);
3159 if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
3160 *more_data = true;
3161 spin_unlock_bh(&conn->psq_lock);
3162 }
3163
3164 return false;
3165}
3166
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003167/* Check if SSID length is greater than DIRECT- */
3168static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
3169{
3170 const struct ieee80211_mgmt *mgmt;
3171 mgmt = (const struct ieee80211_mgmt *) buf;
3172
3173 /* variable[1] contains the SSID tag length */
3174 if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
3175 (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
3176 return true;
3177 }
3178
3179 return false;
3180}
3181
Johannes Berg71bbc992012-06-15 15:30:18 +02003182static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003183 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003184{
Johannes Berg71bbc992012-06-15 15:30:18 +02003185 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3186 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003187 struct ieee80211_channel *chan = params->chan;
3188 const u8 *buf = params->buf;
3189 size_t len = params->len;
3190 unsigned int wait = params->wait;
3191 bool no_cck = params->no_cck;
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003192 u32 id, freq;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003193 const struct ieee80211_mgmt *mgmt;
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003194 bool more_data, queued;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003195
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003196 /* default to the current channel, but use the one specified as argument
3197 * if any
3198 */
3199 freq = vif->ch_hint;
3200 if (chan)
3201 freq = chan->center_freq;
3202
3203 /* never send freq zero to the firmware */
3204 if (WARN_ON(freq == 0))
3205 return -EINVAL;
3206
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003207 mgmt = (const struct ieee80211_mgmt *) buf;
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003208 if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
3209 ieee80211_is_probe_resp(mgmt->frame_control) &&
3210 ath6kl_is_p2p_go_ssid(buf, len)) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003211 /*
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003212 * Send Probe Response frame in GO mode using a separate WMI
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003213 * command to allow the target to fill in the generic IEs.
3214 */
3215 *cookie = 0; /* TX status not supported */
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003216 return ath6kl_send_go_probe_resp(vif, buf, len, freq);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003217 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003218
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303219 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003220 if (id == 0) {
3221 /*
3222 * 0 is a reserved value in the WMI command and shall not be
3223 * used for the command.
3224 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303225 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003226 }
3227
3228 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08003229
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003230 /* AP mode Power saving processing */
3231 if (vif->nw_type == AP_NETWORK) {
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003232 queued = ath6kl_mgmt_powersave_ap(vif, id, freq, wait, buf, len,
3233 &more_data, no_cck);
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003234 if (queued)
3235 return 0;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08003236 }
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003237
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003238 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, freq,
3239 wait, buf, len, no_cck);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003240}
3241
Ben Greear9c2e90f2015-10-21 14:53:19 -07003242static int ath6kl_get_antenna(struct wiphy *wiphy,
3243 u32 *tx_ant, u32 *rx_ant)
3244{
3245 struct ath6kl *ar = wiphy_priv(wiphy);
3246 *tx_ant = ar->hw.tx_ant;
3247 *rx_ant = ar->hw.rx_ant;
3248 return 0;
3249}
3250
Jouni Malinenae32c302011-08-30 21:58:01 +03003251static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003252 struct wireless_dev *wdev,
Jouni Malinenae32c302011-08-30 21:58:01 +03003253 u16 frame_type, bool reg)
3254{
Johannes Berg71bbc992012-06-15 15:30:18 +02003255 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
Jouni Malinenae32c302011-08-30 21:58:01 +03003256
3257 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
3258 __func__, frame_type, reg);
3259 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
3260 /*
3261 * Note: This notification callback is not allowed to sleep, so
3262 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
3263 * hardcode target to report Probe Request frames all the time.
3264 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303265 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03003266 }
3267}
3268
Kalle Valo10509f92011-12-13 14:52:07 +02003269static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3270 struct net_device *dev,
3271 struct cfg80211_sched_scan_request *request)
3272{
3273 struct ath6kl *ar = ath6kl_priv(dev);
3274 struct ath6kl_vif *vif = netdev_priv(dev);
3275 u16 interval;
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003276 int ret, rssi_thold;
Johannes Bergea73cbc2014-01-24 10:53:53 +01003277 int n_match_sets = request->n_match_sets;
3278
3279 /*
3280 * If there's a matchset w/o an SSID, then assume it's just for
3281 * the RSSI (nothing else is currently supported) and ignore it.
3282 * The device only supports a global RSSI filter that we set below.
3283 */
3284 if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
3285 n_match_sets = 0;
Kalle Valo10509f92011-12-13 14:52:07 +02003286
3287 if (ar->state != ATH6KL_STATE_ON)
3288 return -EIO;
3289
3290 if (vif->sme_state != SME_DISCONNECTED)
3291 return -EBUSY;
3292
Kalle Valob4d13d32012-03-21 10:01:09 +02003293 ath6kl_cfg80211_scan_complete_event(vif, true);
3294
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03003295 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
Naveen Singhdd45b752012-05-16 13:29:00 +03003296 request->n_ssids,
3297 request->match_sets,
Johannes Bergea73cbc2014-01-24 10:53:53 +01003298 n_match_sets);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03003299 if (ret < 0)
3300 return ret;
Kalle Valo10509f92011-12-13 14:52:07 +02003301
Johannes Bergea73cbc2014-01-24 10:53:53 +01003302 if (!n_match_sets) {
Naveen Singhdd45b752012-05-16 13:29:00 +03003303 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
3304 ALL_BSS_FILTER, 0);
3305 if (ret < 0)
3306 return ret;
3307 } else {
3308 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
3309 MATCHED_SSID_FILTER, 0);
3310 if (ret < 0)
3311 return ret;
3312 }
3313
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003314 if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
3315 ar->fw_capabilities)) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01003316 if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003317 rssi_thold = 0;
Johannes Bergea73cbc2014-01-24 10:53:53 +01003318 else if (request->min_rssi_thold < -127)
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003319 rssi_thold = -127;
3320 else
Johannes Bergea73cbc2014-01-24 10:53:53 +01003321 rssi_thold = request->min_rssi_thold;
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003322
3323 ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
3324 rssi_thold);
3325 if (ret) {
3326 ath6kl_err("failed to set RSSI threshold for scan\n");
3327 return ret;
3328 }
3329 }
3330
Kalle Valo10509f92011-12-13 14:52:07 +02003331 /* fw uses seconds, also make sure that it's >0 */
Avraham Stern3b06d272015-10-12 09:51:34 +03003332 interval = max_t(u16, 1, request->scan_plans[0].interval);
Kalle Valo10509f92011-12-13 14:52:07 +02003333
3334 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
3335 interval, interval,
Subramania Sharma Thandaveswarand472b5e2012-04-16 16:09:57 +05303336 vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
Kalle Valo10509f92011-12-13 14:52:07 +02003337
Kalle Valo10509f92011-12-13 14:52:07 +02003338 /* this also clears IE in fw if it's not set */
3339 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
3340 WMI_FRAME_PROBE_REQ,
3341 request->ie, request->ie_len);
3342 if (ret) {
Joe Perchesf1ff32e2012-05-30 01:58:39 -07003343 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
Kalle Valo10509f92011-12-13 14:52:07 +02003344 ret);
3345 return ret;
3346 }
3347
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003348 ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
3349 if (ret)
Kalle Valo10509f92011-12-13 14:52:07 +02003350 return ret;
Kalle Valo10509f92011-12-13 14:52:07 +02003351
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003352 set_bit(SCHED_SCANNING, &vif->flags);
Kalle Valo10509f92011-12-13 14:52:07 +02003353
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003354 return 0;
Kalle Valo10509f92011-12-13 14:52:07 +02003355}
3356
3357static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
3358 struct net_device *dev)
3359{
3360 struct ath6kl_vif *vif = netdev_priv(dev);
3361 bool stopped;
3362
3363 stopped = __ath6kl_cfg80211_sscan_stop(vif);
3364
3365 if (!stopped)
3366 return -EIO;
3367
3368 return 0;
3369}
3370
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303371static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
3372 struct net_device *dev,
3373 const u8 *addr,
3374 const struct cfg80211_bitrate_mask *mask)
3375{
3376 struct ath6kl *ar = ath6kl_priv(dev);
3377 struct ath6kl_vif *vif = netdev_priv(dev);
3378
3379 return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
3380 mask);
3381}
3382
Thomas Pedersen279b2862012-07-17 19:39:55 -07003383static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy,
3384 struct net_device *dev,
3385 u32 rate, u32 pkts, u32 intvl)
3386{
3387 struct ath6kl *ar = ath6kl_priv(dev);
3388 struct ath6kl_vif *vif = netdev_priv(dev);
3389
3390 if (vif->nw_type != INFRA_NETWORK ||
3391 !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities))
3392 return -EOPNOTSUPP;
3393
3394 if (vif->sme_state != SME_CONNECTED)
3395 return -ENOTCONN;
3396
3397 /* save this since the firmware won't report the interval */
3398 vif->txe_intvl = intvl;
3399
3400 return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx,
3401 rate, pkts, intvl);
3402}
3403
Jouni Malinenf80574a2011-08-30 21:58:04 +03003404static const struct ieee80211_txrx_stypes
3405ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
3406 [NL80211_IFTYPE_STATION] = {
3407 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3408 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3409 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3410 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3411 },
Jouni Malinenba1f6fe2011-12-27 11:03:53 +02003412 [NL80211_IFTYPE_AP] = {
3413 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3414 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3415 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3416 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3417 },
Jouni Malinenf80574a2011-08-30 21:58:04 +03003418 [NL80211_IFTYPE_P2P_CLIENT] = {
3419 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3420 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3421 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3422 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3423 },
3424 [NL80211_IFTYPE_P2P_GO] = {
3425 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3426 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3427 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3428 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3429 },
3430};
3431
Kalle Valobdcd8172011-07-18 00:22:30 +03003432static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303433 .add_virtual_intf = ath6kl_cfg80211_add_iface,
3434 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03003435 .change_virtual_intf = ath6kl_cfg80211_change_iface,
3436 .scan = ath6kl_cfg80211_scan,
3437 .connect = ath6kl_cfg80211_connect,
3438 .disconnect = ath6kl_cfg80211_disconnect,
3439 .add_key = ath6kl_cfg80211_add_key,
3440 .get_key = ath6kl_cfg80211_get_key,
3441 .del_key = ath6kl_cfg80211_del_key,
3442 .set_default_key = ath6kl_cfg80211_set_default_key,
3443 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
3444 .set_tx_power = ath6kl_cfg80211_set_txpower,
3445 .get_tx_power = ath6kl_cfg80211_get_txpower,
3446 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
3447 .join_ibss = ath6kl_cfg80211_join_ibss,
3448 .leave_ibss = ath6kl_cfg80211_leave_ibss,
3449 .get_station = ath6kl_get_station,
3450 .set_pmksa = ath6kl_set_pmksa,
3451 .del_pmksa = ath6kl_del_pmksa,
3452 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03003453 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03003454#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02003455 .suspend = __ath6kl_cfg80211_suspend,
3456 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03003457#endif
Johannes Berg88600202012-02-13 15:17:18 +01003458 .start_ap = ath6kl_start_ap,
3459 .change_beacon = ath6kl_change_beacon,
3460 .stop_ap = ath6kl_stop_ap,
Jouni Malinen33e53082011-12-27 11:02:56 +02003461 .del_station = ath6kl_del_station,
Jouni Malinen23875132011-08-30 21:57:53 +03003462 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003463 .remain_on_channel = ath6kl_remain_on_channel,
3464 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003465 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03003466 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Ben Greear9c2e90f2015-10-21 14:53:19 -07003467 .get_antenna = ath6kl_get_antenna,
Kalle Valo10509f92011-12-13 14:52:07 +02003468 .sched_scan_start = ath6kl_cfg80211_sscan_start,
3469 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303470 .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
Thomas Pedersen279b2862012-07-17 19:39:55 -07003471 .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,
Kalle Valobdcd8172011-07-18 00:22:30 +03003472};
3473
Kalle Valo7125f012011-12-13 14:51:37 +02003474void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02003475{
Kalle Valo10509f92011-12-13 14:52:07 +02003476 ath6kl_cfg80211_sscan_disable(vif);
3477
Kalle Valoec4b7f62011-11-01 08:44:04 +02003478 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02003479 case SME_DISCONNECTED:
3480 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02003481 case SME_CONNECTING:
3482 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
3483 NULL, 0,
3484 WLAN_STATUS_UNSPECIFIED_FAILURE,
3485 GFP_KERNEL);
3486 break;
3487 case SME_CONNECTED:
Johannes Berg80279fb2015-05-22 16:22:20 +02003488 cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003489 break;
3490 }
3491
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +05303492 if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
3493 (test_bit(CONNECTED, &vif->flags) ||
3494 test_bit(CONNECT_PEND, &vif->flags)))
Kalle Valo7125f012011-12-13 14:51:37 +02003495 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003496
3497 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02003498 clear_bit(CONNECTED, &vif->flags);
3499 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003500
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05303501 /* Stop netdev queues, needed during recovery */
3502 netif_stop_queue(vif->ndev);
3503 netif_carrier_off(vif->ndev);
3504
Kalle Valoec4b7f62011-11-01 08:44:04 +02003505 /* disable scanning */
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +05303506 if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
3507 ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
Kalle Valo7125f012011-12-13 14:51:37 +02003508 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
3509 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02003510
3511 ath6kl_cfg80211_scan_complete_event(vif, true);
3512}
3513
Kalle Valo7125f012011-12-13 14:51:37 +02003514void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
3515{
3516 struct ath6kl_vif *vif;
3517
3518 vif = ath6kl_vif_first(ar);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05303519 if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
Kalle Valo7125f012011-12-13 14:51:37 +02003520 /* save the current power mode before enabling power save */
3521 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
3522
3523 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
Kalle Valocdeb8602012-04-12 11:02:18 +03003524 ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n");
Kalle Valo7125f012011-12-13 14:51:37 +02003525 return;
3526 }
3527
3528 /*
3529 * FIXME: we should take ar->list_lock to protect changes in the
3530 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
3531 * sleeps.
3532 */
3533 list_for_each_entry(vif, &ar->vif_list, list)
3534 ath6kl_cfg80211_stop(vif);
3535}
3536
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003537static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
3538 struct regulatory_request *request)
Kalle Valo84841ba2012-07-19 16:00:56 +03003539{
3540 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg57fbcce2016-04-12 15:56:15 +02003541 u32 rates[NUM_NL80211_BANDS];
Kalle Valo84841ba2012-07-19 16:00:56 +03003542 int ret, i;
3543
3544 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
Kalle Valoff7e6862012-11-15 16:34:56 +02003545 "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
Kalle Valo84841ba2012-07-19 16:00:56 +03003546 request->alpha2[0], request->alpha2[1],
3547 request->intersect ? " intersect" : "",
3548 request->processed ? " processed" : "",
Kalle Valoff7e6862012-11-15 16:34:56 +02003549 request->initiator, request->user_reg_hint_type);
3550
Kalle Valoff7e6862012-11-15 16:34:56 +02003551 if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003552 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003553
3554 ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
3555 if (ret) {
3556 ath6kl_err("failed to set regdomain: %d\n", ret);
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003557 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003558 }
3559
3560 /*
3561 * Firmware will apply the regdomain change only after a scan is
3562 * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been
3563 * changed.
3564 */
3565
Johannes Berg57fbcce2016-04-12 15:56:15 +02003566 for (i = 0; i < NUM_NL80211_BANDS; i++)
Kalle Valo84841ba2012-07-19 16:00:56 +03003567 if (wiphy->bands[i])
3568 rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
3569
3570
3571 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false,
3572 false, 0, ATH6KL_FG_SCAN_INTERVAL,
3573 0, NULL, false, rates);
3574 if (ret) {
3575 ath6kl_err("failed to start scan for a regdomain change: %d\n",
3576 ret);
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003577 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003578 }
Kalle Valo84841ba2012-07-19 16:00:56 +03003579}
3580
Kalle Valoc25889e2012-01-17 20:08:27 +02003581static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03003582{
Vasanthakumar Thiagarajan7baef812012-01-21 15:22:50 +05303583 vif->aggr_cntxt = aggr_init(vif);
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303584 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303585 ath6kl_err("failed to initialize aggr\n");
3586 return -ENOMEM;
3587 }
Kalle Valobdcd8172011-07-18 00:22:30 +03003588
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303589 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303590 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02003591 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
3592 (unsigned long) vif);
3593
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303594 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05303595 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303596
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303597 INIT_LIST_HEAD(&vif->mc_filter);
3598
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303599 return 0;
3600}
3601
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05303602void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
3603{
3604 static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3605 bool discon_issued;
3606
3607 netif_stop_queue(vif->ndev);
3608
3609 clear_bit(WLAN_ENABLED, &vif->flags);
3610
3611 if (wmi_ready) {
3612 discon_issued = test_bit(CONNECTED, &vif->flags) ||
3613 test_bit(CONNECT_PEND, &vif->flags);
3614 ath6kl_disconnect(vif);
3615 del_timer(&vif->disconnect_timer);
3616
3617 if (discon_issued)
3618 ath6kl_disconnect_event(vif, DISCONNECT_CMD,
3619 (vif->nw_type & AP_NETWORK) ?
3620 bcast_mac : vif->bssid,
3621 0, NULL, 0);
3622 }
3623
3624 if (vif->scan_req) {
Avraham Stern1d762502016-07-05 17:10:13 +03003625 struct cfg80211_scan_info info = {
3626 .aborted = true,
3627 };
3628
3629 cfg80211_scan_done(vif->scan_req, &info);
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05303630 vif->scan_req = NULL;
3631 }
3632
3633 /* need to clean up enhanced bmiss detection fw state */
3634 ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
3635}
3636
Kalle Valoc25889e2012-01-17 20:08:27 +02003637void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303638{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303639 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303640 struct ath6kl_mc_filter *mc_filter, *tmp;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303641
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303642 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303643
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303644 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
3645
3646 if (vif->nw_type == ADHOC_NETWORK)
3647 ar->ibss_if_active = false;
3648
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303649 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
3650 list_del(&mc_filter->list);
3651 kfree(mc_filter);
3652 }
3653
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303654 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303655
3656 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303657}
3658
Ben Greear13eff532015-10-22 09:07:39 -07003659static const char ath6kl_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
3660 /* Common stats names used by many drivers. */
3661 "tx_pkts_nic", "tx_bytes_nic", "rx_pkts_nic", "rx_bytes_nic",
3662
3663 /* TX stats. */
3664 "d_tx_ucast_pkts", "d_tx_bcast_pkts",
3665 "d_tx_ucast_bytes", "d_tx_bcast_bytes",
3666 "d_tx_rts_ok", "d_tx_error", "d_tx_fail",
3667 "d_tx_retry", "d_tx_multi_retry", "d_tx_rts_fail",
3668 "d_tx_tkip_counter_measures",
3669
3670 /* RX Stats. */
3671 "d_rx_ucast_pkts", "d_rx_ucast_rate", "d_rx_bcast_pkts",
3672 "d_rx_ucast_bytes", "d_rx_bcast_bytes", "d_rx_frag_pkt",
3673 "d_rx_error", "d_rx_crc_err", "d_rx_keycache_miss",
3674 "d_rx_decrypt_crc_err", "d_rx_duplicate_frames",
3675 "d_rx_mic_err", "d_rx_tkip_format_err", "d_rx_ccmp_format_err",
3676 "d_rx_ccmp_replay_err",
3677
3678 /* Misc stats. */
3679 "d_beacon_miss", "d_num_connects", "d_num_disconnects",
3680 "d_beacon_avg_rssi", "d_arp_received", "d_arp_matched",
3681 "d_arp_replied"
3682};
3683
3684#define ATH6KL_STATS_LEN ARRAY_SIZE(ath6kl_gstrings_sta_stats)
3685
3686static int ath6kl_get_sset_count(struct net_device *dev, int sset)
3687{
3688 int rv = 0;
3689
3690 if (sset == ETH_SS_STATS)
3691 rv += ATH6KL_STATS_LEN;
3692
3693 if (rv == 0)
3694 return -EOPNOTSUPP;
3695 return rv;
3696}
3697
3698static void ath6kl_get_stats(struct net_device *dev,
3699 struct ethtool_stats *stats,
3700 u64 *data)
3701{
3702 struct ath6kl_vif *vif = netdev_priv(dev);
3703 struct ath6kl *ar = vif->ar;
3704 int i = 0;
3705 struct target_stats *tgt_stats;
3706
3707 memset(data, 0, sizeof(u64) * ATH6KL_STATS_LEN);
3708
3709 ath6kl_read_tgt_stats(ar, vif);
3710
3711 tgt_stats = &vif->target_stats;
3712
3713 data[i++] = tgt_stats->tx_ucast_pkt + tgt_stats->tx_bcast_pkt;
3714 data[i++] = tgt_stats->tx_ucast_byte + tgt_stats->tx_bcast_byte;
3715 data[i++] = tgt_stats->rx_ucast_pkt + tgt_stats->rx_bcast_pkt;
3716 data[i++] = tgt_stats->rx_ucast_byte + tgt_stats->rx_bcast_byte;
3717
3718 data[i++] = tgt_stats->tx_ucast_pkt;
3719 data[i++] = tgt_stats->tx_bcast_pkt;
3720 data[i++] = tgt_stats->tx_ucast_byte;
3721 data[i++] = tgt_stats->tx_bcast_byte;
3722 data[i++] = tgt_stats->tx_rts_success_cnt;
3723 data[i++] = tgt_stats->tx_err;
3724 data[i++] = tgt_stats->tx_fail_cnt;
3725 data[i++] = tgt_stats->tx_retry_cnt;
3726 data[i++] = tgt_stats->tx_mult_retry_cnt;
3727 data[i++] = tgt_stats->tx_rts_fail_cnt;
3728 data[i++] = tgt_stats->tkip_cnter_measures_invoked;
3729
3730 data[i++] = tgt_stats->rx_ucast_pkt;
3731 data[i++] = tgt_stats->rx_ucast_rate;
3732 data[i++] = tgt_stats->rx_bcast_pkt;
3733 data[i++] = tgt_stats->rx_ucast_byte;
3734 data[i++] = tgt_stats->rx_bcast_byte;
3735 data[i++] = tgt_stats->rx_frgment_pkt;
3736 data[i++] = tgt_stats->rx_err;
3737 data[i++] = tgt_stats->rx_crc_err;
3738 data[i++] = tgt_stats->rx_key_cache_miss;
3739 data[i++] = tgt_stats->rx_decrypt_err;
3740 data[i++] = tgt_stats->rx_dupl_frame;
3741 data[i++] = tgt_stats->tkip_local_mic_fail;
3742 data[i++] = tgt_stats->tkip_fmt_err;
3743 data[i++] = tgt_stats->ccmp_fmt_err;
3744 data[i++] = tgt_stats->ccmp_replays;
3745
3746 data[i++] = tgt_stats->cs_bmiss_cnt;
3747 data[i++] = tgt_stats->cs_connect_cnt;
3748 data[i++] = tgt_stats->cs_discon_cnt;
3749 data[i++] = tgt_stats->cs_ave_beacon_rssi;
3750 data[i++] = tgt_stats->arp_received;
3751 data[i++] = tgt_stats->arp_matched;
3752 data[i++] = tgt_stats->arp_replied;
3753
3754 if (i != ATH6KL_STATS_LEN) {
3755 WARN_ON_ONCE(1);
3756 ath6kl_err("ethtool stats error, i: %d STATS_LEN: %d\n",
3757 i, (int)ATH6KL_STATS_LEN);
3758 }
3759}
3760
3761/* These stats are per NIC, not really per vdev, so we just ignore dev. */
3762static void ath6kl_get_strings(struct net_device *dev, u32 sset, u8 *data)
3763{
3764 int sz_sta_stats = 0;
3765
3766 if (sset == ETH_SS_STATS) {
3767 sz_sta_stats = sizeof(ath6kl_gstrings_sta_stats);
3768 memcpy(data, ath6kl_gstrings_sta_stats, sz_sta_stats);
3769 }
3770}
3771
3772static const struct ethtool_ops ath6kl_ethtool_ops = {
3773 .get_drvinfo = cfg80211_get_drvinfo,
3774 .get_link = ethtool_op_get_link,
3775 .get_strings = ath6kl_get_strings,
3776 .get_ethtool_stats = ath6kl_get_stats,
3777 .get_sset_count = ath6kl_get_sset_count,
3778};
3779
Johannes Berg552bff02012-09-19 09:26:06 +02003780struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +01003781 unsigned char name_assign_type,
Johannes Berg84efbb82012-06-16 00:00:26 +02003782 enum nl80211_iftype type,
3783 u8 fw_vif_idx, u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303784{
3785 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303786 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303787
Tom Gundersen6bab2e192015-03-18 11:13:39 +01003788 ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303789 if (!ndev)
3790 return NULL;
3791
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303792 vif = netdev_priv(ndev);
3793 ndev->ieee80211_ptr = &vif->wdev;
3794 vif->wdev.wiphy = ar->wiphy;
3795 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303796 vif->ndev = ndev;
3797 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
3798 vif->wdev.netdev = ndev;
3799 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303800 vif->fw_vif_idx = fw_vif_idx;
Kalle Valod0d670a2012-03-07 20:03:58 +02003801 vif->nw_type = nw_type;
3802 vif->next_mode = nw_type;
Raja Mani8f46fcc2012-02-20 19:08:07 +05303803 vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
Raja Manice0dc0c2012-02-20 19:08:08 +05303804 vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
Raja Manieb389872012-04-16 16:09:56 +05303805 vif->bg_scan_period = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02003806 vif->htcap[NL80211_BAND_2GHZ].ht_enable = true;
3807 vif->htcap[NL80211_BAND_5GHZ].ht_enable = true;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303808
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303809 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
Aarthi Thiruvengadamc95dcb52012-07-10 13:20:40 -07003810 if (fw_vif_idx != 0) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303811 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
3812 0x2;
Aarthi Thiruvengadamc95dcb52012-07-10 13:20:40 -07003813 if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
3814 ar->fw_capabilities))
3815 ndev->dev_addr[4] ^= 0x80;
3816 }
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303817
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303818 init_netdev(ndev);
3819
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05303820 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303821
Kalle Valoc25889e2012-01-17 20:08:27 +02003822 if (ath6kl_cfg80211_vif_init(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303823 goto err;
3824
Ben Greear13eff532015-10-22 09:07:39 -07003825 netdev_set_default_ethtool_ops(ndev, &ath6kl_ethtool_ops);
3826
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303827 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303828 goto err;
3829
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303830 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05303831 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05303832 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303833 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303834
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303835 if (type == NL80211_IFTYPE_ADHOC)
3836 ar->ibss_if_active = true;
3837
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303838 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303839 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303840 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303841
Johannes Berg84efbb82012-06-16 00:00:26 +02003842 return &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303843
3844err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303845 aggr_module_destroy(vif->aggr_cntxt);
3846 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303847 return NULL;
3848}
3849
Johannes Berg964dc9e2013-06-03 17:25:34 +02003850#ifdef CONFIG_PM
3851static const struct wiphy_wowlan_support ath6kl_wowlan_support = {
3852 .flags = WIPHY_WOWLAN_MAGIC_PKT |
3853 WIPHY_WOWLAN_DISCONNECT |
3854 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
3855 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
3856 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
3857 WIPHY_WOWLAN_4WAY_HANDSHAKE,
3858 .n_patterns = WOW_MAX_FILTERS_PER_LIST,
3859 .pattern_min_len = 1,
3860 .pattern_max_len = WOW_PATTERN_SIZE,
3861};
3862#endif
3863
Kalle Valo46d33a22012-01-17 20:08:40 +02003864int ath6kl_cfg80211_init(struct ath6kl *ar)
3865{
3866 struct wiphy *wiphy = ar->wiphy;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003867 bool band_2gig = false, band_5gig = false, ht = false;
Kalle Valo46d33a22012-01-17 20:08:40 +02003868 int ret;
3869
3870 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
3871
3872 wiphy->max_remain_on_channel_duration = 5000;
3873
3874 /* set device pointer for wiphy */
3875 set_wiphy_dev(wiphy, ar->dev);
3876
3877 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3878 BIT(NL80211_IFTYPE_ADHOC) |
3879 BIT(NL80211_IFTYPE_AP);
3880 if (ar->p2p) {
3881 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
3882 BIT(NL80211_IFTYPE_P2P_CLIENT);
3883 }
3884
Kalle Valo84841ba2012-07-19 16:00:56 +03003885 if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) &&
Kalle Valoff7e6862012-11-15 16:34:56 +02003886 test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
Kalle Valo84841ba2012-07-19 16:00:56 +03003887 wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
Kalle Valoff7e6862012-11-15 16:34:56 +02003888 ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
3889 }
Kalle Valo84841ba2012-07-19 16:00:56 +03003890
Kalle Valo46d33a22012-01-17 20:08:40 +02003891 /* max num of ssids that can be probed during scanning */
Jouni Malinen8ab54152012-05-09 22:14:51 +03003892 wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
Naveen Singhdd45b752012-05-16 13:29:00 +03003893
3894 /* max num of ssids that can be matched after scan */
3895 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
3896 ar->fw_capabilities))
3897 wiphy->max_match_sets = MAX_PROBED_SSIDS;
3898
Kalle Valo46d33a22012-01-17 20:08:40 +02003899 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Thomas Pedersend92917e2012-04-19 15:31:56 -07003900 switch (ar->hw.cap) {
3901 case WMI_11AN_CAP:
3902 ht = true;
3903 case WMI_11A_CAP:
3904 band_5gig = true;
3905 break;
3906 case WMI_11GN_CAP:
3907 ht = true;
3908 case WMI_11G_CAP:
3909 band_2gig = true;
3910 break;
3911 case WMI_11AGN_CAP:
3912 ht = true;
3913 case WMI_11AG_CAP:
3914 band_2gig = true;
3915 band_5gig = true;
3916 break;
3917 default:
3918 ath6kl_err("invalid phy capability!\n");
3919 return -EINVAL;
3920 }
3921
Vasanthakumar Thiagarajan7fd1ce72012-04-25 12:38:18 +05303922 /*
3923 * Even if the fw has HT support, advertise HT cap only when
3924 * the firmware has support to override RSN capability, otherwise
3925 * 4-way handshake would fail.
3926 */
3927 if (!(ht &&
3928 test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
3929 ar->fw_capabilities))) {
Thomas Pedersend92917e2012-04-19 15:31:56 -07003930 ath6kl_band_2ghz.ht_cap.cap = 0;
3931 ath6kl_band_2ghz.ht_cap.ht_supported = false;
3932 ath6kl_band_5ghz.ht_cap.cap = 0;
3933 ath6kl_band_5ghz.ht_cap.ht_supported = false;
Ben Greear7fd98522015-10-21 14:53:20 -07003934
3935 if (ht)
3936 ath6kl_err("Firmware lacks RSN-CAP-OVERRIDE, so HT (802.11n) is disabled.");
Thomas Pedersend92917e2012-04-19 15:31:56 -07003937 }
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303938
Kalle Valoeba95bc2014-06-17 12:40:52 +03003939 if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
3940 ar->fw_capabilities)) {
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303941 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3942 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3943 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
3944 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
Ben Greear26ca14d2015-11-30 15:01:47 -08003945 ar->hw.tx_ant = 0x3; /* mask, 2 antenna */
3946 ar->hw.rx_ant = 0x3;
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303947 } else {
3948 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3949 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
Ben Greear9c2e90f2015-10-21 14:53:19 -07003950 ar->hw.tx_ant = 1;
3951 ar->hw.rx_ant = 1;
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303952 }
3953
Ben Greear9c2e90f2015-10-21 14:53:19 -07003954 wiphy->available_antennas_tx = ar->hw.tx_ant;
3955 wiphy->available_antennas_rx = ar->hw.rx_ant;
3956
Thomas Pedersend92917e2012-04-19 15:31:56 -07003957 if (band_2gig)
Johannes Berg57fbcce2016-04-12 15:56:15 +02003958 wiphy->bands[NL80211_BAND_2GHZ] = &ath6kl_band_2ghz;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003959 if (band_5gig)
Johannes Berg57fbcce2016-04-12 15:56:15 +02003960 wiphy->bands[NL80211_BAND_5GHZ] = &ath6kl_band_5ghz;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003961
Kalle Valo46d33a22012-01-17 20:08:40 +02003962 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3963
3964 wiphy->cipher_suites = cipher_suites;
3965 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3966
Johannes Bergdfb89c52012-06-27 09:23:48 +02003967#ifdef CONFIG_PM
Johannes Berg964dc9e2013-06-03 17:25:34 +02003968 wiphy->wowlan = &ath6kl_wowlan_support;
Johannes Bergdfb89c52012-06-27 09:23:48 +02003969#endif
Kalle Valo46d33a22012-01-17 20:08:40 +02003970
Jouni Malinen8ab54152012-05-09 22:14:51 +03003971 wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
Kalle Valo46d33a22012-01-17 20:08:40 +02003972
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303973 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
3974 WIPHY_FLAG_HAVE_AP_SME |
3975 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
3976 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
3977
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003978 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303979 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
3980
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05303981 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
3982 ar->fw_capabilities))
Johannes Bergb2922192012-10-12 10:55:53 +02003983 ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05303984
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303985 ar->wiphy->probe_resp_offload =
3986 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
3987 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
Jouni Malinena432e7c2012-04-16 19:25:35 +03003988 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303989
Kalle Valo46d33a22012-01-17 20:08:40 +02003990 ret = wiphy_register(wiphy);
3991 if (ret < 0) {
3992 ath6kl_err("couldn't register wiphy device\n");
3993 return ret;
3994 }
3995
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05303996 ar->wiphy_registered = true;
3997
Kalle Valo46d33a22012-01-17 20:08:40 +02003998 return 0;
3999}
4000
4001void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05304002{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05304003 wiphy_unregister(ar->wiphy);
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05304004
4005 ar->wiphy_registered = false;
Kalle Valo45eaa782012-01-17 20:09:05 +02004006}
Kalle Valo46d33a22012-01-17 20:08:40 +02004007
Kalle Valo45eaa782012-01-17 20:09:05 +02004008struct ath6kl *ath6kl_cfg80211_create(void)
4009{
4010 struct ath6kl *ar;
4011 struct wiphy *wiphy;
4012
4013 /* create a new wiphy for use with cfg80211 */
4014 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
4015
4016 if (!wiphy) {
4017 ath6kl_err("couldn't allocate wiphy device\n");
4018 return NULL;
4019 }
4020
4021 ar = wiphy_priv(wiphy);
4022 ar->wiphy = wiphy;
4023
4024 return ar;
4025}
4026
4027/* Note: ar variable must not be accessed after calling this! */
4028void ath6kl_cfg80211_destroy(struct ath6kl *ar)
4029{
Vasanthakumar Thiagarajan1d2a4452012-01-21 15:22:53 +05304030 int i;
4031
4032 for (i = 0; i < AP_MAX_NUM_STA; i++)
4033 kfree(ar->sta_list[i].aggr_conn);
4034
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05304035 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03004036}
Kalle Valo45eaa782012-01-17 20:09:05 +02004037