blob: 1906412afa70bf663edb469a4499c322c0bc1f01 [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>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010023#include <linux/sched/signal.h>
Paul Gortmaker6eb07ca2011-09-15 19:46:05 -040024
Kalle Valobdcd8172011-07-18 00:22:30 +030025#include "core.h"
26#include "cfg80211.h"
27#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030028#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030029#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030030
31#define RATETAB_ENT(_rate, _rateid, _flags) { \
32 .bitrate = (_rate), \
33 .flags = (_flags), \
34 .hw_value = (_rateid), \
35}
36
37#define CHAN2G(_channel, _freq, _flags) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +020038 .band = NL80211_BAND_2GHZ, \
Kalle Valobdcd8172011-07-18 00:22:30 +030039 .hw_value = (_channel), \
40 .center_freq = (_freq), \
41 .flags = (_flags), \
42 .max_antenna_gain = 0, \
43 .max_power = 30, \
44}
45
46#define CHAN5G(_channel, _flags) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +020047 .band = NL80211_BAND_5GHZ, \
Kalle Valobdcd8172011-07-18 00:22:30 +030048 .hw_value = (_channel), \
49 .center_freq = 5000 + (5 * (_channel)), \
50 .flags = (_flags), \
51 .max_antenna_gain = 0, \
52 .max_power = 30, \
53}
54
Bala Shanmugamf5993592012-03-27 12:17:32 +053055#define DEFAULT_BG_SCAN_PERIOD 60
56
Naveen Singhdd45b752012-05-16 13:29:00 +030057struct ath6kl_cfg80211_match_probe_ssid {
58 struct cfg80211_ssid ssid;
59 u8 flag;
60};
61
Kalle Valobdcd8172011-07-18 00:22:30 +030062static struct ieee80211_rate ath6kl_rates[] = {
63 RATETAB_ENT(10, 0x1, 0),
64 RATETAB_ENT(20, 0x2, 0),
65 RATETAB_ENT(55, 0x4, 0),
66 RATETAB_ENT(110, 0x8, 0),
67 RATETAB_ENT(60, 0x10, 0),
68 RATETAB_ENT(90, 0x20, 0),
69 RATETAB_ENT(120, 0x40, 0),
70 RATETAB_ENT(180, 0x80, 0),
71 RATETAB_ENT(240, 0x100, 0),
72 RATETAB_ENT(360, 0x200, 0),
73 RATETAB_ENT(480, 0x400, 0),
74 RATETAB_ENT(540, 0x800, 0),
75};
76
77#define ath6kl_a_rates (ath6kl_rates + 4)
78#define ath6kl_a_rates_size 8
79#define ath6kl_g_rates (ath6kl_rates + 0)
80#define ath6kl_g_rates_size 12
81
Vasanthakumar Thiagarajanbed56e32012-04-09 19:03:57 +053082#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20
83#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +053084 IEEE80211_HT_CAP_SGI_20 | \
85 IEEE80211_HT_CAP_SGI_40)
86
Kalle Valobdcd8172011-07-18 00:22:30 +030087static struct ieee80211_channel ath6kl_2ghz_channels[] = {
88 CHAN2G(1, 2412, 0),
89 CHAN2G(2, 2417, 0),
90 CHAN2G(3, 2422, 0),
91 CHAN2G(4, 2427, 0),
92 CHAN2G(5, 2432, 0),
93 CHAN2G(6, 2437, 0),
94 CHAN2G(7, 2442, 0),
95 CHAN2G(8, 2447, 0),
96 CHAN2G(9, 2452, 0),
97 CHAN2G(10, 2457, 0),
98 CHAN2G(11, 2462, 0),
99 CHAN2G(12, 2467, 0),
100 CHAN2G(13, 2472, 0),
101 CHAN2G(14, 2484, 0),
102};
103
104static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
Rostyslav Khudoliib51040f2017-03-16 11:22:17 +0200105 CHAN5G(36, 0), CHAN5G(40, 0),
106 CHAN5G(44, 0), CHAN5G(48, 0),
Kalle Valobdcd8172011-07-18 00:22:30 +0300107 CHAN5G(52, 0), CHAN5G(56, 0),
108 CHAN5G(60, 0), CHAN5G(64, 0),
109 CHAN5G(100, 0), CHAN5G(104, 0),
110 CHAN5G(108, 0), CHAN5G(112, 0),
111 CHAN5G(116, 0), CHAN5G(120, 0),
112 CHAN5G(124, 0), CHAN5G(128, 0),
113 CHAN5G(132, 0), CHAN5G(136, 0),
114 CHAN5G(140, 0), CHAN5G(149, 0),
115 CHAN5G(153, 0), CHAN5G(157, 0),
116 CHAN5G(161, 0), CHAN5G(165, 0),
117 CHAN5G(184, 0), CHAN5G(188, 0),
118 CHAN5G(192, 0), CHAN5G(196, 0),
119 CHAN5G(200, 0), CHAN5G(204, 0),
120 CHAN5G(208, 0), CHAN5G(212, 0),
121 CHAN5G(216, 0),
122};
123
124static struct ieee80211_supported_band ath6kl_band_2ghz = {
125 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
126 .channels = ath6kl_2ghz_channels,
127 .n_bitrates = ath6kl_g_rates_size,
128 .bitrates = ath6kl_g_rates,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530129 .ht_cap.cap = ath6kl_g_htcap,
130 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300131};
132
133static struct ieee80211_supported_band ath6kl_band_5ghz = {
134 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
135 .channels = ath6kl_5ghz_a_channels,
136 .n_bitrates = ath6kl_a_rates_size,
137 .bitrates = ath6kl_a_rates,
Vasanthakumar Thiagarajanbed56e32012-04-09 19:03:57 +0530138 .ht_cap.cap = ath6kl_a_htcap,
Vasanthakumar Thiagarajanfaaf1922012-02-27 11:44:19 +0530139 .ht_cap.ht_supported = true,
Kalle Valobdcd8172011-07-18 00:22:30 +0300140};
141
Jouni Malinen837cb972011-10-11 17:31:57 +0300142#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
143
Kalle Valo10509f92011-12-13 14:52:07 +0200144/* returns true if scheduled scan was stopped */
145static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
146{
147 struct ath6kl *ar = vif->ar;
148
Thomas Pedersenb1f47e32012-08-15 16:51:24 -0700149 if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))
Kalle Valo10509f92011-12-13 14:52:07 +0200150 return false;
151
152 del_timer_sync(&vif->sched_scan_timer);
153
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +0530154 if (ar->state == ATH6KL_STATE_RECOVERY)
155 return true;
Kalle Valo10509f92011-12-13 14:52:07 +0200156
Thomas Pedersenb1f47e32012-08-15 16:51:24 -0700157 ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
Kalle Valo10509f92011-12-13 14:52:07 +0200158
159 return true;
160}
161
162static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
163{
164 struct ath6kl *ar = vif->ar;
165 bool stopped;
166
167 stopped = __ath6kl_cfg80211_sscan_stop(vif);
168
169 if (!stopped)
170 return;
171
172 cfg80211_sched_scan_stopped(ar->wiphy);
173}
174
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530175static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300176 enum nl80211_wpa_versions wpa_version)
177{
178 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
179
180 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530181 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300182 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530183 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300184 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530185 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300186 } else {
187 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
188 return -ENOTSUPP;
189 }
190
191 return 0;
192}
193
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530194static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300195 enum nl80211_auth_type auth_type)
196{
Kalle Valobdcd8172011-07-18 00:22:30 +0300197 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
198
199 switch (auth_type) {
200 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530201 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300202 break;
203 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530204 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300205 break;
206 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530207 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300208 break;
209
210 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530211 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300212 break;
213
214 default:
Masanari Iida3c325fb2012-01-31 23:32:55 +0900215 ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300216 return -ENOTSUPP;
217 }
218
219 return 0;
220}
221
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530222static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300223{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530224 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
225 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
226 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300227
228 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
229 __func__, cipher, ucast);
230
231 switch (cipher) {
232 case 0:
233 /* our own hack to use value 0 as no crypto used */
234 *ar_cipher = NONE_CRYPT;
235 *ar_cipher_len = 0;
236 break;
237 case WLAN_CIPHER_SUITE_WEP40:
238 *ar_cipher = WEP_CRYPT;
239 *ar_cipher_len = 5;
240 break;
241 case WLAN_CIPHER_SUITE_WEP104:
242 *ar_cipher = WEP_CRYPT;
243 *ar_cipher_len = 13;
244 break;
245 case WLAN_CIPHER_SUITE_TKIP:
246 *ar_cipher = TKIP_CRYPT;
247 *ar_cipher_len = 0;
248 break;
249 case WLAN_CIPHER_SUITE_CCMP:
250 *ar_cipher = AES_CRYPT;
251 *ar_cipher_len = 0;
252 break;
Dai Shuibing5e070212011-11-03 11:39:37 +0200253 case WLAN_CIPHER_SUITE_SMS4:
254 *ar_cipher = WAPI_CRYPT;
255 *ar_cipher_len = 0;
256 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300257 default:
258 ath6kl_err("cipher 0x%x not supported\n", cipher);
259 return -ENOTSUPP;
260 }
261
262 return 0;
263}
264
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530265static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300266{
267 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
268
269 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530270 if (vif->auth_mode == WPA_AUTH)
271 vif->auth_mode = WPA_PSK_AUTH;
272 else if (vif->auth_mode == WPA2_AUTH)
273 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300274 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530275 if (vif->auth_mode == WPA_AUTH)
276 vif->auth_mode = WPA_AUTH_CCKM;
277 else if (vif->auth_mode == WPA2_AUTH)
278 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300279 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530280 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300281 }
282}
283
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530284static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300285{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530286 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530287
Kalle Valobdcd8172011-07-18 00:22:30 +0300288 if (!test_bit(WMI_READY, &ar->flag)) {
289 ath6kl_err("wmi is not ready\n");
290 return false;
291 }
292
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530293 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300294 ath6kl_err("wlan disabled\n");
295 return false;
296 }
297
298 return true;
299}
300
Kevin Fang6981ffd2011-10-07 08:51:19 +0800301static bool ath6kl_is_wpa_ie(const u8 *pos)
302{
Arend van Spriel04b23122012-10-12 12:28:14 +0200303 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
Kevin Fang6981ffd2011-10-07 08:51:19 +0800304 pos[2] == 0x00 && pos[3] == 0x50 &&
305 pos[4] == 0xf2 && pos[5] == 0x01;
306}
307
308static bool ath6kl_is_rsn_ie(const u8 *pos)
309{
310 return pos[0] == WLAN_EID_RSN;
311}
312
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700313static bool ath6kl_is_wps_ie(const u8 *pos)
314{
315 return (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
316 pos[1] >= 4 &&
317 pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 &&
318 pos[5] == 0x04);
319}
320
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530321static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
322 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800323{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530324 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800325 const u8 *pos;
326 u8 *buf = NULL;
327 size_t len = 0;
328 int ret;
329
330 /*
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700331 * Clear previously set flag
332 */
333
334 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
335
336 /*
Kevin Fang6981ffd2011-10-07 08:51:19 +0800337 * Filter out RSN/WPA IE(s)
338 */
339
340 if (ies && ies_len) {
341 buf = kmalloc(ies_len, GFP_KERNEL);
342 if (buf == NULL)
343 return -ENOMEM;
344 pos = ies;
345
346 while (pos + 1 < ies + ies_len) {
347 if (pos + 2 + pos[1] > ies + ies_len)
348 break;
349 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
350 memcpy(buf + len, pos, 2 + pos[1]);
351 len += 2 + pos[1];
352 }
Aarthi Thiruvengadam63541212011-10-25 11:25:52 -0700353
354 if (ath6kl_is_wps_ie(pos))
355 ar->connect_ctrl_flags |= CONNECT_WPS_FLAG;
356
Kevin Fang6981ffd2011-10-07 08:51:19 +0800357 pos += 2 + pos[1];
358 }
359 }
360
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530361 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
362 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800363 kfree(buf);
364 return ret;
365}
366
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530367static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
368{
369 switch (type) {
370 case NL80211_IFTYPE_STATION:
Mohammed Shafi Shajakhan38142642012-08-24 19:53:28 +0530371 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530372 *nw_type = INFRA_NETWORK;
373 break;
374 case NL80211_IFTYPE_ADHOC:
375 *nw_type = ADHOC_NETWORK;
376 break;
377 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530378 case NL80211_IFTYPE_P2P_GO:
379 *nw_type = AP_NETWORK;
380 break;
381 default:
382 ath6kl_err("invalid interface type %u\n", type);
383 return -ENOTSUPP;
384 }
385
386 return 0;
387}
388
389static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
390 u8 *if_idx, u8 *nw_type)
391{
392 int i;
393
394 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
395 return false;
396
397 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
Kalle Valo96f1fad2012-03-07 20:03:57 +0200398 ar->num_vif))
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530399 return false;
400
401 if (type == NL80211_IFTYPE_STATION ||
402 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200403 for (i = 0; i < ar->vif_max; i++) {
Mohammed Shafi Shajakhan0db96de2013-02-22 20:19:55 +0530404 if ((ar->avail_idx_map) & BIT(i)) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530405 *if_idx = i;
406 return true;
407 }
408 }
409 }
410
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530411 if (type == NL80211_IFTYPE_P2P_CLIENT ||
412 type == NL80211_IFTYPE_P2P_GO) {
Kalle Valo71f96ee2011-11-14 19:31:30 +0200413 for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
Mohammed Shafi Shajakhan0db96de2013-02-22 20:19:55 +0530414 if ((ar->avail_idx_map) & BIT(i)) {
Vasanthakumar Thiagarajan3226f68a2011-10-25 19:34:24 +0530415 *if_idx = i;
416 return true;
417 }
418 }
419 }
420
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530421 return false;
422}
423
Kalle Valo8c9bb052012-03-07 20:04:00 +0200424static bool ath6kl_is_tx_pending(struct ath6kl *ar)
425{
426 return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
427}
428
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +0530429static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif,
430 bool enable)
431{
432 int err;
433
434 if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
435 return;
436
437 if (vif->nw_type != INFRA_NETWORK)
438 return;
439
440 if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
441 vif->ar->fw_capabilities))
442 return;
443
444 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
445 enable ? "enable" : "disable");
446
447 err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
448 vif->fw_vif_idx, enable);
449 if (err)
450 ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
451 enable ? "enable" : "disable", err);
452}
Kalle Valo8c9bb052012-03-07 20:04:00 +0200453
Kalle Valobdcd8172011-07-18 00:22:30 +0300454static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
455 struct cfg80211_connect_params *sme)
456{
457 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530458 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300459 int status;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800460 u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
Raja Manice0dc0c2012-02-20 19:08:08 +0530461 u16 interval;
Kalle Valobdcd8172011-07-18 00:22:30 +0300462
Kalle Valo10509f92011-12-13 14:52:07 +0200463 ath6kl_cfg80211_sscan_disable(vif);
464
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530465 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300466
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530467 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300468 return -EIO;
469
470 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
471 ath6kl_err("destroy in progress\n");
472 return -EBUSY;
473 }
474
475 if (test_bit(SKIP_SCAN, &ar->flag) &&
476 ((sme->channel && sme->channel->center_freq == 0) ||
477 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
478 ath6kl_err("SkipScan: channel or bssid invalid\n");
479 return -EINVAL;
480 }
481
482 if (down_interruptible(&ar->sem)) {
483 ath6kl_err("busy, couldn't get access\n");
484 return -ERESTARTSYS;
485 }
486
487 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
488 ath6kl_err("busy, destroy in progress\n");
489 up(&ar->sem);
490 return -EBUSY;
491 }
492
493 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
494 /*
495 * sleep until the command queue drains
496 */
497 wait_event_interruptible_timeout(ar->event_wq,
Kalle Valo8c9bb052012-03-07 20:04:00 +0200498 ath6kl_is_tx_pending(ar),
499 WMI_TIMEOUT);
Kalle Valobdcd8172011-07-18 00:22:30 +0300500 if (signal_pending(current)) {
501 ath6kl_err("cmd queue drain timeout\n");
502 up(&ar->sem);
503 return -EINTR;
504 }
505 }
506
Jouni Malinen6e786cb2011-12-15 14:16:00 +0200507 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
508 if (status) {
509 up(&ar->sem);
510 return status;
511 }
512
513 if (sme->ie == NULL || sme->ie_len == 0)
Raja Mani542c5192011-11-15 14:14:56 +0530514 ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800515
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530516 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530517 vif->ssid_len == sme->ssid_len &&
518 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530519 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530520 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
521 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530522 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300523
524 up(&ar->sem);
525 if (status) {
526 ath6kl_err("wmi_reconnect_cmd failed\n");
527 return -EIO;
528 }
529 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530530 } else if (vif->ssid_len == sme->ssid_len &&
531 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530532 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300533 }
534
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530535 memset(vif->ssid, 0, sizeof(vif->ssid));
536 vif->ssid_len = sme->ssid_len;
537 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300538
539 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530540 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300541
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530542 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300543 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530544 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300545
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530546 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300547
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530548 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300549 if (status) {
550 up(&ar->sem);
551 return status;
552 }
553
554 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530555 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300556 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530557 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300558
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530559 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300560
561 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530562 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300563
564 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530565 (vif->auth_mode == NONE_AUTH) &&
566 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300567 struct ath6kl_key *key = NULL;
568
Vivek Natarajan792ecb32011-12-29 16:18:39 +0530569 if (sme->key_idx > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300570 ath6kl_err("key index %d out of bounds\n",
571 sme->key_idx);
572 up(&ar->sem);
573 return -ENOENT;
574 }
575
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530576 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300577 key->key_len = sme->key_len;
578 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530579 key->cipher = vif->prwise_crypto;
580 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300581
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530582 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530583 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300584 GROUP_USAGE | TX_USAGE,
585 key->key_len,
Jouni Malinenf4bb9a62011-11-02 23:45:55 +0200586 NULL, 0,
Kalle Valobdcd8172011-07-18 00:22:30 +0300587 key->key, KEY_OP_INIT_VAL, NULL,
588 NO_SYNC_WMIFLAG);
589 }
590
591 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530592 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530593 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200594 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300595 ath6kl_err("couldn't set bss filtering\n");
596 up(&ar->sem);
597 return -EIO;
598 }
599 }
600
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530601 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300602
Thomas Pedersenc422d52d2012-05-15 00:09:23 -0700603 /* enable enhanced bmiss detection if applicable */
604 ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
605
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800606 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
607 nw_subtype = SUBTYPE_P2PCLIENT;
608
Kalle Valobdcd8172011-07-18 00:22:30 +0300609 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
610 "%s: connect called with authmode %d dot11 auth %d"
611 " PW crypto %d PW crypto len %d GRP crypto %d"
612 " GRP crypto len %d channel hint %u\n",
613 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530614 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
615 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530616 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300617
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530618 vif->reconnect_flag = 0;
Raja Manice0dc0c2012-02-20 19:08:08 +0530619
620 if (vif->nw_type == INFRA_NETWORK) {
Kalle Valob5283872012-03-12 13:23:23 +0200621 interval = max_t(u16, vif->listen_intvl_t,
622 ATH6KL_MAX_WOW_LISTEN_INTL);
Raja Manice0dc0c2012-02-20 19:08:08 +0530623 status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
624 interval,
625 0);
626 if (status) {
627 ath6kl_err("couldn't set listen intervel\n");
628 up(&ar->sem);
629 return status;
630 }
631 }
632
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530633 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530634 vif->dot11_auth_mode, vif->auth_mode,
635 vif->prwise_crypto,
636 vif->prwise_crypto_len,
637 vif->grp_crypto, vif->grp_crypto_len,
638 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530639 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -0800640 ar->connect_ctrl_flags, nw_subtype);
Kalle Valobdcd8172011-07-18 00:22:30 +0300641
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530642 if (sme->bg_scan_period == 0) {
643 /* disable background scan if period is 0 */
Bala Shanmugamf5993592012-03-27 12:17:32 +0530644 sme->bg_scan_period = 0xffff;
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530645 } else if (sme->bg_scan_period == -1) {
646 /* configure default value if not specified */
Bala Shanmugamf5993592012-03-27 12:17:32 +0530647 sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
Mohammed Shafi Shajakhan6f7c1ad2012-11-16 18:24:37 +0530648 }
Bala Shanmugamf5993592012-03-27 12:17:32 +0530649
650 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
651 sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
652
Kalle Valobdcd8172011-07-18 00:22:30 +0300653 up(&ar->sem);
654
655 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530656 memset(vif->ssid, 0, sizeof(vif->ssid));
657 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300658 ath6kl_err("invalid request\n");
659 return -ENOENT;
660 } else if (status) {
661 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
662 return -EIO;
663 }
664
665 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Kalle Valoddc3d772012-03-07 20:03:58 +0200666 ((vif->auth_mode == WPA_PSK_AUTH) ||
667 (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530668 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300669 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
670 }
671
672 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530673 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300674
675 return 0;
676}
677
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530678static struct cfg80211_bss *
679ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
680 enum network_type nw_type,
681 const u8 *bssid,
682 struct ieee80211_channel *chan,
683 const u8 *beacon_ie,
684 size_t beacon_ie_len)
Jouni Malinen01cac472011-09-19 19:14:59 +0300685{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530686 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300687 struct cfg80211_bss *bss;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200688 u16 cap_val;
689 enum ieee80211_bss_type bss_type;
Jouni Malinen01cac472011-09-19 19:14:59 +0300690 u8 *ie;
691
Raja Mani4eab6f42011-11-09 17:02:23 +0530692 if (nw_type & ADHOC_NETWORK) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530693 cap_val = WLAN_CAPABILITY_IBSS;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200694 bss_type = IEEE80211_BSS_TYPE_IBSS;
Raja Mani4eab6f42011-11-09 17:02:23 +0530695 } else {
Raja Mani4eab6f42011-11-09 17:02:23 +0530696 cap_val = WLAN_CAPABILITY_ESS;
Dedy Lansky6eb18132015-02-08 15:52:03 +0200697 bss_type = IEEE80211_BSS_TYPE_ESS;
Raja Mani4eab6f42011-11-09 17:02:23 +0530698 }
699
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530700 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Raja Mani4eab6f42011-11-09 17:02:23 +0530701 vif->ssid, vif->ssid_len,
Dedy Lansky6eb18132015-02-08 15:52:03 +0200702 bss_type, IEEE80211_PRIVACY_ANY);
Jouni Malinen01cac472011-09-19 19:14:59 +0300703 if (bss == NULL) {
704 /*
705 * Since cfg80211 may not yet know about the BSS,
706 * generate a partial entry until the first BSS info
707 * event becomes available.
708 *
709 * Prepend SSID element since it is not included in the Beacon
710 * IEs from the target.
711 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530712 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300713 if (ie == NULL)
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530714 return NULL;
Jouni Malinen01cac472011-09-19 19:14:59 +0300715 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530716 ie[1] = vif->ssid_len;
717 memcpy(ie + 2, vif->ssid, vif->ssid_len);
718 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530719 bss = cfg80211_inform_bss(ar->wiphy, chan,
Johannes Berg5bc8c1f2014-08-12 21:01:28 +0200720 CFG80211_BSS_FTYPE_UNKNOWN,
Raja Mani4eab6f42011-11-09 17:02:23 +0530721 bssid, 0, cap_val, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530722 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300723 0, GFP_KERNEL);
724 if (bss)
Kalle Valocdeb8602012-04-12 11:02:18 +0300725 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
726 "added bss %pM to cfg80211\n", bssid);
Jouni Malinen01cac472011-09-19 19:14:59 +0300727 kfree(ie);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +0200728 } else {
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530729 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
Kalle Valoa5d8f9d2014-03-11 12:58:01 +0200730 }
Jouni Malinen01cac472011-09-19 19:14:59 +0300731
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530732 return bss;
Jouni Malinen01cac472011-09-19 19:14:59 +0300733}
734
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530735void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300736 u8 *bssid, u16 listen_intvl,
737 u16 beacon_intvl,
738 enum network_type nw_type,
739 u8 beacon_ie_len, u8 assoc_req_len,
740 u8 assoc_resp_len, u8 *assoc_info)
741{
Jouni Malinen01cac472011-09-19 19:14:59 +0300742 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530743 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530744 struct cfg80211_bss *bss;
Kalle Valobdcd8172011-07-18 00:22:30 +0300745
746 /* capinfo + listen interval */
747 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
748
749 /* capinfo + status code + associd */
750 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
751
752 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
753 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
754 assoc_resp_ie_offset;
755
756 assoc_req_len -= assoc_req_ie_offset;
757 assoc_resp_len -= assoc_resp_ie_offset;
758
Jouni Malinen32c10872011-09-19 19:15:07 +0300759 /*
760 * Store Beacon interval here; DTIM period will be available only once
761 * a Beacon frame from the AP is seen.
762 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530763 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530764 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300765
Kalle Valobdcd8172011-07-18 00:22:30 +0300766 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530767 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
769 "%s: ath6k not in ibss mode\n", __func__);
770 return;
771 }
772 }
773
774 if (nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530775 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
776 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300777 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
778 "%s: ath6k not in station mode\n", __func__);
779 return;
780 }
781 }
782
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530783 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300784
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530785 bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
786 assoc_info, beacon_ie_len);
787 if (!bss) {
Raja Mani4eab6f42011-11-09 17:02:23 +0530788 ath6kl_err("could not add cfg80211 bss entry\n");
Kalle Valobdcd8172011-07-18 00:22:30 +0300789 return;
790 }
791
Raja Mani4eab6f42011-11-09 17:02:23 +0530792 if (nw_type & ADHOC_NETWORK) {
793 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
794 nw_type & ADHOC_CREATOR ? "creator" : "joiner");
Antonio Quartullife94f3a2014-01-29 17:53:43 +0100795 cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
Johannes Berg5b112d32013-02-01 01:49:58 +0100796 cfg80211_put_bss(ar->wiphy, bss);
Jouni Malinen01cac472011-09-19 19:14:59 +0300797 return;
798 }
799
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530800 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300801 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530802 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530803 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300804 assoc_req_ie, assoc_req_len,
805 assoc_resp_ie, assoc_resp_len,
806 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Johannes Berg5b112d32013-02-01 01:49:58 +0100807 cfg80211_put_bss(ar->wiphy, bss);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530808 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300809 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan5e13fd32011-12-13 17:19:57 +0530810 cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
811 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300812 }
813}
814
815static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
816 struct net_device *dev, u16 reason_code)
817{
Kalle Valod6d5c062011-11-25 13:17:37 +0200818 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530819 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300820
821 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
822 reason_code);
823
Kalle Valo10509f92011-12-13 14:52:07 +0200824 ath6kl_cfg80211_sscan_disable(vif);
825
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530826 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300827 return -EIO;
828
829 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
830 ath6kl_err("busy, destroy in progress\n");
831 return -EBUSY;
832 }
833
834 if (down_interruptible(&ar->sem)) {
835 ath6kl_err("busy, couldn't get access\n");
836 return -ERESTARTSYS;
837 }
838
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530839 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530840 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530841 memset(vif->ssid, 0, sizeof(vif->ssid));
842 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300843
844 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530845 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300846
847 up(&ar->sem);
848
849 return 0;
850}
851
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530852void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300853 u8 *bssid, u8 assoc_resp_len,
854 u8 *assoc_info, u16 proto_reason)
855{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530856 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530857
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530858 if (vif->scan_req) {
Avraham Stern1d762502016-07-05 17:10:13 +0300859 struct cfg80211_scan_info info = {
860 .aborted = true,
861 };
862
863 cfg80211_scan_done(vif->scan_req, &info);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530864 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300865 }
866
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530867 if (vif->nw_type & ADHOC_NETWORK) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +0100868 if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
Kalle Valobdcd8172011-07-18 00:22:30 +0300869 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
870 "%s: ath6k not in ibss mode\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +0300871 return;
872 }
873
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530874 if (vif->nw_type & INFRA_NETWORK) {
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +0530875 if (vif->wdev.iftype != NL80211_IFTYPE_STATION &&
876 vif->wdev.iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300877 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
878 "%s: ath6k not in station mode\n", __func__);
879 return;
880 }
881 }
882
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530883 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300884
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530885 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530886 cfg80211_connect_result(vif->ndev,
Kalle Valo96f1fad2012-03-07 20:03:57 +0200887 bssid, NULL, 0,
888 NULL, 0,
889 WLAN_STATUS_UNSPECIFIED_FAILURE,
890 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530891 } else if (vif->sme_state == SME_CONNECTED) {
Thomas Pedersen33a66642012-05-16 13:41:13 -0700892 cfg80211_disconnected(vif->ndev, proto_reason,
Johannes Berg80279fb2015-05-22 16:22:20 +0200893 NULL, 0, false, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300894 }
895
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530896 vif->sme_state = SME_DISCONNECTED;
Thomas Pedersen33a66642012-05-16 13:41:13 -0700897
898 /*
899 * Send a disconnect command to target when a disconnect event is
900 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
901 * request from host) to make the firmware stop trying to connect even
902 * after giving disconnect event. There will be one more disconnect
903 * event for this disconnect command with reason code DISCONNECT_CMD
904 * which won't be notified to cfg80211.
905 */
906 if (reason != DISCONNECT_CMD)
907 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300908}
909
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300910static int ath6kl_set_probed_ssids(struct ath6kl *ar,
911 struct ath6kl_vif *vif,
Naveen Singhdd45b752012-05-16 13:29:00 +0300912 struct cfg80211_ssid *ssids, int n_ssids,
913 struct cfg80211_match_set *match_set,
914 int n_match_ssid)
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300915{
Naveen Singhdd45b752012-05-16 13:29:00 +0300916 u8 i, j, index_to_add, ssid_found = false;
917 struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300918
Naveen Singhdd45b752012-05-16 13:29:00 +0300919 memset(ssid_list, 0, sizeof(ssid_list));
920
921 if (n_ssids > MAX_PROBED_SSIDS ||
922 n_match_ssid > MAX_PROBED_SSIDS)
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300923 return -EINVAL;
924
925 for (i = 0; i < n_ssids; i++) {
Naveen Singhdd45b752012-05-16 13:29:00 +0300926 memcpy(ssid_list[i].ssid.ssid,
927 ssids[i].ssid,
928 ssids[i].ssid_len);
929 ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
930
931 if (ssids[i].ssid_len)
932 ssid_list[i].flag = SPECIFIC_SSID_FLAG;
933 else
934 ssid_list[i].flag = ANY_SSID_FLAG;
935
936 if (n_match_ssid == 0)
937 ssid_list[i].flag |= MATCH_SSID_FLAG;
938 }
939
940 index_to_add = i;
941
942 for (i = 0; i < n_match_ssid; i++) {
943 ssid_found = false;
944
945 for (j = 0; j < n_ssids; j++) {
946 if ((match_set[i].ssid.ssid_len ==
947 ssid_list[j].ssid.ssid_len) &&
948 (!memcmp(ssid_list[j].ssid.ssid,
949 match_set[i].ssid.ssid,
950 match_set[i].ssid.ssid_len))) {
951 ssid_list[j].flag |= MATCH_SSID_FLAG;
952 ssid_found = true;
953 break;
954 }
955 }
956
957 if (ssid_found)
958 continue;
959
960 if (index_to_add >= MAX_PROBED_SSIDS)
961 continue;
962
963 ssid_list[index_to_add].ssid.ssid_len =
964 match_set[i].ssid.ssid_len;
965 memcpy(ssid_list[index_to_add].ssid.ssid,
966 match_set[i].ssid.ssid,
967 match_set[i].ssid.ssid_len);
968 ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
969 index_to_add++;
970 }
971
972 for (i = 0; i < index_to_add; i++) {
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300973 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
Naveen Singhdd45b752012-05-16 13:29:00 +0300974 ssid_list[i].flag,
975 ssid_list[i].ssid.ssid_len,
976 ssid_list[i].ssid.ssid);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300977 }
978
979 /* Make sure no old entries are left behind */
Naveen Singhdd45b752012-05-16 13:29:00 +0300980 for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
Jouni Malinen3b8ffc62012-04-16 19:28:03 +0300981 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
982 DISABLE_SSID_FLAG, 0, NULL);
983 }
984
985 return 0;
986}
987
Johannes Bergfd014282012-06-18 19:17:03 +0200988static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
Kalle Valobdcd8172011-07-18 00:22:30 +0300989 struct cfg80211_scan_request *request)
990{
Johannes Bergfd014282012-06-18 19:17:03 +0200991 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev);
992 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300993 s8 n_channels = 0;
994 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300995 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530996 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300997
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530998 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300999 return -EIO;
1000
Kalle Valo10509f92011-12-13 14:52:07 +02001001 ath6kl_cfg80211_sscan_disable(vif);
1002
Kalle Valobdcd8172011-07-18 00:22:30 +03001003 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301004 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan954e6ce2012-04-25 12:39:06 +05301005 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
1006 ALL_BSS_FILTER, 0);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +03001007 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001008 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +03001009 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03001010 }
1011 }
1012
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03001013 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
Naveen Singhdd45b752012-05-16 13:29:00 +03001014 request->n_ssids, NULL, 0);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03001015 if (ret < 0)
1016 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03001017
Aarthi Thiruvengadam080eec42012-02-28 09:17:04 -08001018 /* this also clears IE in fw if it's not set */
1019 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1020 WMI_FRAME_PROBE_REQ,
1021 request->ie, request->ie_len);
1022 if (ret) {
Joe Perchesf1ff32e2012-05-30 01:58:39 -07001023 ath6kl_err("failed to set Probe Request appie for scan\n");
Aarthi Thiruvengadam080eec42012-02-28 09:17:04 -08001024 return ret;
Jouni Malinenb84da8c2011-08-30 21:57:59 +03001025 }
1026
Jouni Malinen11869be2011-09-02 20:07:06 +03001027 /*
1028 * Scan only the requested channels if the request specifies a set of
1029 * channels. If the list is longer than the target supports, do not
1030 * configure the list and instead, scan all available channels.
1031 */
1032 if (request->n_channels > 0 &&
1033 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +03001034 u8 i;
1035
Jouni Malinen11869be2011-09-02 20:07:06 +03001036 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +03001037
1038 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
1039 if (channels == NULL) {
Kalle Valocdeb8602012-04-12 11:02:18 +03001040 ath6kl_warn("failed to set scan channels, scan all channels");
Edward Lu1276c9e2011-08-30 21:58:00 +03001041 n_channels = 0;
1042 }
1043
1044 for (i = 0; i < n_channels; i++)
1045 channels[i] = request->channels[i]->center_freq;
1046 }
1047
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301048 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +05301049 force_fg_scan = 1;
1050
Raja Mani5b35dff2012-03-28 18:50:35 +05301051 vif->scan_req = request;
1052
Kalle Valo11f0bfc2012-07-19 16:00:48 +03001053 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
1054 WMI_LONG_SCAN, force_fg_scan,
1055 false, 0,
1056 ATH6KL_FG_SCAN_INTERVAL,
1057 n_channels, channels,
1058 request->no_cck,
1059 request->rates);
Raja Mani5b35dff2012-03-28 18:50:35 +05301060 if (ret) {
Kalle Valo11f0bfc2012-07-19 16:00:48 +03001061 ath6kl_err("failed to start scan: %d\n", ret);
Raja Mani5b35dff2012-03-28 18:50:35 +05301062 vif->scan_req = NULL;
1063 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001064
Edward Lu1276c9e2011-08-30 21:58:00 +03001065 kfree(channels);
1066
Kalle Valobdcd8172011-07-18 00:22:30 +03001067 return ret;
1068}
1069
Kalle Valo1c17d312011-11-01 08:43:56 +02001070void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
Kalle Valobdcd8172011-07-18 00:22:30 +03001071{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301072 struct ath6kl *ar = vif->ar;
Avraham Stern1d762502016-07-05 17:10:13 +03001073 struct cfg80211_scan_info info = {
1074 .aborted = aborted,
1075 };
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001076 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +03001077
Kalle Valo1c17d312011-11-01 08:43:56 +02001078 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
1079 aborted ? " aborted" : "");
Kalle Valobdcd8172011-07-18 00:22:30 +03001080
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301081 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001082 return;
Kalle Valobdcd8172011-07-18 00:22:30 +03001083
Kalle Valo1c17d312011-11-01 08:43:56 +02001084 if (aborted)
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001085 goto out;
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001086
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301087 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
1088 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301089 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
1090 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +03001091 0, NULL);
1092 }
1093 }
1094
1095out:
Avraham Stern1d762502016-07-05 17:10:13 +03001096 cfg80211_scan_done(vif->scan_req, &info);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05301097 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001098}
1099
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001100void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
1101 enum wmi_phy_mode mode)
1102{
Johannes Berg683b6d32012-11-08 21:25:48 +01001103 struct cfg80211_chan_def chandef;
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001104
1105 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1106 "channel switch notify nw_type %d freq %d mode %d\n",
1107 vif->nw_type, freq, mode);
1108
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001109 cfg80211_chandef_create(&chandef,
1110 ieee80211_get_channel(vif->ar->wiphy, freq),
Pierre Le Magourouf3651ba2016-07-18 23:22:19 +03001111 (mode == WMI_11G_HT20 &&
1112 ath6kl_band_2ghz.ht_cap.ht_supported) ?
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001113 NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001114
Simon Wunderliche487eae2013-11-21 18:19:51 +01001115 mutex_lock(&vif->wdev.mtx);
Johannes Berg683b6d32012-11-08 21:25:48 +01001116 cfg80211_ch_switch_notify(vif->ndev, &chandef);
Simon Wunderliche487eae2013-11-21 18:19:51 +01001117 mutex_unlock(&vif->wdev.mtx);
Thomas Pedersenc4f78632012-04-06 13:35:48 -07001118}
1119
Kalle Valobdcd8172011-07-18 00:22:30 +03001120static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1121 u8 key_index, bool pairwise,
1122 const u8 *mac_addr,
1123 struct key_params *params)
1124{
Kalle Valod6d5c062011-11-25 13:17:37 +02001125 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301126 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001127 struct ath6kl_key *key = NULL;
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301128 int seq_len;
Kalle Valobdcd8172011-07-18 00:22:30 +03001129 u8 key_usage;
1130 u8 key_type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001131
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301132 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001133 return -EIO;
1134
Jouni Malinen837cb972011-10-11 17:31:57 +03001135 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
1136 if (params->key_len != WMI_KRK_LEN)
1137 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301138 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
1139 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +03001140 }
1141
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301142 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001143 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1144 "%s: key index %d out of bounds\n", __func__,
1145 key_index);
1146 return -ENOENT;
1147 }
1148
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301149 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001150 memset(key, 0, sizeof(struct ath6kl_key));
1151
1152 if (pairwise)
1153 key_usage = PAIRWISE_USAGE;
1154 else
1155 key_usage = GROUP_USAGE;
1156
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301157 seq_len = params->seq_len;
1158 if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
1159 seq_len > ATH6KL_KEY_SEQ_LEN) {
1160 /* Only first half of the WPI PN is configured */
1161 seq_len = ATH6KL_KEY_SEQ_LEN;
Kalle Valobdcd8172011-07-18 00:22:30 +03001162 }
Sujith Manoharan4a8ce2f2012-01-10 09:53:38 +05301163 if (params->key_len > WLAN_MAX_KEY_LEN ||
1164 seq_len > sizeof(key->seq))
1165 return -EINVAL;
1166
1167 key->key_len = params->key_len;
1168 memcpy(key->key, params->key, key->key_len);
1169 key->seq_len = seq_len;
1170 memcpy(key->seq, params->seq, key->seq_len);
1171 key->cipher = params->cipher;
Kalle Valobdcd8172011-07-18 00:22:30 +03001172
1173 switch (key->cipher) {
1174 case WLAN_CIPHER_SUITE_WEP40:
1175 case WLAN_CIPHER_SUITE_WEP104:
1176 key_type = WEP_CRYPT;
1177 break;
1178
1179 case WLAN_CIPHER_SUITE_TKIP:
1180 key_type = TKIP_CRYPT;
1181 break;
1182
1183 case WLAN_CIPHER_SUITE_CCMP:
1184 key_type = AES_CRYPT;
1185 break;
Dai Shuibing5e070212011-11-03 11:39:37 +02001186 case WLAN_CIPHER_SUITE_SMS4:
1187 key_type = WAPI_CRYPT;
1188 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001189
1190 default:
1191 return -ENOTSUPP;
1192 }
1193
Kalle Valoddc3d772012-03-07 20:03:58 +02001194 if (((vif->auth_mode == WPA_PSK_AUTH) ||
1195 (vif->auth_mode == WPA2_PSK_AUTH)) &&
1196 (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05301197 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +03001198
1199 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1200 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
1201 __func__, key_index, key->key_len, key_type,
1202 key_usage, key->seq_len);
1203
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301204 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen47032902011-12-08 16:50:30 +02001205 (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
Vasanthakumar Thiagarajancc4d6232012-02-14 20:33:00 +05301206 key_type == WAPI_CRYPT)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001207 ar->ap_mode_bkey.valid = true;
1208 ar->ap_mode_bkey.key_index = key_index;
1209 ar->ap_mode_bkey.key_type = key_type;
1210 ar->ap_mode_bkey.key_len = key->key_len;
1211 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301212 if (!test_bit(CONNECTED, &vif->flags)) {
Kalle Valocdeb8602012-04-12 11:02:18 +03001213 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1214 "Delay initial group key configuration until AP mode has been started\n");
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001215 /*
1216 * The key will be set in ath6kl_connect_ap_mode() once
1217 * the connected event is received from the target.
1218 */
1219 return 0;
1220 }
1221 }
1222
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301223 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301224 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +03001225 /*
1226 * Store the key locally so that it can be re-configured after
1227 * the AP mode has properly started
1228 * (ath6kl_install_statioc_wep_keys).
1229 */
Kalle Valocdeb8602012-04-12 11:02:18 +03001230 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1231 "Delay WEP key configuration until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301232 vif->wep_key_list[key_index].key_len = key->key_len;
1233 memcpy(vif->wep_key_list[key_index].key, key->key,
1234 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +03001235 return 0;
1236 }
1237
Vasanthakumar Thiagarajan7cefa442011-11-11 20:33:00 +05301238 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001239 key_type, key_usage, key->key_len,
1240 key->seq, key->seq_len, key->key,
1241 KEY_OP_INIT_VAL,
1242 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001243}
1244
1245static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1246 u8 key_index, bool pairwise,
1247 const u8 *mac_addr)
1248{
Kalle Valod6d5c062011-11-25 13:17:37 +02001249 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301250 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001251
1252 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1253
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301254 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001255 return -EIO;
1256
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301257 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001258 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1259 "%s: key index %d out of bounds\n", __func__,
1260 key_index);
1261 return -ENOENT;
1262 }
1263
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301264 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001265 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1266 "%s: index %d is empty\n", __func__, key_index);
1267 return 0;
1268 }
1269
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301270 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001271
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301272 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001273}
1274
1275static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1276 u8 key_index, bool pairwise,
1277 const u8 *mac_addr, void *cookie,
1278 void (*callback) (void *cookie,
1279 struct key_params *))
1280{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301281 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001282 struct ath6kl_key *key = NULL;
1283 struct key_params params;
1284
1285 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1286
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301287 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001288 return -EIO;
1289
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301290 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001291 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1292 "%s: key index %d out of bounds\n", __func__,
1293 key_index);
1294 return -ENOENT;
1295 }
1296
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301297 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001298 memset(&params, 0, sizeof(params));
1299 params.cipher = key->cipher;
1300 params.key_len = key->key_len;
1301 params.seq_len = key->seq_len;
1302 params.seq = key->seq;
1303 params.key = key->key;
1304
1305 callback(cookie, &params);
1306
1307 return key->key_len ? 0 : -ENOENT;
1308}
1309
1310static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1311 struct net_device *ndev,
1312 u8 key_index, bool unicast,
1313 bool multicast)
1314{
Kalle Valod6d5c062011-11-25 13:17:37 +02001315 struct ath6kl *ar = ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301316 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001317 struct ath6kl_key *key = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +03001318 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001319 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001320
1321 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1322
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301323 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001324 return -EIO;
1325
Vivek Natarajan792ecb32011-12-29 16:18:39 +05301326 if (key_index > WMI_MAX_KEY_INDEX) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001327 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1328 "%s: key index %d out of bounds\n",
1329 __func__, key_index);
1330 return -ENOENT;
1331 }
1332
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301333 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001334 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1335 __func__, key_index);
1336 return -EINVAL;
1337 }
1338
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301339 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301340 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001341 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301342 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001343 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001344 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301345 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001346 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301347 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001348
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301349 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001350 return 0; /* Delay until AP mode has been started */
1351
Jouni Malinenf3e61ec2011-11-02 23:46:47 +02001352 return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1353 vif->def_txkey_index,
1354 key_type, key_usage,
1355 key->key_len, key->seq, key->seq_len,
1356 key->key,
1357 KEY_OP_INIT_VAL, NULL,
1358 SYNC_BOTH_WMIFLAG);
Kalle Valobdcd8172011-07-18 00:22:30 +03001359}
1360
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301361void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001362 bool ismcast)
1363{
1364 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1365 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1366
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301367 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001368 (ismcast ? NL80211_KEYTYPE_GROUP :
1369 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1370 GFP_KERNEL);
1371}
1372
1373static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1374{
1375 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301376 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001377 int ret;
1378
1379 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1380 changed);
1381
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301382 vif = ath6kl_vif_first(ar);
1383 if (!vif)
1384 return -EIO;
1385
1386 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001387 return -EIO;
1388
1389 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1390 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1391 if (ret != 0) {
1392 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1393 return -EIO;
1394 }
1395 }
1396
1397 return 0;
1398}
1399
Kalle Valobdcd8172011-07-18 00:22:30 +03001400static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
Johannes Bergc8442112012-10-24 10:17:18 +02001401 struct wireless_dev *wdev,
Kalle Valobdcd8172011-07-18 00:22:30 +03001402 enum nl80211_tx_power_setting type,
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001403 int mbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001404{
1405 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301406 struct ath6kl_vif *vif;
Luis R. Rodriguezb992a282011-11-23 11:08:14 -05001407 int dbm = MBM_TO_DBM(mbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001408
1409 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1410 type, dbm);
1411
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301412 vif = ath6kl_vif_first(ar);
1413 if (!vif)
1414 return -EIO;
1415
1416 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001417 return -EIO;
1418
1419 switch (type) {
1420 case NL80211_TX_POWER_AUTOMATIC:
1421 return 0;
1422 case NL80211_TX_POWER_LIMITED:
Kalle Valod0d670a2012-03-07 20:03:58 +02001423 ar->tx_pwr = dbm;
Kalle Valobdcd8172011-07-18 00:22:30 +03001424 break;
1425 default:
1426 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1427 __func__, type);
1428 return -EOPNOTSUPP;
1429 }
1430
Kalle Valod0d670a2012-03-07 20:03:58 +02001431 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001432
1433 return 0;
1434}
1435
Johannes Bergc8442112012-10-24 10:17:18 +02001436static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
1437 struct wireless_dev *wdev,
1438 int *dbm)
Kalle Valobdcd8172011-07-18 00:22:30 +03001439{
1440 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301441 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001442
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301443 vif = ath6kl_vif_first(ar);
1444 if (!vif)
1445 return -EIO;
1446
1447 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001448 return -EIO;
1449
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301450 if (test_bit(CONNECTED, &vif->flags)) {
Eric Bentleycabd34d2016-08-30 02:16:19 -04001451 ar->tx_pwr = 255;
Kalle Valobdcd8172011-07-18 00:22:30 +03001452
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301453 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001454 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1455 return -EIO;
1456 }
1457
Eric Bentleycabd34d2016-08-30 02:16:19 -04001458 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 255,
Kalle Valobdcd8172011-07-18 00:22:30 +03001459 5 * HZ);
1460
1461 if (signal_pending(current)) {
1462 ath6kl_err("target did not respond\n");
1463 return -EINTR;
1464 }
1465 }
1466
1467 *dbm = ar->tx_pwr;
1468 return 0;
1469}
1470
1471static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1472 struct net_device *dev,
1473 bool pmgmt, int timeout)
1474{
1475 struct ath6kl *ar = ath6kl_priv(dev);
1476 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301477 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001478
1479 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1480 __func__, pmgmt, timeout);
1481
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301482 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001483 return -EIO;
1484
1485 if (pmgmt) {
Mohammed Shafi Shajakhanf0ed67e2012-10-12 17:40:41 +05301486 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +03001487 mode.pwr_mode = REC_POWER;
1488 } else {
Mohammed Shafi Shajakhanf0ed67e2012-10-12 17:40:41 +05301489 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
Kalle Valobdcd8172011-07-18 00:22:30 +03001490 mode.pwr_mode = MAX_PERF_POWER;
1491 }
1492
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301493 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
Kalle Valo96f1fad2012-03-07 20:03:57 +02001494 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001495 ath6kl_err("wmi_powermode_cmd failed\n");
1496 return -EIO;
1497 }
1498
1499 return 0;
1500}
1501
Johannes Berg84efbb82012-06-16 00:00:26 +02001502static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
Johannes Berg552bff02012-09-19 09:26:06 +02001503 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +01001504 unsigned char name_assign_type,
Johannes Berg84efbb82012-06-16 00:00:26 +02001505 enum nl80211_iftype type,
Johannes Berg84efbb82012-06-16 00:00:26 +02001506 struct vif_params *params)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301507{
1508 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg84efbb82012-06-16 00:00:26 +02001509 struct wireless_dev *wdev;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301510 u8 if_idx, nw_type;
1511
Kalle Valo71f96ee2011-11-14 19:31:30 +02001512 if (ar->num_vif == ar->vif_max) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301513 ath6kl_err("Reached maximum number of supported vif\n");
1514 return ERR_PTR(-EINVAL);
1515 }
1516
1517 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1518 ath6kl_err("Not a supported interface type\n");
1519 return ERR_PTR(-EINVAL);
1520 }
1521
Tom Gundersen6bab2e192015-03-18 11:13:39 +01001522 wdev = ath6kl_interface_add(ar, name, name_assign_type, type, if_idx, nw_type);
Johannes Berg84efbb82012-06-16 00:00:26 +02001523 if (!wdev)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301524 return ERR_PTR(-ENOMEM);
1525
1526 ar->num_vif++;
1527
Johannes Berg84efbb82012-06-16 00:00:26 +02001528 return wdev;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301529}
1530
1531static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
Johannes Berg84efbb82012-06-16 00:00:26 +02001532 struct wireless_dev *wdev)
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301533{
1534 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg84efbb82012-06-16 00:00:26 +02001535 struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301536
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301537 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301538 list_del(&vif->list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05301539 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301540
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05301541 ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301542
Mohammed Shafi Shajakhanbc52aab2013-02-22 20:20:09 +05301543 rtnl_lock();
Kalle Valoc25889e2012-01-17 20:08:27 +02001544 ath6kl_cfg80211_vif_cleanup(vif);
Mohammed Shafi Shajakhanbc52aab2013-02-22 20:20:09 +05301545 rtnl_unlock();
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301546
1547 return 0;
1548}
1549
Kalle Valobdcd8172011-07-18 00:22:30 +03001550static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1551 struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +02001552 enum nl80211_iftype type,
Kalle Valobdcd8172011-07-18 00:22:30 +03001553 struct vif_params *params)
1554{
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301555 struct ath6kl_vif *vif = netdev_priv(ndev);
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301556 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +03001557
1558 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1559
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301560 /*
1561 * Don't bring up p2p on an interface which is not initialized
1562 * for p2p operation where fw does not have capability to switch
1563 * dynamically between non-p2p and p2p type interface.
1564 */
1565 if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
1566 vif->ar->fw_capabilities) &&
1567 (type == NL80211_IFTYPE_P2P_CLIENT ||
1568 type == NL80211_IFTYPE_P2P_GO)) {
1569 if (vif->ar->vif_max == 1) {
1570 if (vif->fw_vif_idx != 0)
1571 return -EINVAL;
1572 else
1573 goto set_iface_type;
1574 }
1575
1576 for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
1577 if (i == vif->fw_vif_idx)
1578 break;
1579 }
1580
1581 if (i == vif->ar->vif_max) {
1582 ath6kl_err("Invalid interface to bring up P2P\n");
1583 return -EINVAL;
1584 }
1585 }
1586
Thomas Pedersenc422d52d2012-05-15 00:09:23 -07001587 /* need to clean up enhanced bmiss detection fw state */
1588 ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
1589
Vasanthakumar Thiagarajan1e8d13b2012-04-06 20:24:30 +05301590set_iface_type:
Kalle Valobdcd8172011-07-18 00:22:30 +03001591 switch (type) {
1592 case NL80211_IFTYPE_STATION:
Mohammed Shafi Shajakhan8aa659d2012-11-16 18:22:57 +05301593 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301594 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001595 break;
1596 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301597 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001598 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001599 case NL80211_IFTYPE_AP:
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001600 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301601 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001602 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001603 default:
1604 ath6kl_err("invalid interface type %u\n", type);
1605 return -EOPNOTSUPP;
1606 }
1607
Vasanthakumar Thiagarajan551959d2011-10-25 19:34:26 +05301608 vif->wdev.iftype = type;
Kalle Valobdcd8172011-07-18 00:22:30 +03001609
1610 return 0;
1611}
1612
1613static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1614 struct net_device *dev,
1615 struct cfg80211_ibss_params *ibss_param)
1616{
1617 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301618 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001619 int status;
1620
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301621 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001622 return -EIO;
1623
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301624 vif->ssid_len = ibss_param->ssid_len;
1625 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001626
Johannes Berg683b6d32012-11-08 21:25:48 +01001627 if (ibss_param->chandef.chan)
1628 vif->ch_hint = ibss_param->chandef.chan->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001629
1630 if (ibss_param->channel_fixed) {
1631 /*
1632 * TODO: channel_fixed: The channel should be fixed, do not
1633 * search for IBSSs to join on other channels. Target
1634 * firmware does not support this feature, needs to be
1635 * updated.
1636 */
1637 return -EOPNOTSUPP;
1638 }
1639
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301640 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001641 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301642 memcpy(vif->req_bssid, ibss_param->bssid,
1643 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001644
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301645 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001646
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301647 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001648 if (status)
1649 return status;
1650
1651 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301652 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1653 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001654 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301655 ath6kl_set_cipher(vif, 0, true);
1656 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001657 }
1658
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301659 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001660
1661 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1662 "%s: connect called with authmode %d dot11 auth %d"
1663 " PW crypto %d PW crypto len %d GRP crypto %d"
1664 " GRP crypto len %d channel hint %u\n",
1665 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301666 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1667 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301668 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001669
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301670 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301671 vif->dot11_auth_mode, vif->auth_mode,
1672 vif->prwise_crypto,
1673 vif->prwise_crypto_len,
1674 vif->grp_crypto, vif->grp_crypto_len,
1675 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301676 vif->req_bssid, vif->ch_hint,
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08001677 ar->connect_ctrl_flags, SUBTYPE_NONE);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301678 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001679
1680 return 0;
1681}
1682
1683static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1684 struct net_device *dev)
1685{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301686 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001687
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301688 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001689 return -EIO;
1690
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301691 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301692 memset(vif->ssid, 0, sizeof(vif->ssid));
1693 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001694
1695 return 0;
1696}
1697
1698static const u32 cipher_suites[] = {
1699 WLAN_CIPHER_SUITE_WEP40,
1700 WLAN_CIPHER_SUITE_WEP104,
1701 WLAN_CIPHER_SUITE_TKIP,
1702 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001703 CCKM_KRK_CIPHER_SUITE,
Dai Shuibing5e070212011-11-03 11:39:37 +02001704 WLAN_CIPHER_SUITE_SMS4,
Kalle Valobdcd8172011-07-18 00:22:30 +03001705};
1706
1707static bool is_rate_legacy(s32 rate)
1708{
1709 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1710 6000, 9000, 12000, 18000, 24000,
1711 36000, 48000, 54000
1712 };
1713 u8 i;
1714
1715 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1716 if (rate == legacy[i])
1717 return true;
1718
1719 return false;
1720}
1721
1722static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1723{
1724 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1725 52000, 58500, 65000, 72200
1726 };
1727 u8 i;
1728
1729 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1730 if (rate == ht20[i]) {
1731 if (i == ARRAY_SIZE(ht20) - 1)
1732 /* last rate uses sgi */
1733 *sgi = true;
1734 else
1735 *sgi = false;
1736
1737 *mcs = i;
1738 return true;
1739 }
1740 }
1741 return false;
1742}
1743
1744static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1745{
1746 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1747 81000, 108000, 121500, 135000,
1748 150000
1749 };
1750 u8 i;
1751
1752 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1753 if (rate == ht40[i]) {
1754 if (i == ARRAY_SIZE(ht40) - 1)
1755 /* last rate uses sgi */
1756 *sgi = true;
1757 else
1758 *sgi = false;
1759
1760 *mcs = i;
1761 return true;
1762 }
1763 }
1764
1765 return false;
1766}
1767
1768static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02001769 const u8 *mac, struct station_info *sinfo)
Kalle Valobdcd8172011-07-18 00:22:30 +03001770{
1771 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301772 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001773 long left;
1774 bool sgi;
1775 s32 rate;
1776 int ret;
1777 u8 mcs;
1778
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301779 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001780 return -ENOENT;
1781
1782 if (down_interruptible(&ar->sem))
1783 return -EBUSY;
1784
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301785 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001786
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301787 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001788
1789 if (ret != 0) {
1790 up(&ar->sem);
1791 return -EIO;
1792 }
1793
1794 left = wait_event_interruptible_timeout(ar->event_wq,
1795 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301796 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001797 WMI_TIMEOUT);
1798
1799 up(&ar->sem);
1800
1801 if (left == 0)
1802 return -ETIMEDOUT;
1803 else if (left < 0)
1804 return left;
1805
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301806 if (vif->target_stats.rx_byte) {
1807 sinfo->rx_bytes = vif->target_stats.rx_byte;
Johannes Berg319090b2014-11-17 14:08:11 +01001808 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301809 sinfo->rx_packets = vif->target_stats.rx_pkt;
Johannes Berg319090b2014-11-17 14:08:11 +01001810 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
Kalle Valobdcd8172011-07-18 00:22:30 +03001811 }
1812
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301813 if (vif->target_stats.tx_byte) {
1814 sinfo->tx_bytes = vif->target_stats.tx_byte;
Johannes Berg319090b2014-11-17 14:08:11 +01001815 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301816 sinfo->tx_packets = vif->target_stats.tx_pkt;
Johannes Berg319090b2014-11-17 14:08:11 +01001817 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
Kalle Valobdcd8172011-07-18 00:22:30 +03001818 }
1819
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301820 sinfo->signal = vif->target_stats.cs_rssi;
Johannes Berg319090b2014-11-17 14:08:11 +01001821 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
Kalle Valobdcd8172011-07-18 00:22:30 +03001822
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301823 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001824
1825 if (is_rate_legacy(rate)) {
1826 sinfo->txrate.legacy = rate / 100;
1827 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1828 if (sgi) {
1829 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1830 sinfo->txrate.mcs = mcs - 1;
1831 } else {
1832 sinfo->txrate.mcs = mcs;
1833 }
1834
1835 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Johannes Bergb51f3be2015-01-15 16:14:02 +01001836 sinfo->txrate.bw = RATE_INFO_BW_20;
Kalle Valobdcd8172011-07-18 00:22:30 +03001837 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1838 if (sgi) {
1839 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1840 sinfo->txrate.mcs = mcs - 1;
1841 } else {
1842 sinfo->txrate.mcs = mcs;
1843 }
1844
Johannes Bergb51f3be2015-01-15 16:14:02 +01001845 sinfo->txrate.bw = RATE_INFO_BW_40;
Kalle Valobdcd8172011-07-18 00:22:30 +03001846 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1847 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001848 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1849 "invalid rate from stats: %d\n", rate);
1850 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001851 return 0;
1852 }
1853
Johannes Berg319090b2014-11-17 14:08:11 +01001854 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001855
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301856 if (test_bit(CONNECTED, &vif->flags) &&
1857 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301858 vif->nw_type == INFRA_NETWORK) {
Johannes Berg319090b2014-11-17 14:08:11 +01001859 sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
Jouni Malinen32c10872011-09-19 19:15:07 +03001860 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301861 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1862 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001863 }
1864
Kalle Valobdcd8172011-07-18 00:22:30 +03001865 return 0;
1866}
1867
1868static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1869 struct cfg80211_pmksa *pmksa)
1870{
1871 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301872 struct ath6kl_vif *vif = netdev_priv(netdev);
1873
1874 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001875 pmksa->pmkid, true);
1876}
1877
1878static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1879 struct cfg80211_pmksa *pmksa)
1880{
1881 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301882 struct ath6kl_vif *vif = netdev_priv(netdev);
1883
1884 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001885 pmksa->pmkid, false);
1886}
1887
1888static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1889{
1890 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301891 struct ath6kl_vif *vif = netdev_priv(netdev);
1892
1893 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301894 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1895 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001896 return 0;
1897}
1898
Raja Manid91e8ee2012-01-30 17:13:10 +05301899static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
1900 struct cfg80211_wowlan *wow, u32 *filter)
Raja Mani6cb3c712011-11-07 22:52:45 +02001901{
Raja Manid91e8ee2012-01-30 17:13:10 +05301902 int ret, pos;
Thomas Pedersen2c07cf42012-08-20 14:26:50 -07001903 u8 mask[WOW_PATTERN_SIZE];
Raja Mani6cb3c712011-11-07 22:52:45 +02001904 u16 i;
Raja Mani6cb3c712011-11-07 22:52:45 +02001905
Raja Manid91e8ee2012-01-30 17:13:10 +05301906 /* Configure the patterns that we received from the user. */
Raja Mani6cb3c712011-11-07 22:52:45 +02001907 for (i = 0; i < wow->n_patterns; i++) {
Raja Mani6cb3c712011-11-07 22:52:45 +02001908 /*
1909 * Convert given nl80211 specific mask value to equivalent
1910 * driver specific mask value and send it to the chip along
1911 * with patterns. For example, If the mask value defined in
1912 * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
1913 * then equivalent driver specific mask value is
1914 * "0xFF 0x00 0xFF 0x00".
1915 */
1916 memset(&mask, 0, sizeof(mask));
1917 for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
1918 if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
1919 mask[pos] = 0xFF;
1920 }
1921 /*
1922 * Note: Pattern's offset is not passed as part of wowlan
1923 * parameter from CFG layer. So it's always passed as ZERO
1924 * to the firmware. It means, given WOW patterns are always
1925 * matched from the first byte of received pkt in the firmware.
1926 */
1927 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
Raja Manid91e8ee2012-01-30 17:13:10 +05301928 vif->fw_vif_idx, WOW_LIST_ID,
1929 wow->patterns[i].pattern_len,
1930 0 /* pattern offset */,
1931 wow->patterns[i].pattern, mask);
Raja Mani6cb3c712011-11-07 22:52:45 +02001932 if (ret)
1933 return ret;
1934 }
1935
Raja Manid91e8ee2012-01-30 17:13:10 +05301936 if (wow->disconnect)
1937 *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
1938
1939 if (wow->magic_pkt)
1940 *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
1941
1942 if (wow->gtk_rekey_failure)
1943 *filter |= WOW_FILTER_OPTION_GTK_ERROR;
1944
1945 if (wow->eap_identity_req)
1946 *filter |= WOW_FILTER_OPTION_EAP_REQ;
1947
1948 if (wow->four_way_handshake)
1949 *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
1950
1951 return 0;
1952}
1953
1954static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif)
1955{
1956 static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00,
1957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1958 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1959 0x00, 0x08 };
1960 static const u8 unicst_mask[] = { 0x01, 0x00, 0x00,
1961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1962 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1963 0x00, 0x7f };
1964 u8 unicst_offset = 0;
1965 static const u8 arp_pattern[] = { 0x08, 0x06 };
1966 static const u8 arp_mask[] = { 0xff, 0xff };
1967 u8 arp_offset = 20;
1968 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
1969 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
1970 u8 discvr_offset = 38;
1971 static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff,
1972 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
1974 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1976 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
1977 static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff,
1978 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
1980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1982 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ };
1983 u8 dhcp_offset = 0;
1984 int ret;
1985
1986 /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
1987 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1988 vif->fw_vif_idx, WOW_LIST_ID,
1989 sizeof(unicst_pattern), unicst_offset,
1990 unicst_pattern, unicst_mask);
1991 if (ret) {
1992 ath6kl_err("failed to add WOW unicast IP pattern\n");
1993 return ret;
1994 }
1995
1996 /* Setup all ARP pkt pattern */
1997 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
1998 vif->fw_vif_idx, WOW_LIST_ID,
1999 sizeof(arp_pattern), arp_offset,
2000 arp_pattern, arp_mask);
2001 if (ret) {
2002 ath6kl_err("failed to add WOW ARP pattern\n");
2003 return ret;
2004 }
2005
2006 /*
2007 * Setup multicast pattern for mDNS 224.0.0.251,
2008 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
2009 */
2010 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2011 vif->fw_vif_idx, WOW_LIST_ID,
2012 sizeof(discvr_pattern), discvr_offset,
2013 discvr_pattern, discvr_mask);
2014 if (ret) {
2015 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
2016 return ret;
2017 }
2018
2019 /* Setup all DHCP broadcast pkt pattern */
2020 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2021 vif->fw_vif_idx, WOW_LIST_ID,
2022 sizeof(dhcp_pattern), dhcp_offset,
2023 dhcp_pattern, dhcp_mask);
2024 if (ret) {
2025 ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
2026 return ret;
2027 }
2028
2029 return 0;
2030}
2031
2032static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
2033{
2034 struct net_device *ndev = vif->ndev;
2035 static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
2036 static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
2037 u8 discvr_offset = 38;
2038 u8 mac_mask[ETH_ALEN];
2039 int ret;
2040
2041 /* Setup unicast pkt pattern */
Joe Perches93803b32015-03-02 19:54:49 -08002042 eth_broadcast_addr(mac_mask);
Raja Manid91e8ee2012-01-30 17:13:10 +05302043 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2044 vif->fw_vif_idx, WOW_LIST_ID,
2045 ETH_ALEN, 0, ndev->dev_addr,
2046 mac_mask);
2047 if (ret) {
2048 ath6kl_err("failed to add WOW unicast pattern\n");
2049 return ret;
2050 }
2051
2052 /*
2053 * Setup multicast pattern for mDNS 224.0.0.251,
2054 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
2055 */
2056 if ((ndev->flags & IFF_ALLMULTI) ||
2057 (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
2058 ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
2059 vif->fw_vif_idx, WOW_LIST_ID,
2060 sizeof(discvr_pattern), discvr_offset,
2061 discvr_pattern, discvr_mask);
2062 if (ret) {
Kalle Valocdeb8602012-04-12 11:02:18 +03002063 ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
Raja Manid91e8ee2012-01-30 17:13:10 +05302064 return ret;
2065 }
2066 }
2067
2068 return 0;
2069}
2070
Raja Mani055bde42012-03-21 15:03:37 +05302071static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
2072{
2073 return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2074}
2075
2076static bool is_ctrl_ep_empty(struct ath6kl *ar)
2077{
2078 return !ar->tx_pending[ar->ctrl_ep];
2079}
2080
2081static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
2082{
2083 int ret, left;
2084
2085 clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2086
2087 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2088 ATH6KL_HOST_MODE_ASLEEP);
2089 if (ret)
2090 return ret;
2091
2092 left = wait_event_interruptible_timeout(ar->event_wq,
2093 is_hsleep_mode_procsed(vif),
2094 WMI_TIMEOUT);
2095 if (left == 0) {
2096 ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
2097 ret = -ETIMEDOUT;
2098 } else if (left < 0) {
2099 ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
2100 left);
2101 ret = left;
2102 }
2103
2104 if (ar->tx_pending[ar->ctrl_ep]) {
2105 left = wait_event_interruptible_timeout(ar->event_wq,
2106 is_ctrl_ep_empty(ar),
2107 WMI_TIMEOUT);
2108 if (left == 0) {
2109 ath6kl_warn("clear wmi ctrl data timeout\n");
2110 ret = -ETIMEDOUT;
2111 } else if (left < 0) {
2112 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
2113 ret = left;
2114 }
2115 }
2116
2117 return ret;
2118}
2119
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002120static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
2121 struct cfg80211_wowlan *wow, u32 *filter)
Raja Manid91e8ee2012-01-30 17:13:10 +05302122{
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002123 struct ath6kl *ar = vif->ar;
Raja Manid91e8ee2012-01-30 17:13:10 +05302124 struct in_device *in_dev;
2125 struct in_ifaddr *ifa;
Raja Mani055bde42012-03-21 15:03:37 +05302126 int ret;
Raja Manice0dc0c2012-02-20 19:08:08 +05302127 u16 i, bmiss_time;
Raja Manid91e8ee2012-01-30 17:13:10 +05302128 __be32 ips[MAX_IP_ADDRS];
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002129 u8 index = 0;
Raja Manid91e8ee2012-01-30 17:13:10 +05302130
Naveen Gangadharan6821d4f2012-05-11 14:19:09 -07002131 if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
2132 test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
2133 ar->fw_capabilities)) {
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002134 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
2135 vif->fw_vif_idx, false);
2136 if (ret)
2137 return ret;
2138 }
2139
Raja Manid91e8ee2012-01-30 17:13:10 +05302140 /* Clear existing WOW patterns */
2141 for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
2142 ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
2143 WOW_LIST_ID, i);
2144
2145 /*
2146 * Skip the default WOW pattern configuration
2147 * if the driver receives any WOW patterns from
2148 * the user.
2149 */
2150 if (wow)
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002151 ret = ath6kl_wow_usr(ar, vif, wow, filter);
Raja Manid91e8ee2012-01-30 17:13:10 +05302152 else if (vif->nw_type == AP_NETWORK)
2153 ret = ath6kl_wow_ap(ar, vif);
2154 else
2155 ret = ath6kl_wow_sta(ar, vif);
2156
2157 if (ret)
2158 return ret;
2159
Raja Mani390a8c82012-03-07 11:35:04 +05302160 netif_stop_queue(vif->ndev);
2161
Raja Manice0dc0c2012-02-20 19:08:08 +05302162 if (vif->nw_type != AP_NETWORK) {
2163 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2164 ATH6KL_MAX_WOW_LISTEN_INTL,
2165 0);
2166 if (ret)
2167 return ret;
2168
2169 /* Set listen interval x 15 times as bmiss time */
2170 bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
2171 if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
2172 bmiss_time = ATH6KL_MAX_BMISS_TIME;
2173
2174 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2175 bmiss_time, 0);
2176 if (ret)
2177 return ret;
2178
2179 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2180 0xFFFF, 0, 0xFFFF, 0, 0, 0,
2181 0, 0, 0, 0);
2182 if (ret)
2183 return ret;
2184 }
2185
Raja Manic08631c2011-12-16 14:24:24 +05302186 /* Setup own IP addr for ARP agent. */
2187 in_dev = __in_dev_get_rtnl(vif->ndev);
2188 if (!in_dev)
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002189 return 0;
Raja Manic08631c2011-12-16 14:24:24 +05302190
2191 ifa = in_dev->ifa_list;
2192 memset(&ips, 0, sizeof(ips));
2193
2194 /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
2195 while (index < MAX_IP_ADDRS && ifa) {
2196 ips[index] = ifa->ifa_local;
2197 ifa = ifa->ifa_next;
2198 index++;
2199 }
2200
2201 if (ifa) {
2202 ath6kl_err("total IP addr count is exceeding fw limit\n");
2203 return -EINVAL;
2204 }
2205
2206 ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
2207 if (ret) {
2208 ath6kl_err("fail to setup ip for arp agent\n");
2209 return ret;
2210 }
2211
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002212 return ret;
2213}
2214
2215static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
2216{
2217 struct ath6kl_vif *first_vif, *vif;
2218 int ret = 0;
2219 u32 filter = 0;
2220 bool connected = false;
2221
2222 /* enter / leave wow suspend on first vif always */
2223 first_vif = ath6kl_vif_first(ar);
Geliang Tangbffb7db2015-10-05 20:46:12 +08002224 if (WARN_ON(!first_vif) ||
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002225 !ath6kl_cfg80211_ready(first_vif))
2226 return -EIO;
2227
2228 if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
2229 return -EINVAL;
2230
2231 /* install filters for each connected vif */
2232 spin_lock_bh(&ar->list_lock);
2233 list_for_each_entry(vif, &ar->vif_list, list) {
2234 if (!test_bit(CONNECTED, &vif->flags) ||
2235 !ath6kl_cfg80211_ready(vif))
2236 continue;
2237 connected = true;
2238
2239 ret = ath6kl_wow_suspend_vif(vif, wow, &filter);
2240 if (ret)
2241 break;
2242 }
2243 spin_unlock_bh(&ar->list_lock);
2244
2245 if (!connected)
2246 return -ENOTCONN;
2247 else if (ret)
2248 return ret;
2249
2250 ar->state = ATH6KL_STATE_SUSPENDING;
2251
2252 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,
Raja Mani6cb3c712011-11-07 22:52:45 +02002253 ATH6KL_WOW_MODE_ENABLE,
2254 filter,
2255 WOW_HOST_REQ_DELAY);
2256 if (ret)
2257 return ret;
2258
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002259 return ath6kl_cfg80211_host_sleep(ar, first_vif);
Raja Mani6cb3c712011-11-07 22:52:45 +02002260}
2261
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002262static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)
Raja Mani6cb3c712011-11-07 22:52:45 +02002263{
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002264 struct ath6kl *ar = vif->ar;
Raja Mani6cb3c712011-11-07 22:52:45 +02002265 int ret;
2266
Raja Manice0dc0c2012-02-20 19:08:08 +05302267 if (vif->nw_type != AP_NETWORK) {
2268 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2269 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2270 if (ret)
2271 return ret;
2272
2273 ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
2274 vif->listen_intvl_t, 0);
2275 if (ret)
2276 return ret;
2277
2278 ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
2279 vif->bmiss_time_t, 0);
2280 if (ret)
2281 return ret;
2282 }
2283
Naveen Gangadharan6821d4f2012-05-11 14:19:09 -07002284 if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
2285 test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
2286 ar->fw_capabilities)) {
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002287 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002288 vif->fw_vif_idx, true);
Naveen Gangadharan6251d802012-04-20 12:46:56 -07002289 if (ret)
2290 return ret;
2291 }
2292
Raja Mani390a8c82012-03-07 11:35:04 +05302293 netif_wake_queue(vif->ndev);
2294
2295 return 0;
Raja Mani6cb3c712011-11-07 22:52:45 +02002296}
2297
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002298static int ath6kl_wow_resume(struct ath6kl *ar)
2299{
2300 struct ath6kl_vif *vif;
2301 int ret;
2302
2303 vif = ath6kl_vif_first(ar);
Geliang Tangbffb7db2015-10-05 20:46:12 +08002304 if (WARN_ON(!vif) ||
Thomas Pedersenfd4377b2012-08-09 17:32:33 -07002305 !ath6kl_cfg80211_ready(vif))
2306 return -EIO;
2307
2308 ar->state = ATH6KL_STATE_RESUMING;
2309
2310 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2311 ATH6KL_HOST_MODE_AWAKE);
2312 if (ret) {
2313 ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
2314 ret);
2315 goto cleanup;
2316 }
2317
2318 spin_lock_bh(&ar->list_lock);
2319 list_for_each_entry(vif, &ar->vif_list, list) {
2320 if (!test_bit(CONNECTED, &vif->flags) ||
2321 !ath6kl_cfg80211_ready(vif))
2322 continue;
2323 ret = ath6kl_wow_resume_vif(vif);
2324 if (ret)
2325 break;
2326 }
2327 spin_unlock_bh(&ar->list_lock);
2328
2329 if (ret)
2330 goto cleanup;
2331
2332 ar->state = ATH6KL_STATE_ON;
2333 return 0;
2334
2335cleanup:
2336 ar->state = ATH6KL_STATE_WOW;
2337 return ret;
2338}
2339
Raja Mani40abc2d2012-03-21 15:03:38 +05302340static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
2341{
2342 struct ath6kl_vif *vif;
2343 int ret;
2344
2345 vif = ath6kl_vif_first(ar);
2346 if (!vif)
2347 return -EIO;
2348
Ming Jiang48f27582012-04-13 21:09:25 +08002349 if (!test_bit(WMI_READY, &ar->flag)) {
2350 ath6kl_err("deepsleep failed as wmi is not ready\n");
Raja Mani40abc2d2012-03-21 15:03:38 +05302351 return -EIO;
Ming Jiang48f27582012-04-13 21:09:25 +08002352 }
Raja Mani40abc2d2012-03-21 15:03:38 +05302353
2354 ath6kl_cfg80211_stop_all(ar);
2355
2356 /* Save the current power mode before enabling power save */
2357 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2358
2359 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
2360 if (ret)
2361 return ret;
2362
2363 /* Disable WOW mode */
2364 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2365 ATH6KL_WOW_MODE_DISABLE,
2366 0, 0);
2367 if (ret)
2368 return ret;
2369
2370 /* Flush all non control pkts in TX path */
2371 ath6kl_tx_data_cleanup(ar);
2372
2373 ret = ath6kl_cfg80211_host_sleep(ar, vif);
2374 if (ret)
2375 return ret;
2376
2377 return 0;
2378}
2379
2380static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
2381{
2382 struct ath6kl_vif *vif;
2383 int ret;
2384
2385 vif = ath6kl_vif_first(ar);
2386
2387 if (!vif)
2388 return -EIO;
2389
2390 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
2391 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
2392 ar->wmi->saved_pwr_mode);
2393 if (ret)
2394 return ret;
2395 }
2396
2397 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2398 ATH6KL_HOST_MODE_AWAKE);
2399 if (ret)
2400 return ret;
2401
2402 ar->state = ATH6KL_STATE_ON;
2403
2404 /* Reset scan parameter to default values */
2405 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2406 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2407 if (ret)
2408 return ret;
2409
2410 return 0;
2411}
2412
Kalle Valo52d81a62011-11-01 08:44:21 +02002413int ath6kl_cfg80211_suspend(struct ath6kl *ar,
Raja Mani0f60e9f2011-11-07 22:52:45 +02002414 enum ath6kl_cfg_suspend_mode mode,
2415 struct cfg80211_wowlan *wow)
Kalle Valo52d81a62011-11-01 08:44:21 +02002416{
Vivek Natarajan3d794992012-03-28 19:21:26 +05302417 struct ath6kl_vif *vif;
Raja Mani390a8c82012-03-07 11:35:04 +05302418 enum ath6kl_state prev_state;
Kalle Valo52d81a62011-11-01 08:44:21 +02002419 int ret;
2420
Kalle Valo52d81a62011-11-01 08:44:21 +02002421 switch (mode) {
Raja Manid7c44e02011-11-07 22:52:46 +02002422 case ATH6KL_CFG_SUSPEND_WOW:
2423
2424 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
2425
2426 /* Flush all non control pkts in TX path */
2427 ath6kl_tx_data_cleanup(ar);
2428
Raja Mani390a8c82012-03-07 11:35:04 +05302429 prev_state = ar->state;
2430
Raja Manid7c44e02011-11-07 22:52:46 +02002431 ret = ath6kl_wow_suspend(ar, wow);
Raja Mani390a8c82012-03-07 11:35:04 +05302432 if (ret) {
2433 ar->state = prev_state;
Raja Manid7c44e02011-11-07 22:52:46 +02002434 return ret;
Raja Mani390a8c82012-03-07 11:35:04 +05302435 }
Raja Mani1e9a9052012-03-06 15:03:59 +05302436
Raja Manid7c44e02011-11-07 22:52:46 +02002437 ar->state = ATH6KL_STATE_WOW;
2438 break;
2439
Kalle Valo52d81a62011-11-01 08:44:21 +02002440 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
Raja Mani524441e2011-11-07 22:52:46 +02002441
Raja Mani40abc2d2012-03-21 15:03:38 +05302442 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n");
Raja Mani524441e2011-11-07 22:52:46 +02002443
Raja Mani40abc2d2012-03-21 15:03:38 +05302444 ret = ath6kl_cfg80211_deepsleep_suspend(ar);
Kalle Valo52d81a62011-11-01 08:44:21 +02002445 if (ret) {
Raja Mani40abc2d2012-03-21 15:03:38 +05302446 ath6kl_err("deepsleep suspend failed: %d\n", ret);
2447 return ret;
Kalle Valo52d81a62011-11-01 08:44:21 +02002448 }
2449
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002450 ar->state = ATH6KL_STATE_DEEPSLEEP;
2451
Kalle Valo52d81a62011-11-01 08:44:21 +02002452 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002453
2454 case ATH6KL_CFG_SUSPEND_CUTPOWER:
Raja Mani524441e2011-11-07 22:52:46 +02002455
Kalle Valo7125f012011-12-13 14:51:37 +02002456 ath6kl_cfg80211_stop_all(ar);
Raja Mani524441e2011-11-07 22:52:46 +02002457
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002458 if (ar->state == ATH6KL_STATE_OFF) {
2459 ath6kl_dbg(ATH6KL_DBG_SUSPEND,
2460 "suspend hw off, no action for cutpower\n");
2461 break;
2462 }
2463
2464 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");
2465
2466 ret = ath6kl_init_hw_stop(ar);
2467 if (ret) {
2468 ath6kl_warn("failed to stop hw during suspend: %d\n",
2469 ret);
2470 }
2471
2472 ar->state = ATH6KL_STATE_CUTPOWER;
2473
2474 break;
2475
2476 default:
2477 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002478 }
2479
Vivek Natarajan3d794992012-03-28 19:21:26 +05302480 list_for_each_entry(vif, &ar->vif_list, list)
2481 ath6kl_cfg80211_scan_complete_event(vif, true);
2482
Kalle Valo52d81a62011-11-01 08:44:21 +02002483 return 0;
2484}
Kalle Valod6a434d2012-01-17 20:09:36 +02002485EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
Kalle Valo52d81a62011-11-01 08:44:21 +02002486
2487int ath6kl_cfg80211_resume(struct ath6kl *ar)
2488{
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002489 int ret;
2490
2491 switch (ar->state) {
Raja Manid7c44e02011-11-07 22:52:46 +02002492 case ATH6KL_STATE_WOW:
2493 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
2494
2495 ret = ath6kl_wow_resume(ar);
2496 if (ret) {
2497 ath6kl_warn("wow mode resume failed: %d\n", ret);
2498 return ret;
2499 }
2500
Raja Manid7c44e02011-11-07 22:52:46 +02002501 break;
2502
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002503 case ATH6KL_STATE_DEEPSLEEP:
Raja Mani40abc2d2012-03-21 15:03:38 +05302504 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
2505
2506 ret = ath6kl_cfg80211_deepsleep_resume(ar);
2507 if (ret) {
2508 ath6kl_warn("deep sleep resume failed: %d\n", ret);
2509 return ret;
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002510 }
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002511 break;
2512
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002513 case ATH6KL_STATE_CUTPOWER:
2514 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");
2515
2516 ret = ath6kl_init_hw_start(ar);
2517 if (ret) {
2518 ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
2519 return ret;
2520 }
Raja Manid7c44e02011-11-07 22:52:46 +02002521 break;
Kalle Valob4b2a0b2011-11-01 08:44:44 +02002522
Kalle Valo76a9fbe2011-11-01 08:44:28 +02002523 default:
2524 break;
Kalle Valo52d81a62011-11-01 08:44:21 +02002525 }
2526
2527 return 0;
2528}
Kalle Valod6a434d2012-01-17 20:09:36 +02002529EXPORT_SYMBOL(ath6kl_cfg80211_resume);
Kalle Valo52d81a62011-11-01 08:44:21 +02002530
Kalle Valoabcb3442011-07-22 08:26:20 +03002531#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02002532
2533/* hif layer decides what suspend mode to use */
2534static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
Kalle Valoabcb3442011-07-22 08:26:20 +03002535 struct cfg80211_wowlan *wow)
2536{
2537 struct ath6kl *ar = wiphy_priv(wiphy);
2538
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302539 ath6kl_recovery_suspend(ar);
2540
Raja Mani0f60e9f2011-11-07 22:52:45 +02002541 return ath6kl_hif_suspend(ar, wow);
Kalle Valoabcb3442011-07-22 08:26:20 +03002542}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002543
Kalle Valo52d81a62011-11-01 08:44:21 +02002544static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002545{
2546 struct ath6kl *ar = wiphy_priv(wiphy);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302547 int err;
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002548
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302549 err = ath6kl_hif_resume(ar);
2550 if (err)
2551 return err;
2552
Vasanthakumar Thiagarajan92332992012-08-29 19:40:27 +05302553 ath6kl_recovery_resume(ar);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05302554
2555 return 0;
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002556}
Raja Mania918fb32011-11-07 22:52:46 +02002557
2558/*
2559 * FIXME: WOW suspend mode is selected if the host sdio controller supports
2560 * both sdio irq wake up and keep power. The target pulls sdio data line to
2561 * wake up the host when WOW pattern matches. This causes sdio irq handler
2562 * is being called in the host side which internally hits ath6kl's RX path.
2563 *
2564 * Since sdio interrupt is not disabled, RX path executes even before
2565 * the host executes the actual resume operation from PM module.
2566 *
2567 * In the current scenario, WOW resume should happen before start processing
2568 * any data from the target. So It's required to perform WOW resume in RX path.
2569 * Ideally we should perform WOW resume only in the actual platform
2570 * resume path. This area needs bit rework to avoid WOW resume in RX path.
2571 *
2572 * ath6kl_check_wow_status() is called from ath6kl_rx().
2573 */
2574void ath6kl_check_wow_status(struct ath6kl *ar)
2575{
Raja Mani390a8c82012-03-07 11:35:04 +05302576 if (ar->state == ATH6KL_STATE_SUSPENDING)
2577 return;
2578
Raja Mania918fb32011-11-07 22:52:46 +02002579 if (ar->state == ATH6KL_STATE_WOW)
2580 ath6kl_cfg80211_resume(ar);
2581}
2582
2583#else
2584
2585void ath6kl_check_wow_status(struct ath6kl *ar)
2586{
2587}
Kalle Valoabcb3442011-07-22 08:26:20 +03002588#endif
2589
Johannes Berg57fbcce2016-04-12 15:56:15 +02002590static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum nl80211_band band,
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302591 bool ht_enable)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002592{
Kiran Reddy67b3f122012-05-29 11:12:50 -07002593 struct ath6kl_htcap *htcap = &vif->htcap[band];
Sujith Manoharane68f6752011-12-22 12:15:27 +05302594
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302595 if (htcap->ht_enable == ht_enable)
2596 return 0;
Sujith Manoharane68f6752011-12-22 12:15:27 +05302597
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302598 if (ht_enable) {
2599 /* Set default ht capabilities */
2600 htcap->ht_enable = true;
Johannes Berg57fbcce2016-04-12 15:56:15 +02002601 htcap->cap_info = (band == NL80211_BAND_2GHZ) ?
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302602 ath6kl_g_htcap : ath6kl_a_htcap;
2603 htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
2604 } else /* Disable ht */
2605 memset(htcap, 0, sizeof(*htcap));
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002606
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302607 return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx,
2608 band, htcap);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002609}
2610
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002611static int ath6kl_restore_htcap(struct ath6kl_vif *vif)
2612{
2613 struct wiphy *wiphy = vif->ar->wiphy;
2614 int band, ret = 0;
2615
Johannes Berg57fbcce2016-04-12 15:56:15 +02002616 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002617 if (!wiphy->bands[band])
2618 continue;
2619
2620 ret = ath6kl_set_htcap(vif, band,
2621 wiphy->bands[band]->ht_cap.ht_supported);
2622 if (ret)
2623 return ret;
2624 }
2625
2626 return ret;
2627}
2628
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002629static bool ath6kl_is_p2p_ie(const u8 *pos)
2630{
2631 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
2632 pos[2] == 0x50 && pos[3] == 0x6f &&
2633 pos[4] == 0x9a && pos[5] == 0x09;
2634}
2635
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302636static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
2637 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002638{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302639 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002640 const u8 *pos;
2641 u8 *buf = NULL;
2642 size_t len = 0;
2643 int ret;
2644
2645 /*
2646 * Filter out P2P IE(s) since they will be included depending on
2647 * the Probe Request frame in ath6kl_send_go_probe_resp().
2648 */
2649
2650 if (ies && ies_len) {
2651 buf = kmalloc(ies_len, GFP_KERNEL);
2652 if (buf == NULL)
2653 return -ENOMEM;
2654 pos = ies;
2655 while (pos + 1 < ies + ies_len) {
2656 if (pos + 2 + pos[1] > ies + ies_len)
2657 break;
2658 if (!ath6kl_is_p2p_ie(pos)) {
2659 memcpy(buf + len, pos, 2 + pos[1]);
2660 len += 2 + pos[1];
2661 }
2662 pos += 2 + pos[1];
2663 }
2664 }
2665
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302666 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2667 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03002668 kfree(buf);
2669 return ret;
2670}
2671
Johannes Berg88600202012-02-13 15:17:18 +01002672static int ath6kl_set_ies(struct ath6kl_vif *vif,
2673 struct cfg80211_beacon_data *info)
2674{
2675 struct ath6kl *ar = vif->ar;
2676 int res;
2677
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002678 /* this also clears IE in fw if it's not set */
2679 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2680 WMI_FRAME_BEACON,
2681 info->beacon_ies,
2682 info->beacon_ies_len);
2683 if (res)
2684 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002685
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002686 /* this also clears IE in fw if it's not set */
2687 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
2688 info->proberesp_ies_len);
2689 if (res)
2690 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002691
Aarthi Thiruvengadam17a7b162012-03-08 12:25:02 -08002692 /* this also clears IE in fw if it's not set */
2693 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2694 WMI_FRAME_ASSOC_RESP,
2695 info->assocresp_ies,
2696 info->assocresp_ies_len);
2697 if (res)
2698 return res;
Johannes Berg88600202012-02-13 15:17:18 +01002699
2700 return 0;
2701}
2702
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302703static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
2704 u8 *rsn_capab)
2705{
2706 const u8 *rsn_ie;
2707 size_t rsn_ie_len;
2708 u16 cnt;
2709
2710 if (!beacon->tail)
2711 return -EINVAL;
2712
2713 rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
2714 if (!rsn_ie)
2715 return -EINVAL;
2716
2717 rsn_ie_len = *(rsn_ie + 1);
2718 /* skip element id and length */
2719 rsn_ie += 2;
2720
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302721 /* skip version */
2722 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302723 return -EINVAL;
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302724 rsn_ie += 2;
2725 rsn_ie_len -= 2;
2726
2727 /* skip group cipher suite */
2728 if (rsn_ie_len < 4)
2729 return 0;
2730 rsn_ie += 4;
2731 rsn_ie_len -= 4;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302732
2733 /* skip pairwise cipher suite */
2734 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302735 return 0;
Vasanthakumar Thiagarajan798985c2012-04-10 13:35:47 +05302736 cnt = get_unaligned_le16(rsn_ie);
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302737 rsn_ie += (2 + cnt * 4);
2738 rsn_ie_len -= (2 + cnt * 4);
2739
2740 /* skip akm suite */
2741 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302742 return 0;
Vasanthakumar Thiagarajan798985c2012-04-10 13:35:47 +05302743 cnt = get_unaligned_le16(rsn_ie);
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302744 rsn_ie += (2 + cnt * 4);
2745 rsn_ie_len -= (2 + cnt * 4);
2746
2747 if (rsn_ie_len < 2)
Vasanthakumar Thiagarajan9e8b16d2012-04-10 14:27:47 +05302748 return 0;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302749
2750 memcpy(rsn_capab, rsn_ie, 2);
2751
2752 return 0;
2753}
2754
Johannes Berg88600202012-02-13 15:17:18 +01002755static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2756 struct cfg80211_ap_settings *info)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002757{
2758 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302759 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002760 struct ieee80211_mgmt *mgmt;
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002761 bool hidden = false;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002762 u8 *ies;
2763 int ies_len;
2764 struct wmi_connect_cmd p;
2765 int res;
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302766 int i, ret;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302767 u16 rsn_capab = 0;
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302768 int inactivity_timeout = 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002769
Johannes Berg88600202012-02-13 15:17:18 +01002770 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002771
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302772 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002773 return -EIO;
2774
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302775 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002776 return -EOPNOTSUPP;
2777
Johannes Berg88600202012-02-13 15:17:18 +01002778 res = ath6kl_set_ies(vif, &info->beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002779
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002780 ar->ap_mode_bkey.valid = false;
2781
Mohammed Shafi Shajakhaneb922e42012-11-16 18:23:15 +05302782 ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx,
2783 info->beacon_interval);
2784
2785 if (ret)
2786 ath6kl_warn("Failed to set beacon interval: %d\n", ret);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002787
Etay Luzd154f322012-05-30 11:35:08 +03002788 ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
2789 info->dtim_period);
2790
2791 /* ignore error, just print a warning and continue normally */
2792 if (ret)
2793 ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
2794
Johannes Berg88600202012-02-13 15:17:18 +01002795 if (info->beacon.head == NULL)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002796 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002797 mgmt = (struct ieee80211_mgmt *) info->beacon.head;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002798 ies = mgmt->u.beacon.variable;
Johannes Berg88600202012-02-13 15:17:18 +01002799 if (ies > info->beacon.head + info->beacon.head_len)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002800 return -EINVAL;
Johannes Berg88600202012-02-13 15:17:18 +01002801 ies_len = info->beacon.head + info->beacon.head_len - ies;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002802
2803 if (info->ssid == NULL)
2804 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302805 memcpy(vif->ssid, info->ssid, info->ssid_len);
2806 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002807 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
Thomas Pedersen67cd22e2012-02-28 15:08:46 -08002808 hidden = true;
2809
2810 res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
2811 if (res)
2812 return res;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002813
Vasanthakumar Thiagarajanbe5abaa2011-11-11 20:33:01 +05302814 ret = ath6kl_set_auth_type(vif, info->auth_type);
2815 if (ret)
2816 return ret;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002817
2818 memset(&p, 0, sizeof(p));
2819
2820 for (i = 0; i < info->crypto.n_akm_suites; i++) {
2821 switch (info->crypto.akm_suites[i]) {
2822 case WLAN_AKM_SUITE_8021X:
2823 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2824 p.auth_mode |= WPA_AUTH;
2825 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2826 p.auth_mode |= WPA2_AUTH;
2827 break;
2828 case WLAN_AKM_SUITE_PSK:
2829 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
2830 p.auth_mode |= WPA_PSK_AUTH;
2831 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
2832 p.auth_mode |= WPA2_PSK_AUTH;
2833 break;
2834 }
2835 }
2836 if (p.auth_mode == 0)
2837 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302838 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002839
2840 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
2841 switch (info->crypto.ciphers_pairwise[i]) {
2842 case WLAN_CIPHER_SUITE_WEP40:
2843 case WLAN_CIPHER_SUITE_WEP104:
2844 p.prwise_crypto_type |= WEP_CRYPT;
2845 break;
2846 case WLAN_CIPHER_SUITE_TKIP:
2847 p.prwise_crypto_type |= TKIP_CRYPT;
2848 break;
2849 case WLAN_CIPHER_SUITE_CCMP:
2850 p.prwise_crypto_type |= AES_CRYPT;
2851 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002852 case WLAN_CIPHER_SUITE_SMS4:
2853 p.prwise_crypto_type |= WAPI_CRYPT;
2854 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002855 }
2856 }
Edward Lu229ed6b2011-08-30 21:58:07 +03002857 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002858 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302859 ath6kl_set_cipher(vif, 0, true);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +02002860 } else if (info->crypto.n_ciphers_pairwise == 1) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302861 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Kalle Valoa5d8f9d2014-03-11 12:58:01 +02002862 }
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002863
2864 switch (info->crypto.cipher_group) {
2865 case WLAN_CIPHER_SUITE_WEP40:
2866 case WLAN_CIPHER_SUITE_WEP104:
2867 p.grp_crypto_type = WEP_CRYPT;
2868 break;
2869 case WLAN_CIPHER_SUITE_TKIP:
2870 p.grp_crypto_type = TKIP_CRYPT;
2871 break;
2872 case WLAN_CIPHER_SUITE_CCMP:
2873 p.grp_crypto_type = AES_CRYPT;
2874 break;
Dai Shuibingb8214df2011-11-03 11:39:38 +02002875 case WLAN_CIPHER_SUITE_SMS4:
2876 p.grp_crypto_type = WAPI_CRYPT;
2877 break;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002878 default:
2879 p.grp_crypto_type = NONE_CRYPT;
2880 break;
2881 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05302882 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002883
2884 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302885 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002886
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05302887 p.ssid_len = vif->ssid_len;
2888 memcpy(p.ssid, vif->ssid, vif->ssid_len);
2889 p.dot11_auth_mode = vif->dot11_auth_mode;
Johannes Berg683b6d32012-11-08 21:25:48 +01002890 p.ch = cpu_to_le16(info->chandef.chan->center_freq);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002891
Thirumalai Pachamuthuc1762a32012-01-12 18:21:39 +05302892 /* Enable uAPSD support by default */
2893 res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
2894 if (res < 0)
2895 return res;
2896
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08002897 if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
2898 p.nw_subtype = SUBTYPE_P2PGO;
2899 } else {
2900 /*
2901 * Due to firmware limitation, it is not possible to
2902 * do P2P mgmt operations in AP mode
2903 */
2904 p.nw_subtype = SUBTYPE_NONE;
2905 }
2906
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302907 if (info->inactivity_timeout) {
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302908 inactivity_timeout = info->inactivity_timeout;
2909
Kalle Valoeba95bc2014-06-17 12:40:52 +03002910 if (test_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS,
2911 ar->fw_capabilities))
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302912 inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
2913 60);
2914
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302915 res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
Mohammed Shafi Shajakhan7ac25ea2012-09-27 18:19:51 +05302916 inactivity_timeout);
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05302917 if (res < 0)
2918 return res;
2919 }
2920
Johannes Berg683b6d32012-11-08 21:25:48 +01002921 if (ath6kl_set_htcap(vif, info->chandef.chan->band,
2922 cfg80211_get_chandef_type(&info->chandef)
2923 != NL80211_CHAN_NO_HT))
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302924 return -EIO;
2925
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302926 /*
2927 * Get the PTKSA replay counter in the RSN IE. Supplicant
2928 * will use the RSN IE in M3 message and firmware has to
2929 * advertise the same in beacon/probe response. Send
2930 * the complete RSN IE capability field to firmware
2931 */
2932 if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
2933 test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
2934 ar->fw_capabilities)) {
2935 res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
2936 WLAN_EID_RSN, WMI_RSN_IE_CAPB,
2937 (const u8 *) &rsn_capab,
2938 sizeof(rsn_capab));
Thomas Pedersenf21243a2012-07-27 18:13:27 -07002939 vif->rsn_capab = rsn_capab;
Vasanthakumar Thiagarajand97c1212012-04-09 20:51:20 +05302940 if (res < 0)
2941 return res;
2942 }
2943
Thomas Pedersenc4f78632012-04-06 13:35:48 -07002944 memcpy(&vif->profile, &p, sizeof(p));
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302945 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03002946 if (res < 0)
2947 return res;
2948
2949 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002950}
2951
Johannes Berg88600202012-02-13 15:17:18 +01002952static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
2953 struct cfg80211_beacon_data *beacon)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002954{
Johannes Berg88600202012-02-13 15:17:18 +01002955 struct ath6kl_vif *vif = netdev_priv(dev);
2956
2957 if (!ath6kl_cfg80211_ready(vif))
2958 return -EIO;
2959
2960 if (vif->next_mode != AP_NETWORK)
2961 return -EOPNOTSUPP;
2962
2963 return ath6kl_set_ies(vif, beacon);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002964}
2965
Johannes Berg88600202012-02-13 15:17:18 +01002966static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002967{
2968 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302969 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002970
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05302971 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002972 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302973 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002974 return -ENOTCONN;
2975
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302976 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302977 clear_bit(CONNECTED, &vif->flags);
Pierre Le Magourou76b817f2016-07-18 23:22:20 +03002978 netif_carrier_off(vif->ndev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002979
Vasanthakumar Thiagarajandf90b362012-04-09 19:03:58 +05302980 /* Restore ht setting in firmware */
Thomas Pedersen37a2f952012-04-19 15:31:57 -07002981 return ath6kl_restore_htcap(vif);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002982}
2983
Jouni Malinen33e53082011-12-27 11:02:56 +02002984static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2985
2986static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03002987 struct station_del_parameters *params)
Jouni Malinen33e53082011-12-27 11:02:56 +02002988{
2989 struct ath6kl *ar = ath6kl_priv(dev);
2990 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen89c771e2014-10-10 20:52:40 +03002991 const u8 *addr = params->mac ? params->mac : bcast_addr;
Jouni Malinen33e53082011-12-27 11:02:56 +02002992
2993 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
2994 addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
2995}
2996
Jouni Malinen23875132011-08-30 21:57:53 +03002997static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002998 const u8 *mac,
2999 struct station_parameters *params)
Jouni Malinen23875132011-08-30 21:57:53 +03003000{
3001 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05303002 struct ath6kl_vif *vif = netdev_priv(dev);
Johannes Berg77ee7c82013-02-15 00:48:33 +01003003 int err;
Jouni Malinen23875132011-08-30 21:57:53 +03003004
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05303005 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03003006 return -EOPNOTSUPP;
3007
Johannes Berg77ee7c82013-02-15 00:48:33 +01003008 err = cfg80211_check_station_change(wiphy, params,
3009 CFG80211_STA_AP_MLME_CLIENT);
3010 if (err)
3011 return err;
Jouni Malinen23875132011-08-30 21:57:53 +03003012
3013 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303014 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
3015 WMI_AP_MLME_AUTHORIZE, mac, 0);
3016 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
3017 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03003018}
3019
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003020static int ath6kl_remain_on_channel(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003021 struct wireless_dev *wdev,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003022 struct ieee80211_channel *chan,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003023 unsigned int duration,
3024 u64 *cookie)
3025{
Johannes Berg71bbc992012-06-15 15:30:18 +02003026 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3027 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Jouni Malinen10522612011-10-27 16:00:13 +03003028 u32 id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003029
3030 /* TODO: if already pending or ongoing remain-on-channel,
3031 * return -EBUSY */
Jouni Malinen10522612011-10-27 16:00:13 +03003032 id = ++vif->last_roc_id;
3033 if (id == 0) {
3034 /* Do not use 0 as the cookie value */
3035 id = ++vif->last_roc_id;
3036 }
3037 *cookie = id;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003038
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303039 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
3040 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003041}
3042
3043static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003044 struct wireless_dev *wdev,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003045 u64 cookie)
3046{
Johannes Berg71bbc992012-06-15 15:30:18 +02003047 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3048 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003049
Jouni Malinen10522612011-10-27 16:00:13 +03003050 if (cookie != vif->last_roc_id)
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003051 return -ENOENT;
Jouni Malinen10522612011-10-27 16:00:13 +03003052 vif->last_cancel_roc_id = cookie;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003053
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303054 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003055}
3056
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303057static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
3058 const u8 *buf, size_t len,
3059 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003060{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303061 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003062 const u8 *pos;
3063 u8 *p2p;
3064 int p2p_len;
3065 int ret;
3066 const struct ieee80211_mgmt *mgmt;
3067
3068 mgmt = (const struct ieee80211_mgmt *) buf;
3069
3070 /* Include P2P IE(s) from the frame generated in user space. */
3071
3072 p2p = kmalloc(len, GFP_KERNEL);
3073 if (p2p == NULL)
3074 return -ENOMEM;
3075 p2p_len = 0;
3076
3077 pos = mgmt->u.probe_resp.variable;
3078 while (pos + 1 < buf + len) {
3079 if (pos + 2 + pos[1] > buf + len)
3080 break;
3081 if (ath6kl_is_p2p_ie(pos)) {
3082 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
3083 p2p_len += 2 + pos[1];
3084 }
3085 pos += 2 + pos[1];
3086 }
3087
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303088 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
3089 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003090 kfree(p2p);
3091 return ret;
3092}
3093
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003094static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
3095 u32 id,
3096 u32 freq,
3097 u32 wait,
3098 const u8 *buf,
3099 size_t len,
3100 bool *more_data,
3101 bool no_cck)
3102{
3103 struct ieee80211_mgmt *mgmt;
3104 struct ath6kl_sta *conn;
3105 bool is_psq_empty = false;
3106 struct ath6kl_mgmt_buff *mgmt_buf;
3107 size_t mgmt_buf_size;
3108 struct ath6kl *ar = vif->ar;
3109
3110 mgmt = (struct ieee80211_mgmt *) buf;
3111 if (is_multicast_ether_addr(mgmt->da))
3112 return false;
3113
3114 conn = ath6kl_find_sta(vif, mgmt->da);
3115 if (!conn)
3116 return false;
3117
3118 if (conn->sta_flags & STA_PS_SLEEP) {
3119 if (!(conn->sta_flags & STA_PS_POLLED)) {
3120 /* Queue the frames if the STA is sleeping */
3121 mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
3122 mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
3123 if (!mgmt_buf)
3124 return false;
3125
3126 INIT_LIST_HEAD(&mgmt_buf->list);
3127 mgmt_buf->id = id;
3128 mgmt_buf->freq = freq;
3129 mgmt_buf->wait = wait;
3130 mgmt_buf->len = len;
3131 mgmt_buf->no_cck = no_cck;
3132 memcpy(mgmt_buf->buf, buf, len);
3133 spin_lock_bh(&conn->psq_lock);
3134 is_psq_empty = skb_queue_empty(&conn->psq) &&
3135 (conn->mgmt_psq_len == 0);
3136 list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
3137 conn->mgmt_psq_len++;
3138 spin_unlock_bh(&conn->psq_lock);
3139
3140 /*
3141 * If this is the first pkt getting queued
3142 * for this STA, update the PVB for this
3143 * STA.
3144 */
3145 if (is_psq_empty)
3146 ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
3147 conn->aid, 1);
3148 return true;
3149 }
3150
3151 /*
3152 * This tx is because of a PsPoll.
3153 * Determine if MoreData bit has to be set.
3154 */
3155 spin_lock_bh(&conn->psq_lock);
3156 if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
3157 *more_data = true;
3158 spin_unlock_bh(&conn->psq_lock);
3159 }
3160
3161 return false;
3162}
3163
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003164/* Check if SSID length is greater than DIRECT- */
3165static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
3166{
3167 const struct ieee80211_mgmt *mgmt;
3168 mgmt = (const struct ieee80211_mgmt *) buf;
3169
3170 /* variable[1] contains the SSID tag length */
3171 if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
3172 (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
3173 return true;
3174 }
3175
3176 return false;
3177}
3178
Johannes Berg71bbc992012-06-15 15:30:18 +02003179static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003180 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003181{
Johannes Berg71bbc992012-06-15 15:30:18 +02003182 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
3183 struct ath6kl *ar = ath6kl_priv(vif->ndev);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003184 struct ieee80211_channel *chan = params->chan;
3185 const u8 *buf = params->buf;
3186 size_t len = params->len;
3187 unsigned int wait = params->wait;
3188 bool no_cck = params->no_cck;
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003189 u32 id, freq;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003190 const struct ieee80211_mgmt *mgmt;
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003191 bool more_data, queued;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003192
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003193 /* default to the current channel, but use the one specified as argument
3194 * if any
3195 */
3196 freq = vif->ch_hint;
3197 if (chan)
3198 freq = chan->center_freq;
3199
3200 /* never send freq zero to the firmware */
3201 if (WARN_ON(freq == 0))
3202 return -EINVAL;
3203
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003204 mgmt = (const struct ieee80211_mgmt *) buf;
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003205 if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
3206 ieee80211_is_probe_resp(mgmt->frame_control) &&
3207 ath6kl_is_p2p_go_ssid(buf, len)) {
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003208 /*
Aarthi Thiruvengadamc86e4f42012-03-15 14:34:56 -07003209 * Send Probe Response frame in GO mode using a separate WMI
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003210 * command to allow the target to fill in the generic IEs.
3211 */
3212 *cookie = 0; /* TX status not supported */
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003213 return ath6kl_send_go_probe_resp(vif, buf, len, freq);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03003214 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003215
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303216 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003217 if (id == 0) {
3218 /*
3219 * 0 is a reserved value in the WMI command and shall not be
3220 * used for the command.
3221 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303222 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003223 }
3224
3225 *cookie = id;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08003226
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003227 /* AP mode Power saving processing */
3228 if (vif->nw_type == AP_NETWORK) {
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003229 queued = ath6kl_mgmt_powersave_ap(vif, id, freq, wait, buf, len,
3230 &more_data, no_cck);
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003231 if (queued)
3232 return 0;
Aarthi Thiruvengadam3ca9d1f2011-12-13 13:32:12 -08003233 }
Naveen Gangadharand0ff7382012-02-08 17:51:36 -08003234
Antonio Quartullibfd634d2013-06-11 14:20:02 +02003235 return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, freq,
3236 wait, buf, len, no_cck);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003237}
3238
Ben Greear9c2e90f2015-10-21 14:53:19 -07003239static int ath6kl_get_antenna(struct wiphy *wiphy,
3240 u32 *tx_ant, u32 *rx_ant)
3241{
3242 struct ath6kl *ar = wiphy_priv(wiphy);
3243 *tx_ant = ar->hw.tx_ant;
3244 *rx_ant = ar->hw.rx_ant;
3245 return 0;
3246}
3247
Jouni Malinenae32c302011-08-30 21:58:01 +03003248static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
Johannes Berg71bbc992012-06-15 15:30:18 +02003249 struct wireless_dev *wdev,
Jouni Malinenae32c302011-08-30 21:58:01 +03003250 u16 frame_type, bool reg)
3251{
Johannes Berg71bbc992012-06-15 15:30:18 +02003252 struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
Jouni Malinenae32c302011-08-30 21:58:01 +03003253
3254 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
3255 __func__, frame_type, reg);
3256 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
3257 /*
3258 * Note: This notification callback is not allowed to sleep, so
3259 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
3260 * hardcode target to report Probe Request frames all the time.
3261 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05303262 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03003263 }
3264}
3265
Kalle Valo10509f92011-12-13 14:52:07 +02003266static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3267 struct net_device *dev,
3268 struct cfg80211_sched_scan_request *request)
3269{
3270 struct ath6kl *ar = ath6kl_priv(dev);
3271 struct ath6kl_vif *vif = netdev_priv(dev);
3272 u16 interval;
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003273 int ret, rssi_thold;
Johannes Bergea73cbc2014-01-24 10:53:53 +01003274 int n_match_sets = request->n_match_sets;
3275
3276 /*
3277 * If there's a matchset w/o an SSID, then assume it's just for
3278 * the RSSI (nothing else is currently supported) and ignore it.
3279 * The device only supports a global RSSI filter that we set below.
3280 */
3281 if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
3282 n_match_sets = 0;
Kalle Valo10509f92011-12-13 14:52:07 +02003283
3284 if (ar->state != ATH6KL_STATE_ON)
3285 return -EIO;
3286
3287 if (vif->sme_state != SME_DISCONNECTED)
3288 return -EBUSY;
3289
Kalle Valob4d13d32012-03-21 10:01:09 +02003290 ath6kl_cfg80211_scan_complete_event(vif, true);
3291
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03003292 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
Naveen Singhdd45b752012-05-16 13:29:00 +03003293 request->n_ssids,
3294 request->match_sets,
Johannes Bergea73cbc2014-01-24 10:53:53 +01003295 n_match_sets);
Jouni Malinen3b8ffc62012-04-16 19:28:03 +03003296 if (ret < 0)
3297 return ret;
Kalle Valo10509f92011-12-13 14:52:07 +02003298
Johannes Bergea73cbc2014-01-24 10:53:53 +01003299 if (!n_match_sets) {
Naveen Singhdd45b752012-05-16 13:29:00 +03003300 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
3301 ALL_BSS_FILTER, 0);
3302 if (ret < 0)
3303 return ret;
3304 } else {
3305 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
3306 MATCHED_SSID_FILTER, 0);
3307 if (ret < 0)
3308 return ret;
3309 }
3310
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003311 if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
3312 ar->fw_capabilities)) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01003313 if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003314 rssi_thold = 0;
Johannes Bergea73cbc2014-01-24 10:53:53 +01003315 else if (request->min_rssi_thold < -127)
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003316 rssi_thold = -127;
3317 else
Johannes Bergea73cbc2014-01-24 10:53:53 +01003318 rssi_thold = request->min_rssi_thold;
Thomas Pedersen85b20fc2012-06-21 12:50:08 -07003319
3320 ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
3321 rssi_thold);
3322 if (ret) {
3323 ath6kl_err("failed to set RSSI threshold for scan\n");
3324 return ret;
3325 }
3326 }
3327
Kalle Valo10509f92011-12-13 14:52:07 +02003328 /* fw uses seconds, also make sure that it's >0 */
Avraham Stern3b06d272015-10-12 09:51:34 +03003329 interval = max_t(u16, 1, request->scan_plans[0].interval);
Kalle Valo10509f92011-12-13 14:52:07 +02003330
3331 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
3332 interval, interval,
Subramania Sharma Thandaveswarand472b5e2012-04-16 16:09:57 +05303333 vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
Kalle Valo10509f92011-12-13 14:52:07 +02003334
Kalle Valo10509f92011-12-13 14:52:07 +02003335 /* this also clears IE in fw if it's not set */
3336 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
3337 WMI_FRAME_PROBE_REQ,
3338 request->ie, request->ie_len);
3339 if (ret) {
Joe Perchesf1ff32e2012-05-30 01:58:39 -07003340 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
Kalle Valo10509f92011-12-13 14:52:07 +02003341 ret);
3342 return ret;
3343 }
3344
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003345 ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
3346 if (ret)
Kalle Valo10509f92011-12-13 14:52:07 +02003347 return ret;
Kalle Valo10509f92011-12-13 14:52:07 +02003348
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003349 set_bit(SCHED_SCANNING, &vif->flags);
Kalle Valo10509f92011-12-13 14:52:07 +02003350
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003351 return 0;
Kalle Valo10509f92011-12-13 14:52:07 +02003352}
3353
3354static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
3355 struct net_device *dev)
3356{
3357 struct ath6kl_vif *vif = netdev_priv(dev);
3358 bool stopped;
3359
3360 stopped = __ath6kl_cfg80211_sscan_stop(vif);
3361
3362 if (!stopped)
3363 return -EIO;
3364
3365 return 0;
3366}
3367
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303368static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
3369 struct net_device *dev,
3370 const u8 *addr,
3371 const struct cfg80211_bitrate_mask *mask)
3372{
3373 struct ath6kl *ar = ath6kl_priv(dev);
3374 struct ath6kl_vif *vif = netdev_priv(dev);
3375
3376 return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
3377 mask);
3378}
3379
Thomas Pedersen279b2862012-07-17 19:39:55 -07003380static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy,
3381 struct net_device *dev,
3382 u32 rate, u32 pkts, u32 intvl)
3383{
3384 struct ath6kl *ar = ath6kl_priv(dev);
3385 struct ath6kl_vif *vif = netdev_priv(dev);
3386
3387 if (vif->nw_type != INFRA_NETWORK ||
3388 !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities))
3389 return -EOPNOTSUPP;
3390
3391 if (vif->sme_state != SME_CONNECTED)
3392 return -ENOTCONN;
3393
3394 /* save this since the firmware won't report the interval */
3395 vif->txe_intvl = intvl;
3396
3397 return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx,
3398 rate, pkts, intvl);
3399}
3400
Jouni Malinenf80574a2011-08-30 21:58:04 +03003401static const struct ieee80211_txrx_stypes
3402ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
3403 [NL80211_IFTYPE_STATION] = {
3404 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3405 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3406 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3407 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3408 },
Jouni Malinenba1f6fe2011-12-27 11:03:53 +02003409 [NL80211_IFTYPE_AP] = {
3410 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3411 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3412 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3413 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3414 },
Jouni Malinenf80574a2011-08-30 21:58:04 +03003415 [NL80211_IFTYPE_P2P_CLIENT] = {
3416 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3417 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3418 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3419 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3420 },
3421 [NL80211_IFTYPE_P2P_GO] = {
3422 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3423 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
3424 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3425 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3426 },
3427};
3428
Kalle Valobdcd8172011-07-18 00:22:30 +03003429static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303430 .add_virtual_intf = ath6kl_cfg80211_add_iface,
3431 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03003432 .change_virtual_intf = ath6kl_cfg80211_change_iface,
3433 .scan = ath6kl_cfg80211_scan,
3434 .connect = ath6kl_cfg80211_connect,
3435 .disconnect = ath6kl_cfg80211_disconnect,
3436 .add_key = ath6kl_cfg80211_add_key,
3437 .get_key = ath6kl_cfg80211_get_key,
3438 .del_key = ath6kl_cfg80211_del_key,
3439 .set_default_key = ath6kl_cfg80211_set_default_key,
3440 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
3441 .set_tx_power = ath6kl_cfg80211_set_txpower,
3442 .get_tx_power = ath6kl_cfg80211_get_txpower,
3443 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
3444 .join_ibss = ath6kl_cfg80211_join_ibss,
3445 .leave_ibss = ath6kl_cfg80211_leave_ibss,
3446 .get_station = ath6kl_get_station,
3447 .set_pmksa = ath6kl_set_pmksa,
3448 .del_pmksa = ath6kl_del_pmksa,
3449 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03003450 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03003451#ifdef CONFIG_PM
Kalle Valo52d81a62011-11-01 08:44:21 +02003452 .suspend = __ath6kl_cfg80211_suspend,
3453 .resume = __ath6kl_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03003454#endif
Johannes Berg88600202012-02-13 15:17:18 +01003455 .start_ap = ath6kl_start_ap,
3456 .change_beacon = ath6kl_change_beacon,
3457 .stop_ap = ath6kl_stop_ap,
Jouni Malinen33e53082011-12-27 11:02:56 +02003458 .del_station = ath6kl_del_station,
Jouni Malinen23875132011-08-30 21:57:53 +03003459 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03003460 .remain_on_channel = ath6kl_remain_on_channel,
3461 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03003462 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03003463 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Ben Greear9c2e90f2015-10-21 14:53:19 -07003464 .get_antenna = ath6kl_get_antenna,
Kalle Valo10509f92011-12-13 14:52:07 +02003465 .sched_scan_start = ath6kl_cfg80211_sscan_start,
3466 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303467 .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
Thomas Pedersen279b2862012-07-17 19:39:55 -07003468 .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,
Kalle Valobdcd8172011-07-18 00:22:30 +03003469};
3470
Kalle Valo7125f012011-12-13 14:51:37 +02003471void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
Kalle Valoec4b7f62011-11-01 08:44:04 +02003472{
Kalle Valo10509f92011-12-13 14:52:07 +02003473 ath6kl_cfg80211_sscan_disable(vif);
3474
Kalle Valoec4b7f62011-11-01 08:44:04 +02003475 switch (vif->sme_state) {
Kalle Valoc97a31b2011-12-13 14:51:10 +02003476 case SME_DISCONNECTED:
3477 break;
Kalle Valoec4b7f62011-11-01 08:44:04 +02003478 case SME_CONNECTING:
3479 cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
3480 NULL, 0,
3481 WLAN_STATUS_UNSPECIFIED_FAILURE,
3482 GFP_KERNEL);
3483 break;
3484 case SME_CONNECTED:
Johannes Berg80279fb2015-05-22 16:22:20 +02003485 cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003486 break;
3487 }
3488
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +05303489 if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
3490 (test_bit(CONNECTED, &vif->flags) ||
3491 test_bit(CONNECT_PEND, &vif->flags)))
Kalle Valo7125f012011-12-13 14:51:37 +02003492 ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003493
3494 vif->sme_state = SME_DISCONNECTED;
Kalle Valo1f40525512011-11-01 08:44:13 +02003495 clear_bit(CONNECTED, &vif->flags);
3496 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valoec4b7f62011-11-01 08:44:04 +02003497
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05303498 /* Stop netdev queues, needed during recovery */
3499 netif_stop_queue(vif->ndev);
3500 netif_carrier_off(vif->ndev);
3501
Kalle Valoec4b7f62011-11-01 08:44:04 +02003502 /* disable scanning */
Vasanthakumar Thiagarajan58109df2012-09-11 12:07:00 +05303503 if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
3504 ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
Kalle Valo7125f012011-12-13 14:51:37 +02003505 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
3506 ath6kl_warn("failed to disable scan during stop\n");
Kalle Valoec4b7f62011-11-01 08:44:04 +02003507
3508 ath6kl_cfg80211_scan_complete_event(vif, true);
3509}
3510
Kalle Valo7125f012011-12-13 14:51:37 +02003511void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
3512{
3513 struct ath6kl_vif *vif;
3514
3515 vif = ath6kl_vif_first(ar);
Vasanthakumar Thiagarajan84caf802012-08-29 19:40:26 +05303516 if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
Kalle Valo7125f012011-12-13 14:51:37 +02003517 /* save the current power mode before enabling power save */
3518 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
3519
3520 if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
Kalle Valocdeb8602012-04-12 11:02:18 +03003521 ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n");
Kalle Valo7125f012011-12-13 14:51:37 +02003522 return;
3523 }
3524
3525 /*
3526 * FIXME: we should take ar->list_lock to protect changes in the
3527 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
3528 * sleeps.
3529 */
3530 list_for_each_entry(vif, &ar->vif_list, list)
3531 ath6kl_cfg80211_stop(vif);
3532}
3533
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003534static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
3535 struct regulatory_request *request)
Kalle Valo84841ba2012-07-19 16:00:56 +03003536{
3537 struct ath6kl *ar = wiphy_priv(wiphy);
Johannes Berg57fbcce2016-04-12 15:56:15 +02003538 u32 rates[NUM_NL80211_BANDS];
Kalle Valo84841ba2012-07-19 16:00:56 +03003539 int ret, i;
3540
3541 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
Kalle Valoff7e6862012-11-15 16:34:56 +02003542 "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
Kalle Valo84841ba2012-07-19 16:00:56 +03003543 request->alpha2[0], request->alpha2[1],
3544 request->intersect ? " intersect" : "",
3545 request->processed ? " processed" : "",
Kalle Valoff7e6862012-11-15 16:34:56 +02003546 request->initiator, request->user_reg_hint_type);
3547
Kalle Valoff7e6862012-11-15 16:34:56 +02003548 if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003549 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003550
3551 ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
3552 if (ret) {
3553 ath6kl_err("failed to set regdomain: %d\n", ret);
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003554 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003555 }
3556
3557 /*
3558 * Firmware will apply the regdomain change only after a scan is
3559 * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been
3560 * changed.
3561 */
3562
Johannes Berg57fbcce2016-04-12 15:56:15 +02003563 for (i = 0; i < NUM_NL80211_BANDS; i++)
Kalle Valo84841ba2012-07-19 16:00:56 +03003564 if (wiphy->bands[i])
3565 rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
3566
3567
3568 ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false,
3569 false, 0, ATH6KL_FG_SCAN_INTERVAL,
3570 0, NULL, false, rates);
3571 if (ret) {
3572 ath6kl_err("failed to start scan for a regdomain change: %d\n",
3573 ret);
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +00003574 return;
Kalle Valo84841ba2012-07-19 16:00:56 +03003575 }
Kalle Valo84841ba2012-07-19 16:00:56 +03003576}
3577
Kalle Valoc25889e2012-01-17 20:08:27 +02003578static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03003579{
Vasanthakumar Thiagarajan7baef812012-01-21 15:22:50 +05303580 vif->aggr_cntxt = aggr_init(vif);
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303581 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303582 ath6kl_err("failed to initialize aggr\n");
3583 return -ENOMEM;
3584 }
Kalle Valobdcd8172011-07-18 00:22:30 +03003585
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303586 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303587 (unsigned long) vif->ndev);
Kalle Valo10509f92011-12-13 14:52:07 +02003588 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
3589 (unsigned long) vif);
3590
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05303591 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05303592 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303593
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303594 INIT_LIST_HEAD(&vif->mc_filter);
3595
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303596 return 0;
3597}
3598
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05303599void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
3600{
3601 static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3602 bool discon_issued;
3603
3604 netif_stop_queue(vif->ndev);
3605
3606 clear_bit(WLAN_ENABLED, &vif->flags);
3607
3608 if (wmi_ready) {
3609 discon_issued = test_bit(CONNECTED, &vif->flags) ||
3610 test_bit(CONNECT_PEND, &vif->flags);
3611 ath6kl_disconnect(vif);
3612 del_timer(&vif->disconnect_timer);
3613
3614 if (discon_issued)
3615 ath6kl_disconnect_event(vif, DISCONNECT_CMD,
3616 (vif->nw_type & AP_NETWORK) ?
3617 bcast_mac : vif->bssid,
3618 0, NULL, 0);
3619 }
3620
3621 if (vif->scan_req) {
Avraham Stern1d762502016-07-05 17:10:13 +03003622 struct cfg80211_scan_info info = {
3623 .aborted = true,
3624 };
3625
3626 cfg80211_scan_done(vif->scan_req, &info);
Mohammed Shafi Shajakhan355b3a92012-11-16 18:23:36 +05303627 vif->scan_req = NULL;
3628 }
3629
3630 /* need to clean up enhanced bmiss detection fw state */
3631 ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
3632}
3633
Kalle Valoc25889e2012-01-17 20:08:27 +02003634void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303635{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303636 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303637 struct ath6kl_mc_filter *mc_filter, *tmp;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303638
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05303639 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303640
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303641 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
3642
3643 if (vif->nw_type == ADHOC_NETWORK)
3644 ar->ibss_if_active = false;
3645
Vasanthakumar Thiagarajan80abaf92012-01-03 14:42:01 +05303646 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
3647 list_del(&mc_filter->list);
3648 kfree(mc_filter);
3649 }
3650
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303651 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303652
3653 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303654}
3655
Ben Greear13eff532015-10-22 09:07:39 -07003656static const char ath6kl_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
3657 /* Common stats names used by many drivers. */
3658 "tx_pkts_nic", "tx_bytes_nic", "rx_pkts_nic", "rx_bytes_nic",
3659
3660 /* TX stats. */
3661 "d_tx_ucast_pkts", "d_tx_bcast_pkts",
3662 "d_tx_ucast_bytes", "d_tx_bcast_bytes",
3663 "d_tx_rts_ok", "d_tx_error", "d_tx_fail",
3664 "d_tx_retry", "d_tx_multi_retry", "d_tx_rts_fail",
3665 "d_tx_tkip_counter_measures",
3666
3667 /* RX Stats. */
3668 "d_rx_ucast_pkts", "d_rx_ucast_rate", "d_rx_bcast_pkts",
3669 "d_rx_ucast_bytes", "d_rx_bcast_bytes", "d_rx_frag_pkt",
3670 "d_rx_error", "d_rx_crc_err", "d_rx_keycache_miss",
3671 "d_rx_decrypt_crc_err", "d_rx_duplicate_frames",
3672 "d_rx_mic_err", "d_rx_tkip_format_err", "d_rx_ccmp_format_err",
3673 "d_rx_ccmp_replay_err",
3674
3675 /* Misc stats. */
3676 "d_beacon_miss", "d_num_connects", "d_num_disconnects",
3677 "d_beacon_avg_rssi", "d_arp_received", "d_arp_matched",
3678 "d_arp_replied"
3679};
3680
3681#define ATH6KL_STATS_LEN ARRAY_SIZE(ath6kl_gstrings_sta_stats)
3682
3683static int ath6kl_get_sset_count(struct net_device *dev, int sset)
3684{
3685 int rv = 0;
3686
3687 if (sset == ETH_SS_STATS)
3688 rv += ATH6KL_STATS_LEN;
3689
3690 if (rv == 0)
3691 return -EOPNOTSUPP;
3692 return rv;
3693}
3694
3695static void ath6kl_get_stats(struct net_device *dev,
3696 struct ethtool_stats *stats,
3697 u64 *data)
3698{
3699 struct ath6kl_vif *vif = netdev_priv(dev);
3700 struct ath6kl *ar = vif->ar;
3701 int i = 0;
3702 struct target_stats *tgt_stats;
3703
3704 memset(data, 0, sizeof(u64) * ATH6KL_STATS_LEN);
3705
3706 ath6kl_read_tgt_stats(ar, vif);
3707
3708 tgt_stats = &vif->target_stats;
3709
3710 data[i++] = tgt_stats->tx_ucast_pkt + tgt_stats->tx_bcast_pkt;
3711 data[i++] = tgt_stats->tx_ucast_byte + tgt_stats->tx_bcast_byte;
3712 data[i++] = tgt_stats->rx_ucast_pkt + tgt_stats->rx_bcast_pkt;
3713 data[i++] = tgt_stats->rx_ucast_byte + tgt_stats->rx_bcast_byte;
3714
3715 data[i++] = tgt_stats->tx_ucast_pkt;
3716 data[i++] = tgt_stats->tx_bcast_pkt;
3717 data[i++] = tgt_stats->tx_ucast_byte;
3718 data[i++] = tgt_stats->tx_bcast_byte;
3719 data[i++] = tgt_stats->tx_rts_success_cnt;
3720 data[i++] = tgt_stats->tx_err;
3721 data[i++] = tgt_stats->tx_fail_cnt;
3722 data[i++] = tgt_stats->tx_retry_cnt;
3723 data[i++] = tgt_stats->tx_mult_retry_cnt;
3724 data[i++] = tgt_stats->tx_rts_fail_cnt;
3725 data[i++] = tgt_stats->tkip_cnter_measures_invoked;
3726
3727 data[i++] = tgt_stats->rx_ucast_pkt;
3728 data[i++] = tgt_stats->rx_ucast_rate;
3729 data[i++] = tgt_stats->rx_bcast_pkt;
3730 data[i++] = tgt_stats->rx_ucast_byte;
3731 data[i++] = tgt_stats->rx_bcast_byte;
3732 data[i++] = tgt_stats->rx_frgment_pkt;
3733 data[i++] = tgt_stats->rx_err;
3734 data[i++] = tgt_stats->rx_crc_err;
3735 data[i++] = tgt_stats->rx_key_cache_miss;
3736 data[i++] = tgt_stats->rx_decrypt_err;
3737 data[i++] = tgt_stats->rx_dupl_frame;
3738 data[i++] = tgt_stats->tkip_local_mic_fail;
3739 data[i++] = tgt_stats->tkip_fmt_err;
3740 data[i++] = tgt_stats->ccmp_fmt_err;
3741 data[i++] = tgt_stats->ccmp_replays;
3742
3743 data[i++] = tgt_stats->cs_bmiss_cnt;
3744 data[i++] = tgt_stats->cs_connect_cnt;
3745 data[i++] = tgt_stats->cs_discon_cnt;
3746 data[i++] = tgt_stats->cs_ave_beacon_rssi;
3747 data[i++] = tgt_stats->arp_received;
3748 data[i++] = tgt_stats->arp_matched;
3749 data[i++] = tgt_stats->arp_replied;
3750
3751 if (i != ATH6KL_STATS_LEN) {
3752 WARN_ON_ONCE(1);
3753 ath6kl_err("ethtool stats error, i: %d STATS_LEN: %d\n",
3754 i, (int)ATH6KL_STATS_LEN);
3755 }
3756}
3757
3758/* These stats are per NIC, not really per vdev, so we just ignore dev. */
3759static void ath6kl_get_strings(struct net_device *dev, u32 sset, u8 *data)
3760{
3761 int sz_sta_stats = 0;
3762
3763 if (sset == ETH_SS_STATS) {
3764 sz_sta_stats = sizeof(ath6kl_gstrings_sta_stats);
3765 memcpy(data, ath6kl_gstrings_sta_stats, sz_sta_stats);
3766 }
3767}
3768
3769static const struct ethtool_ops ath6kl_ethtool_ops = {
3770 .get_drvinfo = cfg80211_get_drvinfo,
3771 .get_link = ethtool_op_get_link,
3772 .get_strings = ath6kl_get_strings,
3773 .get_ethtool_stats = ath6kl_get_stats,
3774 .get_sset_count = ath6kl_get_sset_count,
3775};
3776
Johannes Berg552bff02012-09-19 09:26:06 +02003777struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +01003778 unsigned char name_assign_type,
Johannes Berg84efbb82012-06-16 00:00:26 +02003779 enum nl80211_iftype type,
3780 u8 fw_vif_idx, u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303781{
3782 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303783 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303784
Tom Gundersen6bab2e192015-03-18 11:13:39 +01003785 ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303786 if (!ndev)
3787 return NULL;
3788
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303789 vif = netdev_priv(ndev);
3790 ndev->ieee80211_ptr = &vif->wdev;
3791 vif->wdev.wiphy = ar->wiphy;
3792 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05303793 vif->ndev = ndev;
3794 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
3795 vif->wdev.netdev = ndev;
3796 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05303797 vif->fw_vif_idx = fw_vif_idx;
Kalle Valod0d670a2012-03-07 20:03:58 +02003798 vif->nw_type = nw_type;
3799 vif->next_mode = nw_type;
Raja Mani8f46fcc2012-02-20 19:08:07 +05303800 vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
Raja Manice0dc0c2012-02-20 19:08:08 +05303801 vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
Raja Manieb389872012-04-16 16:09:56 +05303802 vif->bg_scan_period = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02003803 vif->htcap[NL80211_BAND_2GHZ].ht_enable = true;
3804 vif->htcap[NL80211_BAND_5GHZ].ht_enable = true;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303805
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303806 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
Aarthi Thiruvengadamc95dcb52012-07-10 13:20:40 -07003807 if (fw_vif_idx != 0) {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303808 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
3809 0x2;
Aarthi Thiruvengadamc95dcb52012-07-10 13:20:40 -07003810 if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
3811 ar->fw_capabilities))
3812 ndev->dev_addr[4] ^= 0x80;
3813 }
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303814
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303815 init_netdev(ndev);
3816
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05303817 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303818
Kalle Valoc25889e2012-01-17 20:08:27 +02003819 if (ath6kl_cfg80211_vif_init(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303820 goto err;
3821
Ben Greear13eff532015-10-22 09:07:39 -07003822 netdev_set_default_ethtool_ops(ndev, &ath6kl_ethtool_ops);
3823
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303824 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303825 goto err;
3826
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303827 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05303828 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05303829 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303830 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303831
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05303832 if (type == NL80211_IFTYPE_ADHOC)
3833 ar->ibss_if_active = true;
3834
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303835 spin_lock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303836 list_add_tail(&vif->list, &ar->vif_list);
Vasanthakumar Thiagarajan11f6e402011-11-01 16:38:50 +05303837 spin_unlock_bh(&ar->list_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05303838
Johannes Berg84efbb82012-06-16 00:00:26 +02003839 return &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303840
3841err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05303842 aggr_module_destroy(vif->aggr_cntxt);
3843 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303844 return NULL;
3845}
3846
Johannes Berg964dc9e2013-06-03 17:25:34 +02003847#ifdef CONFIG_PM
3848static const struct wiphy_wowlan_support ath6kl_wowlan_support = {
3849 .flags = WIPHY_WOWLAN_MAGIC_PKT |
3850 WIPHY_WOWLAN_DISCONNECT |
3851 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
3852 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
3853 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
3854 WIPHY_WOWLAN_4WAY_HANDSHAKE,
3855 .n_patterns = WOW_MAX_FILTERS_PER_LIST,
3856 .pattern_min_len = 1,
3857 .pattern_max_len = WOW_PATTERN_SIZE,
3858};
3859#endif
3860
Kalle Valo46d33a22012-01-17 20:08:40 +02003861int ath6kl_cfg80211_init(struct ath6kl *ar)
3862{
3863 struct wiphy *wiphy = ar->wiphy;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003864 bool band_2gig = false, band_5gig = false, ht = false;
Kalle Valo46d33a22012-01-17 20:08:40 +02003865 int ret;
3866
3867 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
3868
3869 wiphy->max_remain_on_channel_duration = 5000;
3870
3871 /* set device pointer for wiphy */
3872 set_wiphy_dev(wiphy, ar->dev);
3873
3874 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3875 BIT(NL80211_IFTYPE_ADHOC) |
3876 BIT(NL80211_IFTYPE_AP);
3877 if (ar->p2p) {
3878 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
3879 BIT(NL80211_IFTYPE_P2P_CLIENT);
3880 }
3881
Masahiro Yamada97f26452016-08-03 13:45:50 -07003882 if (IS_ENABLED(CONFIG_ATH6KL_REGDOMAIN) &&
Kalle Valoff7e6862012-11-15 16:34:56 +02003883 test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
Kalle Valo84841ba2012-07-19 16:00:56 +03003884 wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
Kalle Valoff7e6862012-11-15 16:34:56 +02003885 ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
3886 }
Kalle Valo84841ba2012-07-19 16:00:56 +03003887
Kalle Valo46d33a22012-01-17 20:08:40 +02003888 /* max num of ssids that can be probed during scanning */
Jouni Malinen8ab54152012-05-09 22:14:51 +03003889 wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
Naveen Singhdd45b752012-05-16 13:29:00 +03003890
3891 /* max num of ssids that can be matched after scan */
3892 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
3893 ar->fw_capabilities))
3894 wiphy->max_match_sets = MAX_PROBED_SSIDS;
3895
Kalle Valo46d33a22012-01-17 20:08:40 +02003896 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
Thomas Pedersend92917e2012-04-19 15:31:56 -07003897 switch (ar->hw.cap) {
3898 case WMI_11AN_CAP:
3899 ht = true;
3900 case WMI_11A_CAP:
3901 band_5gig = true;
3902 break;
3903 case WMI_11GN_CAP:
3904 ht = true;
3905 case WMI_11G_CAP:
3906 band_2gig = true;
3907 break;
3908 case WMI_11AGN_CAP:
3909 ht = true;
3910 case WMI_11AG_CAP:
3911 band_2gig = true;
3912 band_5gig = true;
3913 break;
3914 default:
3915 ath6kl_err("invalid phy capability!\n");
3916 return -EINVAL;
3917 }
3918
Vasanthakumar Thiagarajan7fd1ce72012-04-25 12:38:18 +05303919 /*
3920 * Even if the fw has HT support, advertise HT cap only when
3921 * the firmware has support to override RSN capability, otherwise
3922 * 4-way handshake would fail.
3923 */
3924 if (!(ht &&
3925 test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
3926 ar->fw_capabilities))) {
Thomas Pedersend92917e2012-04-19 15:31:56 -07003927 ath6kl_band_2ghz.ht_cap.cap = 0;
3928 ath6kl_band_2ghz.ht_cap.ht_supported = false;
3929 ath6kl_band_5ghz.ht_cap.cap = 0;
3930 ath6kl_band_5ghz.ht_cap.ht_supported = false;
Ben Greear7fd98522015-10-21 14:53:20 -07003931
3932 if (ht)
3933 ath6kl_err("Firmware lacks RSN-CAP-OVERRIDE, so HT (802.11n) is disabled.");
Thomas Pedersend92917e2012-04-19 15:31:56 -07003934 }
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303935
Kalle Valoeba95bc2014-06-17 12:40:52 +03003936 if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
3937 ar->fw_capabilities)) {
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303938 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3939 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3940 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
3941 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
Ben Greear26ca14d2015-11-30 15:01:47 -08003942 ar->hw.tx_ant = 0x3; /* mask, 2 antenna */
3943 ar->hw.rx_ant = 0x3;
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303944 } else {
3945 ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
3946 ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
Ben Greear9c2e90f2015-10-21 14:53:19 -07003947 ar->hw.tx_ant = 1;
3948 ar->hw.rx_ant = 1;
Bala Shanmugam06e360a2012-05-22 13:23:12 +05303949 }
3950
Ben Greear9c2e90f2015-10-21 14:53:19 -07003951 wiphy->available_antennas_tx = ar->hw.tx_ant;
3952 wiphy->available_antennas_rx = ar->hw.rx_ant;
3953
Thomas Pedersend92917e2012-04-19 15:31:56 -07003954 if (band_2gig)
Johannes Berg57fbcce2016-04-12 15:56:15 +02003955 wiphy->bands[NL80211_BAND_2GHZ] = &ath6kl_band_2ghz;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003956 if (band_5gig)
Johannes Berg57fbcce2016-04-12 15:56:15 +02003957 wiphy->bands[NL80211_BAND_5GHZ] = &ath6kl_band_5ghz;
Thomas Pedersend92917e2012-04-19 15:31:56 -07003958
Kalle Valo46d33a22012-01-17 20:08:40 +02003959 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3960
3961 wiphy->cipher_suites = cipher_suites;
3962 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3963
Johannes Bergdfb89c52012-06-27 09:23:48 +02003964#ifdef CONFIG_PM
Johannes Berg964dc9e2013-06-03 17:25:34 +02003965 wiphy->wowlan = &ath6kl_wowlan_support;
Johannes Bergdfb89c52012-06-27 09:23:48 +02003966#endif
Kalle Valo46d33a22012-01-17 20:08:40 +02003967
Jouni Malinen8ab54152012-05-09 22:14:51 +03003968 wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
Kalle Valo46d33a22012-01-17 20:08:40 +02003969
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303970 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
3971 WIPHY_FLAG_HAVE_AP_SME |
3972 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
3973 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
3974
Thomas Pedersenb1f47e32012-08-15 16:51:24 -07003975 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
Arend Van Sprielca986ad2017-04-21 13:05:00 +01003976 ar->wiphy->max_sched_scan_reqs = 1;
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303977
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05303978 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
3979 ar->fw_capabilities))
Johannes Bergb2922192012-10-12 10:55:53 +02003980 ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
Vasanthakumar Thiagarajan03bdeb02012-03-21 20:58:39 +05303981
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303982 ar->wiphy->probe_resp_offload =
3983 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
3984 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
Jouni Malinena432e7c2012-04-16 19:25:35 +03003985 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
Vasanthakumar Thiagarajanf2afdac2012-02-28 20:20:19 +05303986
Kalle Valo46d33a22012-01-17 20:08:40 +02003987 ret = wiphy_register(wiphy);
3988 if (ret < 0) {
3989 ath6kl_err("couldn't register wiphy device\n");
3990 return ret;
3991 }
3992
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05303993 ar->wiphy_registered = true;
3994
Kalle Valo46d33a22012-01-17 20:08:40 +02003995 return 0;
3996}
3997
3998void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05303999{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05304000 wiphy_unregister(ar->wiphy);
Vasanthakumar Thiagarajane5348a12012-02-25 14:43:17 +05304001
4002 ar->wiphy_registered = false;
Kalle Valo45eaa782012-01-17 20:09:05 +02004003}
Kalle Valo46d33a22012-01-17 20:08:40 +02004004
Kalle Valo45eaa782012-01-17 20:09:05 +02004005struct ath6kl *ath6kl_cfg80211_create(void)
4006{
4007 struct ath6kl *ar;
4008 struct wiphy *wiphy;
4009
4010 /* create a new wiphy for use with cfg80211 */
4011 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
4012
4013 if (!wiphy) {
4014 ath6kl_err("couldn't allocate wiphy device\n");
4015 return NULL;
4016 }
4017
4018 ar = wiphy_priv(wiphy);
4019 ar->wiphy = wiphy;
4020
4021 return ar;
4022}
4023
4024/* Note: ar variable must not be accessed after calling this! */
4025void ath6kl_cfg80211_destroy(struct ath6kl *ar)
4026{
Vasanthakumar Thiagarajan1d2a4452012-01-21 15:22:53 +05304027 int i;
4028
4029 for (i = 0; i < AP_MAX_NUM_STA; i++)
4030 kfree(ar->sta_list[i].aggr_conn);
4031
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05304032 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03004033}
Kalle Valo45eaa782012-01-17 20:09:05 +02004034