]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
brcmfmac: merge platform data and module paramaters
[mirror_ubuntu-hirsute-kernel.git] / drivers / net / wireless / broadcom / brcm80211 / brcmfmac / cfg80211.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
5b435de0 20#include <linux/etherdevice.h>
68ca395f 21#include <linux/module.h>
1bacb048 22#include <linux/vmalloc.h>
5b435de0 23#include <net/cfg80211.h>
cbaa177d 24#include <net/netlink.h>
5b435de0
AS
25
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
122d3d04 29#include "core.h"
a8e8ed34 30#include "debug.h"
40c1c249 31#include "tracepoint.h"
7a5c1f64 32#include "fwil_types.h"
9f440b7b 33#include "p2p.h"
61730d4d 34#include "btcoex.h"
bfe81975 35#include "cfg80211.h"
c08437b4 36#include "feature.h"
81f5dcb8 37#include "fwil.h"
8851cce0 38#include "proto.h"
1bacb048 39#include "vendor.h"
d14f78b9 40#include "bus.h"
6b89dcb3 41#include "common.h"
5b435de0 42
e5806072
AS
43#define BRCMF_SCAN_IE_LEN_MAX 2048
44#define BRCMF_PNO_VERSION 2
45#define BRCMF_PNO_TIME 30
46#define BRCMF_PNO_REPEAT 4
47#define BRCMF_PNO_FREQ_EXPO_MAX 3
48#define BRCMF_PNO_MAX_PFN_COUNT 16
49#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
50#define BRCMF_PNO_HIDDEN_BIT 2
51#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
52#define BRCMF_PNO_SCAN_COMPLETE 1
53#define BRCMF_PNO_SCAN_INCOMPLETE 0
54
1a873342
HM
55#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
56#define WPA_OUI_TYPE 1
57#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
58#define WME_OUI_TYPE 2
89286dc9 59#define WPS_OUI_TYPE 4
1a873342
HM
60
61#define VS_IE_FIXED_HDR_LEN 6
62#define WPA_IE_VERSION_LEN 2
63#define WPA_IE_MIN_OUI_LEN 4
64#define WPA_IE_SUITE_COUNT_LEN 2
65
66#define WPA_CIPHER_NONE 0 /* None */
67#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
68#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
69#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
70#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
71
72#define RSN_AKM_NONE 0 /* None (IBSS) */
73#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
74#define RSN_AKM_PSK 2 /* Pre-shared Key */
75#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
76#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
77
78#define VNDR_IE_CMD_LEN 4 /* length of the set command
79 * string :"add", "del" (+ NUL)
80 */
81#define VNDR_IE_COUNT_OFFSET 4
82#define VNDR_IE_PKTFLAG_OFFSET 8
83#define VNDR_IE_VSIE_OFFSET 12
84#define VNDR_IE_HDR_SIZE 12
9f440b7b 85#define VNDR_IE_PARSE_LIMIT 5
1a873342
HM
86
87#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
88#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
04012895 89
89286dc9
HM
90#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
91#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
92#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
93
1678ba8e
HM
94#define BRCMF_SCAN_CHANNEL_TIME 40
95#define BRCMF_SCAN_UNASSOC_TIME 40
96#define BRCMF_SCAN_PASSIVE_TIME 120
97
3021ad9a
HM
98#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
99
5b435de0
AS
100#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
101 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
102
ce81e317 103static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
5b435de0 104{
c1179033 105 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
647c9ae0
AS
106 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
107 vif->sme_state);
5b435de0
AS
108 return false;
109 }
110 return true;
111}
112
5b435de0
AS
113#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
114#define RATETAB_ENT(_rateid, _flags) \
115 { \
116 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
117 .hw_value = (_rateid), \
118 .flags = (_flags), \
119 }
120
121static struct ieee80211_rate __wl_rates[] = {
122 RATETAB_ENT(BRCM_RATE_1M, 0),
123 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
124 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
125 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
126 RATETAB_ENT(BRCM_RATE_6M, 0),
127 RATETAB_ENT(BRCM_RATE_9M, 0),
128 RATETAB_ENT(BRCM_RATE_12M, 0),
129 RATETAB_ENT(BRCM_RATE_18M, 0),
130 RATETAB_ENT(BRCM_RATE_24M, 0),
131 RATETAB_ENT(BRCM_RATE_36M, 0),
132 RATETAB_ENT(BRCM_RATE_48M, 0),
133 RATETAB_ENT(BRCM_RATE_54M, 0),
134};
135
5b435de0 136#define wl_g_rates (__wl_rates + 0)
58de92d2
AS
137#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
138#define wl_a_rates (__wl_rates + 4)
139#define wl_a_rates_size (wl_g_rates_size - 4)
140
141#define CHAN2G(_channel, _freq) { \
142 .band = IEEE80211_BAND_2GHZ, \
143 .center_freq = (_freq), \
144 .hw_value = (_channel), \
145 .flags = IEEE80211_CHAN_DISABLED, \
146 .max_antenna_gain = 0, \
147 .max_power = 30, \
148}
149
150#define CHAN5G(_channel) { \
151 .band = IEEE80211_BAND_5GHZ, \
152 .center_freq = 5000 + (5 * (_channel)), \
153 .hw_value = (_channel), \
154 .flags = IEEE80211_CHAN_DISABLED, \
155 .max_antenna_gain = 0, \
156 .max_power = 30, \
157}
158
159static struct ieee80211_channel __wl_2ghz_channels[] = {
160 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
161 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
162 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
163 CHAN2G(13, 2472), CHAN2G(14, 2484)
164};
165
166static struct ieee80211_channel __wl_5ghz_channels[] = {
167 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
168 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
169 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
170 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
171 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
172 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
173};
5b435de0 174
b48d8916 175/* Band templates duplicated per wiphy. The channel info
58de92d2 176 * above is added to the band during setup.
b48d8916
AS
177 */
178static const struct ieee80211_supported_band __wl_band_2ghz = {
5b435de0 179 .band = IEEE80211_BAND_2GHZ,
5b435de0
AS
180 .bitrates = wl_g_rates,
181 .n_bitrates = wl_g_rates_size,
182};
183
58de92d2 184static const struct ieee80211_supported_band __wl_band_5ghz = {
5b435de0 185 .band = IEEE80211_BAND_5GHZ,
5b435de0
AS
186 .bitrates = wl_a_rates,
187 .n_bitrates = wl_a_rates_size,
188};
189
d48200ba
HM
190/* This is to override regulatory domains defined in cfg80211 module (reg.c)
191 * By default world regulatory domain defined in reg.c puts the flags
8fe02e16
LR
192 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
193 * With respect to these flags, wpa_supplicant doesn't * start p2p
194 * operations on 5GHz channels. All the changes in world regulatory
d48200ba
HM
195 * domain are to be done here.
196 */
197static const struct ieee80211_regdomain brcmf_regdom = {
198 .n_reg_rules = 4,
199 .alpha2 = "99",
200 .reg_rules = {
201 /* IEEE 802.11b/g, channels 1..11 */
202 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
203 /* If any */
204 /* IEEE 802.11 channel 14 - Only JP enables
205 * this and for 802.11b only
206 */
207 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
208 /* IEEE 802.11a, channel 36..64 */
c555ecde 209 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
d48200ba 210 /* IEEE 802.11a, channel 100..165 */
c555ecde 211 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
5b435de0
AS
212};
213
214static const u32 __wl_cipher_suites[] = {
215 WLAN_CIPHER_SUITE_WEP40,
216 WLAN_CIPHER_SUITE_WEP104,
217 WLAN_CIPHER_SUITE_TKIP,
218 WLAN_CIPHER_SUITE_CCMP,
219 WLAN_CIPHER_SUITE_AES_CMAC,
220};
221
1a873342
HM
222/* Vendor specific ie. id = 221, oui and type defines exact ie */
223struct brcmf_vs_tlv {
224 u8 id;
225 u8 len;
226 u8 oui[3];
227 u8 oui_type;
228};
229
230struct parsed_vndr_ie_info {
231 u8 *ie_ptr;
232 u32 ie_len; /* total length including id & length field */
233 struct brcmf_vs_tlv vndrie;
234};
235
236struct parsed_vndr_ies {
237 u32 count;
9f440b7b 238 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
1a873342
HM
239};
240
5a394eba
AS
241static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
242 struct cfg80211_chan_def *ch)
600a897d
AS
243{
244 struct brcmu_chan ch_inf;
245 s32 primary_offset;
246
247 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
248 ch->chan->center_freq, ch->center_freq1, ch->width);
249 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
36e8072e 250 primary_offset = ch->chan->center_freq - ch->center_freq1;
600a897d
AS
251 switch (ch->width) {
252 case NL80211_CHAN_WIDTH_20:
0cd75b19 253 case NL80211_CHAN_WIDTH_20_NOHT:
600a897d
AS
254 ch_inf.bw = BRCMU_CHAN_BW_20;
255 WARN_ON(primary_offset != 0);
256 break;
257 case NL80211_CHAN_WIDTH_40:
258 ch_inf.bw = BRCMU_CHAN_BW_40;
36e8072e 259 if (primary_offset > 0)
600a897d
AS
260 ch_inf.sb = BRCMU_CHAN_SB_U;
261 else
262 ch_inf.sb = BRCMU_CHAN_SB_L;
263 break;
264 case NL80211_CHAN_WIDTH_80:
265 ch_inf.bw = BRCMU_CHAN_BW_80;
36e8072e
RM
266 if (primary_offset == -30)
267 ch_inf.sb = BRCMU_CHAN_SB_LL;
268 else if (primary_offset == -10)
269 ch_inf.sb = BRCMU_CHAN_SB_LU;
270 else if (primary_offset == 10)
271 ch_inf.sb = BRCMU_CHAN_SB_UL;
272 else
273 ch_inf.sb = BRCMU_CHAN_SB_UU;
600a897d 274 break;
0cd75b19
AS
275 case NL80211_CHAN_WIDTH_80P80:
276 case NL80211_CHAN_WIDTH_160:
277 case NL80211_CHAN_WIDTH_5:
278 case NL80211_CHAN_WIDTH_10:
600a897d
AS
279 default:
280 WARN_ON_ONCE(1);
281 }
282 switch (ch->chan->band) {
283 case IEEE80211_BAND_2GHZ:
284 ch_inf.band = BRCMU_CHAN_BAND_2G;
285 break;
286 case IEEE80211_BAND_5GHZ:
287 ch_inf.band = BRCMU_CHAN_BAND_5G;
288 break;
0cd75b19 289 case IEEE80211_BAND_60GHZ:
600a897d
AS
290 default:
291 WARN_ON_ONCE(1);
292 }
293 d11inf->encchspec(&ch_inf);
294
295 return ch_inf.chspec;
296}
297
83cf17aa
FL
298u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
299 struct ieee80211_channel *ch)
6e186166 300{
83cf17aa 301 struct brcmu_chan ch_inf;
6e186166 302
83cf17aa
FL
303 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
304 ch_inf.bw = BRCMU_CHAN_BW_20;
305 d11inf->encchspec(&ch_inf);
6e186166 306
83cf17aa 307 return ch_inf.chspec;
6e186166
AS
308}
309
89286dc9
HM
310/* Traverse a string of 1-byte tag/1-byte length/variable-length value
311 * triples, returning a pointer to the substring whose first element
312 * matches tag
313 */
4b5800fe
JB
314const struct brcmf_tlv *
315brcmf_parse_tlvs(const void *buf, int buflen, uint key)
89286dc9 316{
4b5800fe
JB
317 const struct brcmf_tlv *elt = buf;
318 int totlen = buflen;
89286dc9
HM
319
320 /* find tagged parameter */
321 while (totlen >= TLV_HDR_LEN) {
322 int len = elt->len;
323
324 /* validate remaining totlen */
325 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
326 return elt;
327
328 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
329 totlen -= (len + TLV_HDR_LEN);
330 }
331
332 return NULL;
333}
334
335/* Is any of the tlvs the expected entry? If
336 * not update the tlvs buffer pointer/length.
337 */
338static bool
4b5800fe
JB
339brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
340 const u8 *oui, u32 oui_len, u8 type)
89286dc9
HM
341{
342 /* If the contents match the OUI and the type */
343 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
344 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
345 type == ie[TLV_BODY_OFF + oui_len]) {
346 return true;
347 }
348
349 if (tlvs == NULL)
350 return false;
351 /* point to the next ie */
352 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
353 /* calculate the length of the rest of the buffer */
354 *tlvs_len -= (int)(ie - *tlvs);
355 /* update the pointer to the start of the buffer */
356 *tlvs = ie;
357
358 return false;
359}
360
361static struct brcmf_vs_tlv *
4b5800fe 362brcmf_find_wpaie(const u8 *parse, u32 len)
89286dc9 363{
4b5800fe 364 const struct brcmf_tlv *ie;
89286dc9
HM
365
366 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
4b5800fe 367 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
89286dc9
HM
368 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
369 return (struct brcmf_vs_tlv *)ie;
370 }
371 return NULL;
372}
373
374static struct brcmf_vs_tlv *
4b5800fe 375brcmf_find_wpsie(const u8 *parse, u32 len)
89286dc9 376{
4b5800fe 377 const struct brcmf_tlv *ie;
89286dc9
HM
378
379 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
380 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
381 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
382 return (struct brcmf_vs_tlv *)ie;
383 }
384 return NULL;
385}
386
39504a2d
AS
387static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
388 struct brcmf_cfg80211_vif *vif,
389 enum nl80211_iftype new_type)
390{
391 int iftype_num[NUM_NL80211_IFTYPES];
392 struct brcmf_cfg80211_vif *pos;
353c46ac
AS
393 bool check_combos = false;
394 int ret = 0;
39504a2d
AS
395
396 memset(&iftype_num[0], 0, sizeof(iftype_num));
397 list_for_each_entry(pos, &cfg->vif_list, list)
353c46ac 398 if (pos == vif) {
39504a2d 399 iftype_num[new_type]++;
353c46ac
AS
400 } else {
401 /* concurrent interfaces so need check combinations */
402 check_combos = true;
39504a2d 403 iftype_num[pos->wdev.iftype]++;
353c46ac
AS
404 }
405
406 if (check_combos)
407 ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
39504a2d 408
353c46ac 409 return ret;
39504a2d
AS
410}
411
412static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
413 enum nl80211_iftype new_type)
414{
415 int iftype_num[NUM_NL80211_IFTYPES];
416 struct brcmf_cfg80211_vif *pos;
417
418 memset(&iftype_num[0], 0, sizeof(iftype_num));
419 list_for_each_entry(pos, &cfg->vif_list, list)
420 iftype_num[pos->wdev.iftype]++;
421
422 iftype_num[new_type]++;
423 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
424}
89286dc9 425
5b435de0
AS
426static void convert_key_from_CPU(struct brcmf_wsec_key *key,
427 struct brcmf_wsec_key_le *key_le)
428{
429 key_le->index = cpu_to_le32(key->index);
430 key_le->len = cpu_to_le32(key->len);
431 key_le->algo = cpu_to_le32(key->algo);
432 key_le->flags = cpu_to_le32(key->flags);
433 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
434 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
435 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
436 memcpy(key_le->data, key->data, sizeof(key->data));
437 memcpy(key_le->ea, key->ea, sizeof(key->ea));
438}
439
f09d0c02 440static int
118eb304 441send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
5b435de0
AS
442{
443 int err;
444 struct brcmf_wsec_key_le key_le;
445
446 convert_key_from_CPU(key, &key_le);
f09d0c02 447
118eb304 448 brcmf_netdev_wait_pend8021x(ifp);
81f5dcb8 449
118eb304 450 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
81f5dcb8 451 sizeof(key_le));
f09d0c02 452
5b435de0 453 if (err)
57d6e91a 454 brcmf_err("wsec_key error (%d)\n", err);
5b435de0
AS
455 return err;
456}
457
b3657453 458static s32
52f22fb2 459brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
b3657453
HM
460{
461 s32 err;
462 u32 mode;
463
464 if (enable)
465 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
466 else
467 mode = 0;
468
469 /* Try to set and enable ARP offload feature, this may fail, then it */
470 /* is simply not supported and err 0 will be returned */
471 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
472 if (err) {
473 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
474 mode, err);
475 err = 0;
476 } else {
477 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
478 if (err) {
479 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
480 enable, err);
481 err = 0;
482 } else
483 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
484 enable, mode);
485 }
486
52f22fb2
FL
487 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
488 if (err) {
489 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
490 enable, err);
491 err = 0;
492 } else
493 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
494 enable, mode);
495
b3657453
HM
496 return err;
497}
498
8851cce0
HM
499static void
500brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
501{
8f2b4597
AS
502 struct brcmf_cfg80211_vif *vif;
503 struct brcmf_if *ifp;
504
505 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
506 ifp = vif->ifp;
8851cce0
HM
507
508 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
509 (wdev->iftype == NL80211_IFTYPE_AP) ||
510 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
511 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
512 ADDR_DIRECT);
513 else
514 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
515 ADDR_INDIRECT);
516}
517
a44aa400
HM
518static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
519{
520 struct brcmf_mbss_ssid_le mbss_ssid_le;
521 int bsscfgidx;
522 int err;
523
524 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
525 bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr);
526 if (bsscfgidx < 0)
527 return bsscfgidx;
528
529 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
530 mbss_ssid_le.SSID_len = cpu_to_le32(5);
531 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
532
533 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
534 sizeof(mbss_ssid_le));
535 if (err < 0)
536 brcmf_err("setting ssid failed %d\n", err);
537
538 return err;
539}
540
541/**
542 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
543 *
544 * @wiphy: wiphy device of new interface.
545 * @name: name of the new interface.
546 * @flags: not used.
547 * @params: contains mac address for AP device.
548 */
549static
550struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
551 u32 *flags, struct vif_params *params)
552{
553 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
554 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
555 struct brcmf_cfg80211_vif *vif;
556 int err;
557
558 if (brcmf_cfg80211_vif_event_armed(cfg))
559 return ERR_PTR(-EBUSY);
560
561 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
562
563 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false);
564 if (IS_ERR(vif))
565 return (struct wireless_dev *)vif;
566
567 brcmf_cfg80211_arm_vif_event(cfg, vif);
568
569 err = brcmf_cfg80211_request_ap_if(ifp);
570 if (err) {
571 brcmf_cfg80211_arm_vif_event(cfg, NULL);
572 goto fail;
573 }
574
575 /* wait for firmware event */
a9eb0c4b
AS
576 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
577 BRCMF_VIF_EVENT_TIMEOUT);
a44aa400
HM
578 brcmf_cfg80211_arm_vif_event(cfg, NULL);
579 if (!err) {
580 brcmf_err("timeout occurred\n");
581 err = -EIO;
582 goto fail;
583 }
584
585 /* interface created in firmware */
586 ifp = vif->ifp;
587 if (!ifp) {
588 brcmf_err("no if pointer provided\n");
589 err = -ENOENT;
590 goto fail;
591 }
592
593 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
594 err = brcmf_net_attach(ifp, true);
595 if (err) {
596 brcmf_err("Registering netdevice failed\n");
597 goto fail;
598 }
599
600 return &ifp->vif->wdev;
601
602fail:
603 brcmf_free_vif(vif);
604 return ERR_PTR(err);
605}
606
967fe2c8
AS
607static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
608{
609 enum nl80211_iftype iftype;
610
611 iftype = vif->wdev.iftype;
612 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
613}
614
615static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
616{
617 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
618}
619
9f440b7b
AS
620static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
621 const char *name,
6bab2e19 622 unsigned char name_assign_type,
9f440b7b
AS
623 enum nl80211_iftype type,
624 u32 *flags,
625 struct vif_params *params)
626{
8851cce0 627 struct wireless_dev *wdev;
39504a2d 628 int err;
8851cce0 629
9f440b7b 630 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
39504a2d
AS
631 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
632 if (err) {
633 brcmf_err("iface validation failed: err=%d\n", err);
634 return ERR_PTR(err);
635 }
9f440b7b
AS
636 switch (type) {
637 case NL80211_IFTYPE_ADHOC:
638 case NL80211_IFTYPE_STATION:
9f440b7b
AS
639 case NL80211_IFTYPE_AP_VLAN:
640 case NL80211_IFTYPE_WDS:
641 case NL80211_IFTYPE_MONITOR:
642 case NL80211_IFTYPE_MESH_POINT:
643 return ERR_PTR(-EOPNOTSUPP);
a44aa400
HM
644 case NL80211_IFTYPE_AP:
645 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
646 if (!IS_ERR(wdev))
647 brcmf_cfg80211_update_proto_addr_mode(wdev);
648 return wdev;
9f440b7b
AS
649 case NL80211_IFTYPE_P2P_CLIENT:
650 case NL80211_IFTYPE_P2P_GO:
27f10e38 651 case NL80211_IFTYPE_P2P_DEVICE:
6bab2e19 652 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
8851cce0
HM
653 if (!IS_ERR(wdev))
654 brcmf_cfg80211_update_proto_addr_mode(wdev);
655 return wdev;
9f440b7b 656 case NL80211_IFTYPE_UNSPECIFIED:
9f440b7b
AS
657 default:
658 return ERR_PTR(-EINVAL);
659 }
660}
661
5e787f75
DK
662static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
663{
c08437b4 664 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
5e787f75
DK
665 brcmf_set_mpc(ifp, mpc);
666}
667
f96aa07e 668void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
5f4f9f11 669{
5f4f9f11
AS
670 s32 err = 0;
671
672 if (check_vif_up(ifp->vif)) {
673 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
674 if (err) {
675 brcmf_err("fail to set mpc\n");
676 return;
677 }
678 brcmf_dbg(INFO, "MPC : %d\n", mpc);
679 }
680}
681
a0f472ac
AS
682s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
683 struct brcmf_if *ifp, bool aborted,
684 bool fw_abort)
5f4f9f11
AS
685{
686 struct brcmf_scan_params_le params_le;
687 struct cfg80211_scan_request *scan_request;
688 s32 err = 0;
689
690 brcmf_dbg(SCAN, "Enter\n");
691
692 /* clear scan request, because the FW abort can cause a second call */
693 /* to this functon and might cause a double cfg80211_scan_done */
694 scan_request = cfg->scan_request;
695 cfg->scan_request = NULL;
696
697 if (timer_pending(&cfg->escan_timeout))
698 del_timer_sync(&cfg->escan_timeout);
699
700 if (fw_abort) {
701 /* Do a scan abort to stop the driver's scan engine */
702 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
703 memset(&params_le, 0, sizeof(params_le));
93803b33 704 eth_broadcast_addr(params_le.bssid);
5f4f9f11
AS
705 params_le.bss_type = DOT11_BSSTYPE_ANY;
706 params_le.scan_type = 0;
707 params_le.channel_num = cpu_to_le32(1);
708 params_le.nprobes = cpu_to_le32(1);
709 params_le.active_time = cpu_to_le32(-1);
710 params_le.passive_time = cpu_to_le32(-1);
711 params_le.home_time = cpu_to_le32(-1);
712 /* Scan is aborted by setting channel_list[0] to -1 */
713 params_le.channel_list[0] = cpu_to_le16(-1);
714 /* E-Scan (or anyother type) can be aborted by SCAN */
f96aa07e 715 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
5f4f9f11
AS
716 &params_le, sizeof(params_le));
717 if (err)
718 brcmf_err("Scan abort failed\n");
719 }
0f0fe990 720
5e787f75 721 brcmf_scan_config_mpc(ifp, 1);
0f0fe990 722
5f4f9f11
AS
723 /*
724 * e-scan can be initiated by scheduled scan
725 * which takes precedence.
726 */
727 if (cfg->sched_escan) {
728 brcmf_dbg(SCAN, "scheduled scan completed\n");
729 cfg->sched_escan = false;
730 if (!aborted)
731 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
5f4f9f11
AS
732 } else if (scan_request) {
733 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
734 aborted ? "Aborted" : "Done");
735 cfg80211_scan_done(scan_request, aborted);
5f4f9f11 736 }
6eda4e2c
HM
737 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
738 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
5f4f9f11
AS
739
740 return err;
741}
742
9f440b7b
AS
743static
744int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
745{
5f4f9f11
AS
746 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
747 struct net_device *ndev = wdev->netdev;
748
749 /* vif event pending in firmware */
750 if (brcmf_cfg80211_vif_event_armed(cfg))
751 return -EBUSY;
752
753 if (ndev) {
754 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
a0f472ac
AS
755 cfg->escan_info.ifp == netdev_priv(ndev))
756 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
757 true, true);
5f4f9f11
AS
758
759 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
760 }
761
9f440b7b
AS
762 switch (wdev->iftype) {
763 case NL80211_IFTYPE_ADHOC:
764 case NL80211_IFTYPE_STATION:
765 case NL80211_IFTYPE_AP:
766 case NL80211_IFTYPE_AP_VLAN:
767 case NL80211_IFTYPE_WDS:
768 case NL80211_IFTYPE_MONITOR:
769 case NL80211_IFTYPE_MESH_POINT:
770 return -EOPNOTSUPP;
771 case NL80211_IFTYPE_P2P_CLIENT:
772 case NL80211_IFTYPE_P2P_GO:
27f10e38 773 case NL80211_IFTYPE_P2P_DEVICE:
9f440b7b
AS
774 return brcmf_p2p_del_vif(wiphy, wdev);
775 case NL80211_IFTYPE_UNSPECIFIED:
9f440b7b
AS
776 default:
777 return -EINVAL;
778 }
779 return -EOPNOTSUPP;
780}
781
5b435de0
AS
782static s32
783brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
784 enum nl80211_iftype type, u32 *flags,
785 struct vif_params *params)
786{
7a5c1f64 787 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
c1179033 788 struct brcmf_if *ifp = netdev_priv(ndev);
128ce3b6 789 struct brcmf_cfg80211_vif *vif = ifp->vif;
5b435de0 790 s32 infra = 0;
1a873342 791 s32 ap = 0;
5b435de0
AS
792 s32 err = 0;
793
37a869ec
HM
794 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
795 type);
178e9ef9
HM
796
797 /* WAR: There are a number of p2p interface related problems which
798 * need to be handled initially (before doing the validate).
799 * wpa_supplicant tends to do iface changes on p2p device/client/go
800 * which are not always possible/allowed. However we need to return
801 * OK otherwise the wpa_supplicant wont start. The situation differs
802 * on configuration and setup (p2pon=1 module param). The first check
803 * is to see if the request is a change to station for p2p iface.
804 */
805 if ((type == NL80211_IFTYPE_STATION) &&
806 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
807 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
808 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
809 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
810 /* Now depending on whether module param p2pon=1 was used the
811 * response needs to be either 0 or EOPNOTSUPP. The reason is
812 * that if p2pon=1 is used, but a newer supplicant is used then
813 * we should return an error, as this combination wont work.
814 * In other situations 0 is returned and supplicant will start
815 * normally. It will give a trace in cfg80211, but it is the
816 * only way to get it working. Unfortunately this will result
817 * in situation where we wont support new supplicant in
818 * combination with module param p2pon=1, but that is the way
819 * it is. If the user tries this then unloading of driver might
820 * fail/lock.
821 */
822 if (cfg->p2p.p2pdev_dynamically)
823 return -EOPNOTSUPP;
824 else
825 return 0;
826 }
39504a2d
AS
827 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
828 if (err) {
829 brcmf_err("iface validation failed: err=%d\n", err);
830 return err;
831 }
5b435de0
AS
832 switch (type) {
833 case NL80211_IFTYPE_MONITOR:
834 case NL80211_IFTYPE_WDS:
57d6e91a
AS
835 brcmf_err("type (%d) : currently we do not support this type\n",
836 type);
5b435de0
AS
837 return -EOPNOTSUPP;
838 case NL80211_IFTYPE_ADHOC:
5b435de0
AS
839 infra = 0;
840 break;
841 case NL80211_IFTYPE_STATION:
5b435de0
AS
842 infra = 1;
843 break;
1a873342 844 case NL80211_IFTYPE_AP:
7a5c1f64 845 case NL80211_IFTYPE_P2P_GO:
1a873342
HM
846 ap = 1;
847 break;
5b435de0
AS
848 default:
849 err = -EINVAL;
850 goto done;
851 }
852
1a873342 853 if (ap) {
7a5c1f64
HM
854 if (type == NL80211_IFTYPE_P2P_GO) {
855 brcmf_dbg(INFO, "IF Type = P2P GO\n");
856 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
857 }
858 if (!err) {
7a5c1f64
HM
859 brcmf_dbg(INFO, "IF Type = AP\n");
860 }
5b435de0 861 } else {
128ce3b6 862 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
1a873342 863 if (err) {
57d6e91a 864 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
1a873342
HM
865 err = -EAGAIN;
866 goto done;
867 }
967fe2c8 868 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
647c9ae0 869 "Adhoc" : "Infra");
5b435de0 870 }
1a873342 871 ndev->ieee80211_ptr->iftype = type;
5b435de0 872
8851cce0
HM
873 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
874
5b435de0 875done:
d96b801f 876 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
877
878 return err;
879}
880
83cf17aa
FL
881static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
882 struct brcmf_scan_params_le *params_le,
e756af5b
HM
883 struct cfg80211_scan_request *request)
884{
885 u32 n_ssids;
886 u32 n_channels;
887 s32 i;
888 s32 offset;
029591f3 889 u16 chanspec;
e756af5b 890 char *ptr;
029591f3 891 struct brcmf_ssid_le ssid_le;
e756af5b 892
93803b33 893 eth_broadcast_addr(params_le->bssid);
e756af5b
HM
894 params_le->bss_type = DOT11_BSSTYPE_ANY;
895 params_le->scan_type = 0;
896 params_le->channel_num = 0;
897 params_le->nprobes = cpu_to_le32(-1);
898 params_le->active_time = cpu_to_le32(-1);
899 params_le->passive_time = cpu_to_le32(-1);
900 params_le->home_time = cpu_to_le32(-1);
901 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
902
903 /* if request is null exit so it will be all channel broadcast scan */
904 if (!request)
905 return;
906
907 n_ssids = request->n_ssids;
908 n_channels = request->n_channels;
909 /* Copy channel array if applicable */
4e8a008e
AS
910 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
911 n_channels);
e756af5b
HM
912 if (n_channels > 0) {
913 for (i = 0; i < n_channels; i++) {
83cf17aa
FL
914 chanspec = channel_to_chanspec(&cfg->d11inf,
915 request->channels[i]);
4e8a008e
AS
916 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
917 request->channels[i]->hw_value, chanspec);
029591f3 918 params_le->channel_list[i] = cpu_to_le16(chanspec);
e756af5b
HM
919 }
920 } else {
4e8a008e 921 brcmf_dbg(SCAN, "Scanning all channels\n");
e756af5b
HM
922 }
923 /* Copy ssid array if applicable */
4e8a008e 924 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
e756af5b
HM
925 if (n_ssids > 0) {
926 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
927 n_channels * sizeof(u16);
928 offset = roundup(offset, sizeof(u32));
929 ptr = (char *)params_le + offset;
930 for (i = 0; i < n_ssids; i++) {
029591f3
AS
931 memset(&ssid_le, 0, sizeof(ssid_le));
932 ssid_le.SSID_len =
933 cpu_to_le32(request->ssids[i].ssid_len);
934 memcpy(ssid_le.SSID, request->ssids[i].ssid,
935 request->ssids[i].ssid_len);
936 if (!ssid_le.SSID_len)
4e8a008e 937 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
e756af5b 938 else
4e8a008e
AS
939 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
940 i, ssid_le.SSID, ssid_le.SSID_len);
029591f3
AS
941 memcpy(ptr, &ssid_le, sizeof(ssid_le));
942 ptr += sizeof(ssid_le);
e756af5b
HM
943 }
944 } else {
4e8a008e 945 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
e756af5b 946 if ((request->ssids) && request->ssids->ssid_len) {
4e8a008e
AS
947 brcmf_dbg(SCAN, "SSID %s len=%d\n",
948 params_le->ssid_le.SSID,
949 request->ssids->ssid_len);
e756af5b
HM
950 params_le->ssid_le.SSID_len =
951 cpu_to_le32(request->ssids->ssid_len);
952 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
953 request->ssids->ssid_len);
954 }
955 }
956 /* Adding mask to channel numbers */
957 params_le->channel_num =
958 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
959 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
960}
961
e756af5b 962static s32
a0f472ac 963brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
c4958106 964 struct cfg80211_scan_request *request)
e756af5b
HM
965{
966 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
967 offsetof(struct brcmf_escan_params_le, params_le);
968 struct brcmf_escan_params_le *params;
969 s32 err = 0;
970
4e8a008e 971 brcmf_dbg(SCAN, "E-SCAN START\n");
e756af5b
HM
972
973 if (request != NULL) {
974 /* Allocate space for populating ssids in struct */
975 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
976
977 /* Allocate space for populating ssids in struct */
e9a6ca82 978 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
e756af5b
HM
979 }
980
981 params = kzalloc(params_size, GFP_KERNEL);
982 if (!params) {
983 err = -ENOMEM;
984 goto exit;
985 }
986 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
83cf17aa 987 brcmf_escan_prep(cfg, &params->params_le, request);
e756af5b 988 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
c4958106 989 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
e756af5b
HM
990 params->sync_id = cpu_to_le16(0x1234);
991
a0f472ac 992 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
e756af5b
HM
993 if (err) {
994 if (err == -EBUSY)
647c9ae0 995 brcmf_dbg(INFO, "system busy : escan canceled\n");
e756af5b 996 else
57d6e91a 997 brcmf_err("error (%d)\n", err);
e756af5b
HM
998 }
999
1000 kfree(params);
1001exit:
1002 return err;
1003}
1004
1005static s32
27a68fe3 1006brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
a0f472ac 1007 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
e756af5b
HM
1008{
1009 s32 err;
81f5dcb8 1010 u32 passive_scan;
e756af5b 1011 struct brcmf_scan_results *results;
9f440b7b 1012 struct escan_info *escan = &cfg->escan_info;
e756af5b 1013
4e8a008e 1014 brcmf_dbg(SCAN, "Enter\n");
a0f472ac 1015 escan->ifp = ifp;
9f440b7b
AS
1016 escan->wiphy = wiphy;
1017 escan->escan_state = WL_ESCAN_STATE_SCANNING;
81f5dcb8 1018 passive_scan = cfg->active_scan ? 0 : 1;
f96aa07e 1019 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 1020 passive_scan);
e756af5b 1021 if (err) {
57d6e91a 1022 brcmf_err("error (%d)\n", err);
e756af5b
HM
1023 return err;
1024 }
5e787f75 1025 brcmf_scan_config_mpc(ifp, 0);
27a68fe3 1026 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
e756af5b
HM
1027 results->version = 0;
1028 results->count = 0;
1029 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1030
c4958106 1031 err = escan->run(cfg, ifp, request);
e756af5b 1032 if (err)
5e787f75 1033 brcmf_scan_config_mpc(ifp, 1);
e756af5b
HM
1034 return err;
1035}
1036
1037static s32
a0f472ac 1038brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
e756af5b
HM
1039 struct cfg80211_scan_request *request,
1040 struct cfg80211_ssid *this_ssid)
1041{
a0f472ac
AS
1042 struct brcmf_if *ifp = vif->ifp;
1043 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e756af5b 1044 struct cfg80211_ssid *ssids;
81f5dcb8 1045 u32 passive_scan;
e756af5b
HM
1046 bool escan_req;
1047 bool spec_scan;
1048 s32 err;
675f5d82 1049 struct brcmf_ssid_le ssid_le;
e756af5b
HM
1050 u32 SSID_len;
1051
4e8a008e 1052 brcmf_dbg(SCAN, "START ESCAN\n");
e756af5b 1053
c1179033 1054 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 1055 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e756af5b
HM
1056 return -EAGAIN;
1057 }
c1179033 1058 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
57d6e91a
AS
1059 brcmf_err("Scanning being aborted: status (%lu)\n",
1060 cfg->scan_status);
e756af5b
HM
1061 return -EAGAIN;
1062 }
1687eee2
AS
1063 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1064 brcmf_err("Scanning suppressed: status (%lu)\n",
1065 cfg->scan_status);
1066 return -EAGAIN;
1067 }
c1179033 1068 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
57d6e91a 1069 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
e756af5b
HM
1070 return -EAGAIN;
1071 }
1072
0f8ffe17 1073 /* If scan req comes for p2p0, send it over primary I/F */
a0f472ac
AS
1074 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1075 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
0f8ffe17 1076
e756af5b
HM
1077 escan_req = false;
1078 if (request) {
1079 /* scan bss */
1080 ssids = request->ssids;
1081 escan_req = true;
1082 } else {
1083 /* scan in ibss */
1084 /* we don't do escan in ibss */
1085 ssids = this_ssid;
1086 }
1087
27a68fe3 1088 cfg->scan_request = request;
c1179033 1089 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e756af5b 1090 if (escan_req) {
9f440b7b 1091 cfg->escan_info.run = brcmf_run_escan;
a0f472ac 1092 err = brcmf_p2p_scan_prep(wiphy, request, vif);
9f440b7b
AS
1093 if (err)
1094 goto scan_out;
1095
a0f472ac 1096 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
2cb941c0 1097 if (err)
e756af5b
HM
1098 goto scan_out;
1099 } else {
4e8a008e
AS
1100 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1101 ssids->ssid, ssids->ssid_len);
675f5d82
HM
1102 memset(&ssid_le, 0, sizeof(ssid_le));
1103 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1104 ssid_le.SSID_len = cpu_to_le32(0);
e756af5b
HM
1105 spec_scan = false;
1106 if (SSID_len) {
675f5d82
HM
1107 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1108 ssid_le.SSID_len = cpu_to_le32(SSID_len);
e756af5b
HM
1109 spec_scan = true;
1110 } else
4e8a008e 1111 brcmf_dbg(SCAN, "Broadcast scan\n");
e756af5b 1112
81f5dcb8 1113 passive_scan = cfg->active_scan ? 0 : 1;
c1179033 1114 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 1115 passive_scan);
e756af5b 1116 if (err) {
57d6e91a 1117 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
e756af5b
HM
1118 goto scan_out;
1119 }
5e787f75 1120 brcmf_scan_config_mpc(ifp, 0);
675f5d82
HM
1121 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1122 sizeof(ssid_le));
e756af5b
HM
1123 if (err) {
1124 if (err == -EBUSY)
647c9ae0 1125 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
675f5d82 1126 ssid_le.SSID);
e756af5b 1127 else
57d6e91a 1128 brcmf_err("WLC_SCAN error (%d)\n", err);
e756af5b 1129
5e787f75 1130 brcmf_scan_config_mpc(ifp, 1);
e756af5b
HM
1131 goto scan_out;
1132 }
1133 }
1134
661fa95d
HM
1135 /* Arm scan timeout timer */
1136 mod_timer(&cfg->escan_timeout, jiffies +
d5367334 1137 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
661fa95d 1138
e756af5b
HM
1139 return 0;
1140
1141scan_out:
c1179033 1142 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 1143 cfg->scan_request = NULL;
e756af5b
HM
1144 return err;
1145}
1146
5b435de0 1147static s32
0abb5f21 1148brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
5b435de0 1149{
a0f472ac 1150 struct brcmf_cfg80211_vif *vif;
5b435de0
AS
1151 s32 err = 0;
1152
d96b801f 1153 brcmf_dbg(TRACE, "Enter\n");
a0f472ac
AS
1154 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1155 if (!check_vif_up(vif))
5b435de0
AS
1156 return -EIO;
1157
a0f472ac 1158 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
e756af5b 1159
5b435de0 1160 if (err)
57d6e91a 1161 brcmf_err("scan error (%d)\n", err);
5b435de0 1162
d96b801f 1163 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1164 return err;
1165}
1166
1167static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1168{
1169 s32 err = 0;
1170
ac24be6f
AS
1171 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1172 rts_threshold);
5b435de0 1173 if (err)
57d6e91a 1174 brcmf_err("Error (%d)\n", err);
5b435de0
AS
1175
1176 return err;
1177}
1178
1179static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1180{
1181 s32 err = 0;
1182
ac24be6f
AS
1183 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1184 frag_threshold);
5b435de0 1185 if (err)
57d6e91a 1186 brcmf_err("Error (%d)\n", err);
5b435de0
AS
1187
1188 return err;
1189}
1190
1191static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1192{
1193 s32 err = 0;
b87e2c48 1194 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
5b435de0 1195
ac24be6f 1196 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
5b435de0 1197 if (err) {
57d6e91a 1198 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
5b435de0
AS
1199 return err;
1200 }
1201 return err;
1202}
1203
1204static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1205{
27a68fe3
AS
1206 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1207 struct net_device *ndev = cfg_to_ndev(cfg);
0abb5f21 1208 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1209 s32 err = 0;
1210
d96b801f 1211 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1212 if (!check_vif_up(ifp->vif))
5b435de0
AS
1213 return -EIO;
1214
1215 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
27a68fe3
AS
1216 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1217 cfg->conf->rts_threshold = wiphy->rts_threshold;
1218 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
5b435de0
AS
1219 if (!err)
1220 goto done;
1221 }
1222 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
27a68fe3
AS
1223 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1224 cfg->conf->frag_threshold = wiphy->frag_threshold;
1225 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
5b435de0
AS
1226 if (!err)
1227 goto done;
1228 }
1229 if (changed & WIPHY_PARAM_RETRY_LONG
27a68fe3
AS
1230 && (cfg->conf->retry_long != wiphy->retry_long)) {
1231 cfg->conf->retry_long = wiphy->retry_long;
1232 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
5b435de0
AS
1233 if (!err)
1234 goto done;
1235 }
1236 if (changed & WIPHY_PARAM_RETRY_SHORT
27a68fe3
AS
1237 && (cfg->conf->retry_short != wiphy->retry_short)) {
1238 cfg->conf->retry_short = wiphy->retry_short;
1239 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
5b435de0
AS
1240 if (!err)
1241 goto done;
1242 }
1243
1244done:
d96b801f 1245 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1246 return err;
1247}
1248
5b435de0
AS
1249static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1250{
1251 memset(prof, 0, sizeof(*prof));
1252}
1253
9b7a0ddc
AS
1254static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1255{
1256 u16 reason;
1257
1258 switch (e->event_code) {
1259 case BRCMF_E_DEAUTH:
1260 case BRCMF_E_DEAUTH_IND:
1261 case BRCMF_E_DISASSOC_IND:
1262 reason = e->reason;
1263 break;
1264 case BRCMF_E_LINK:
1265 default:
1266 reason = 0;
1267 break;
1268 }
1269 return reason;
1270}
1271
1272static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
5b435de0 1273{
61730d4d 1274 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
5b435de0
AS
1275 s32 err = 0;
1276
d96b801f 1277 brcmf_dbg(TRACE, "Enter\n");
5b435de0 1278
b0a79088 1279 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
647c9ae0 1280 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
903e0eee 1281 err = brcmf_fil_cmd_data_set(vif->ifp,
ac24be6f 1282 BRCMF_C_DISASSOC, NULL, 0);
a538ae31 1283 if (err) {
57d6e91a 1284 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
a538ae31 1285 }
b0a79088
HM
1286 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1287 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1288 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1289 true, GFP_KERNEL);
5b435de0 1290 }
903e0eee 1291 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
61730d4d
PH
1292 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1293 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
d96b801f 1294 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1295}
1296
1297static s32
1298brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1299 struct cfg80211_ibss_params *params)
1300{
27a68fe3 1301 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1302 struct brcmf_if *ifp = netdev_priv(ndev);
1303 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1304 struct brcmf_join_params join_params;
1305 size_t join_params_size = 0;
1306 s32 err = 0;
1307 s32 wsec = 0;
1308 s32 bcnprd;
1701261d 1309 u16 chanspec;
e9a6ca82 1310 u32 ssid_len;
5b435de0 1311
d96b801f 1312 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1313 if (!check_vif_up(ifp->vif))
5b435de0
AS
1314 return -EIO;
1315
1316 if (params->ssid)
16886735 1317 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
5b435de0 1318 else {
16886735 1319 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
5b435de0
AS
1320 return -EOPNOTSUPP;
1321 }
1322
c1179033 1323 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1324
1325 if (params->bssid)
16886735 1326 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
5b435de0 1327 else
16886735 1328 brcmf_dbg(CONN, "No BSSID specified\n");
5b435de0 1329
683b6d3b 1330 if (params->chandef.chan)
16886735
AS
1331 brcmf_dbg(CONN, "channel: %d\n",
1332 params->chandef.chan->center_freq);
5b435de0 1333 else
16886735 1334 brcmf_dbg(CONN, "no channel specified\n");
5b435de0
AS
1335
1336 if (params->channel_fixed)
16886735 1337 brcmf_dbg(CONN, "fixed channel required\n");
5b435de0 1338 else
16886735 1339 brcmf_dbg(CONN, "no fixed channel required\n");
5b435de0
AS
1340
1341 if (params->ie && params->ie_len)
16886735 1342 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
5b435de0 1343 else
16886735 1344 brcmf_dbg(CONN, "no ie specified\n");
5b435de0
AS
1345
1346 if (params->beacon_interval)
16886735
AS
1347 brcmf_dbg(CONN, "beacon interval: %d\n",
1348 params->beacon_interval);
5b435de0 1349 else
16886735 1350 brcmf_dbg(CONN, "no beacon interval specified\n");
5b435de0
AS
1351
1352 if (params->basic_rates)
16886735 1353 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
5b435de0 1354 else
16886735 1355 brcmf_dbg(CONN, "no basic rates specified\n");
5b435de0
AS
1356
1357 if (params->privacy)
16886735 1358 brcmf_dbg(CONN, "privacy required\n");
5b435de0 1359 else
16886735 1360 brcmf_dbg(CONN, "no privacy required\n");
5b435de0
AS
1361
1362 /* Configure Privacy for starter */
1363 if (params->privacy)
1364 wsec |= WEP_ENABLED;
1365
c1179033 1366 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
5b435de0 1367 if (err) {
57d6e91a 1368 brcmf_err("wsec failed (%d)\n", err);
5b435de0
AS
1369 goto done;
1370 }
1371
1372 /* Configure Beacon Interval for starter */
1373 if (params->beacon_interval)
1374 bcnprd = params->beacon_interval;
1375 else
1376 bcnprd = 100;
1377
b87e2c48 1378 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
5b435de0 1379 if (err) {
57d6e91a 1380 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
5b435de0
AS
1381 goto done;
1382 }
1383
1384 /* Configure required join parameter */
1385 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1386
1387 /* SSID */
e9a6ca82
HM
1388 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1389 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1390 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
5b435de0 1391 join_params_size = sizeof(join_params.ssid_le);
5b435de0
AS
1392
1393 /* BSSID */
1394 if (params->bssid) {
1395 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
e9a6ca82 1396 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
6c8c4f72 1397 memcpy(profile->bssid, params->bssid, ETH_ALEN);
5b435de0 1398 } else {
93803b33
JP
1399 eth_broadcast_addr(join_params.params_le.bssid);
1400 eth_zero_addr(profile->bssid);
5b435de0
AS
1401 }
1402
5b435de0 1403 /* Channel */
683b6d3b 1404 if (params->chandef.chan) {
5b435de0
AS
1405 u32 target_channel;
1406
27a68fe3 1407 cfg->channel =
5b435de0 1408 ieee80211_frequency_to_channel(
683b6d3b 1409 params->chandef.chan->center_freq);
5b435de0
AS
1410 if (params->channel_fixed) {
1411 /* adding chanspec */
600a897d
AS
1412 chanspec = chandef_to_chanspec(&cfg->d11inf,
1413 &params->chandef);
1701261d
HM
1414 join_params.params_le.chanspec_list[0] =
1415 cpu_to_le16(chanspec);
1416 join_params.params_le.chanspec_num = cpu_to_le32(1);
1417 join_params_size += sizeof(join_params.params_le);
5b435de0
AS
1418 }
1419
1420 /* set channel for starter */
27a68fe3 1421 target_channel = cfg->channel;
b87e2c48 1422 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
81f5dcb8 1423 target_channel);
5b435de0 1424 if (err) {
57d6e91a 1425 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
5b435de0
AS
1426 goto done;
1427 }
1428 } else
27a68fe3 1429 cfg->channel = 0;
5b435de0 1430
27a68fe3 1431 cfg->ibss_starter = false;
5b435de0
AS
1432
1433
c1179033 1434 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1435 &join_params, join_params_size);
5b435de0 1436 if (err) {
57d6e91a 1437 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
5b435de0
AS
1438 goto done;
1439 }
1440
1441done:
1442 if (err)
c1179033 1443 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
d96b801f 1444 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1445 return err;
1446}
1447
1448static s32
1449brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1450{
0abb5f21 1451 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 1452
d96b801f 1453 brcmf_dbg(TRACE, "Enter\n");
6a98d64a
HM
1454 if (!check_vif_up(ifp->vif)) {
1455 /* When driver is being unloaded, it can end up here. If an
1456 * error is returned then later on a debug trace in the wireless
1457 * core module will be printed. To avoid this 0 is returned.
1458 */
1459 return 0;
1460 }
5b435de0 1461
9b7a0ddc 1462 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
42e0ed0d 1463 brcmf_net_setcarrier(ifp, false);
5b435de0 1464
d96b801f 1465 brcmf_dbg(TRACE, "Exit\n");
5b435de0 1466
12f32370 1467 return 0;
5b435de0
AS
1468}
1469
1470static s32 brcmf_set_wpa_version(struct net_device *ndev,
1471 struct cfg80211_connect_params *sme)
1472{
6ac4f4ed 1473 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1474 struct brcmf_cfg80211_security *sec;
1475 s32 val = 0;
1476 s32 err = 0;
1477
1478 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1479 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1480 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1481 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1482 else
1483 val = WPA_AUTH_DISABLED;
16886735 1484 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
89286dc9 1485 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
5b435de0 1486 if (err) {
57d6e91a 1487 brcmf_err("set wpa_auth failed (%d)\n", err);
5b435de0
AS
1488 return err;
1489 }
06bb123e 1490 sec = &profile->sec;
5b435de0
AS
1491 sec->wpa_versions = sme->crypto.wpa_versions;
1492 return err;
1493}
1494
1495static s32 brcmf_set_auth_type(struct net_device *ndev,
1496 struct cfg80211_connect_params *sme)
1497{
6ac4f4ed 1498 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1499 struct brcmf_cfg80211_security *sec;
1500 s32 val = 0;
1501 s32 err = 0;
1502
1503 switch (sme->auth_type) {
1504 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1505 val = 0;
16886735 1506 brcmf_dbg(CONN, "open system\n");
5b435de0
AS
1507 break;
1508 case NL80211_AUTHTYPE_SHARED_KEY:
1509 val = 1;
16886735 1510 brcmf_dbg(CONN, "shared key\n");
5b435de0
AS
1511 break;
1512 case NL80211_AUTHTYPE_AUTOMATIC:
1513 val = 2;
16886735 1514 brcmf_dbg(CONN, "automatic\n");
5b435de0
AS
1515 break;
1516 case NL80211_AUTHTYPE_NETWORK_EAP:
16886735 1517 brcmf_dbg(CONN, "network eap\n");
5b435de0
AS
1518 default:
1519 val = 2;
57d6e91a 1520 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
5b435de0
AS
1521 break;
1522 }
1523
89286dc9 1524 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
5b435de0 1525 if (err) {
57d6e91a 1526 brcmf_err("set auth failed (%d)\n", err);
5b435de0
AS
1527 return err;
1528 }
06bb123e 1529 sec = &profile->sec;
5b435de0
AS
1530 sec->auth_type = sme->auth_type;
1531 return err;
1532}
1533
1534static s32
87b7e9e2
DK
1535brcmf_set_wsec_mode(struct net_device *ndev,
1536 struct cfg80211_connect_params *sme, bool mfp)
5b435de0 1537{
6ac4f4ed 1538 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1539 struct brcmf_cfg80211_security *sec;
1540 s32 pval = 0;
1541 s32 gval = 0;
87b7e9e2 1542 s32 wsec;
5b435de0
AS
1543 s32 err = 0;
1544
1545 if (sme->crypto.n_ciphers_pairwise) {
1546 switch (sme->crypto.ciphers_pairwise[0]) {
1547 case WLAN_CIPHER_SUITE_WEP40:
1548 case WLAN_CIPHER_SUITE_WEP104:
1549 pval = WEP_ENABLED;
1550 break;
1551 case WLAN_CIPHER_SUITE_TKIP:
1552 pval = TKIP_ENABLED;
1553 break;
1554 case WLAN_CIPHER_SUITE_CCMP:
1555 pval = AES_ENABLED;
1556 break;
1557 case WLAN_CIPHER_SUITE_AES_CMAC:
1558 pval = AES_ENABLED;
1559 break;
1560 default:
57d6e91a
AS
1561 brcmf_err("invalid cipher pairwise (%d)\n",
1562 sme->crypto.ciphers_pairwise[0]);
5b435de0
AS
1563 return -EINVAL;
1564 }
1565 }
1566 if (sme->crypto.cipher_group) {
1567 switch (sme->crypto.cipher_group) {
1568 case WLAN_CIPHER_SUITE_WEP40:
1569 case WLAN_CIPHER_SUITE_WEP104:
1570 gval = WEP_ENABLED;
1571 break;
1572 case WLAN_CIPHER_SUITE_TKIP:
1573 gval = TKIP_ENABLED;
1574 break;
1575 case WLAN_CIPHER_SUITE_CCMP:
1576 gval = AES_ENABLED;
1577 break;
1578 case WLAN_CIPHER_SUITE_AES_CMAC:
1579 gval = AES_ENABLED;
1580 break;
1581 default:
57d6e91a
AS
1582 brcmf_err("invalid cipher group (%d)\n",
1583 sme->crypto.cipher_group);
5b435de0
AS
1584 return -EINVAL;
1585 }
1586 }
1587
16886735 1588 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
89286dc9
HM
1589 /* In case of privacy, but no security and WPS then simulate */
1590 /* setting AES. WPS-2.0 allows no security */
1591 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1592 sme->privacy)
1593 pval = AES_ENABLED;
87b7e9e2
DK
1594
1595 if (mfp)
1596 wsec = pval | gval | MFP_CAPABLE;
1597 else
1598 wsec = pval | gval;
1599 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
5b435de0 1600 if (err) {
57d6e91a 1601 brcmf_err("error (%d)\n", err);
5b435de0
AS
1602 return err;
1603 }
1604
06bb123e 1605 sec = &profile->sec;
5b435de0
AS
1606 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1607 sec->cipher_group = sme->crypto.cipher_group;
1608
1609 return err;
1610}
1611
1612static s32
1613brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1614{
6ac4f4ed 1615 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1616 struct brcmf_cfg80211_security *sec;
1617 s32 val = 0;
1618 s32 err = 0;
1619
1620 if (sme->crypto.n_akm_suites) {
89286dc9
HM
1621 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1622 "wpa_auth", &val);
5b435de0 1623 if (err) {
57d6e91a 1624 brcmf_err("could not get wpa_auth (%d)\n", err);
5b435de0
AS
1625 return err;
1626 }
1627 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1628 switch (sme->crypto.akm_suites[0]) {
1629 case WLAN_AKM_SUITE_8021X:
1630 val = WPA_AUTH_UNSPECIFIED;
1631 break;
1632 case WLAN_AKM_SUITE_PSK:
1633 val = WPA_AUTH_PSK;
1634 break;
1635 default:
57d6e91a
AS
1636 brcmf_err("invalid cipher group (%d)\n",
1637 sme->crypto.cipher_group);
5b435de0
AS
1638 return -EINVAL;
1639 }
1640 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1641 switch (sme->crypto.akm_suites[0]) {
1642 case WLAN_AKM_SUITE_8021X:
1643 val = WPA2_AUTH_UNSPECIFIED;
1644 break;
1645 case WLAN_AKM_SUITE_PSK:
1646 val = WPA2_AUTH_PSK;
1647 break;
1648 default:
57d6e91a
AS
1649 brcmf_err("invalid cipher group (%d)\n",
1650 sme->crypto.cipher_group);
5b435de0
AS
1651 return -EINVAL;
1652 }
1653 }
1654
16886735 1655 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
89286dc9
HM
1656 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1657 "wpa_auth", val);
5b435de0 1658 if (err) {
57d6e91a 1659 brcmf_err("could not set wpa_auth (%d)\n", err);
5b435de0
AS
1660 return err;
1661 }
1662 }
06bb123e 1663 sec = &profile->sec;
5b435de0
AS
1664 sec->wpa_auth = sme->crypto.akm_suites[0];
1665
1666 return err;
1667}
1668
1669static s32
f09d0c02
HM
1670brcmf_set_sharedkey(struct net_device *ndev,
1671 struct cfg80211_connect_params *sme)
5b435de0 1672{
6ac4f4ed 1673 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1674 struct brcmf_cfg80211_security *sec;
1675 struct brcmf_wsec_key key;
1676 s32 val;
1677 s32 err = 0;
1678
16886735 1679 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
5b435de0 1680
a718e2fe
RV
1681 if (sme->key_len == 0)
1682 return 0;
1683
06bb123e 1684 sec = &profile->sec;
16886735
AS
1685 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1686 sec->wpa_versions, sec->cipher_pairwise);
a718e2fe
RV
1687
1688 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1689 return 0;
1690
f09d0c02
HM
1691 if (!(sec->cipher_pairwise &
1692 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1693 return 0;
a718e2fe 1694
f09d0c02
HM
1695 memset(&key, 0, sizeof(key));
1696 key.len = (u32) sme->key_len;
1697 key.index = (u32) sme->key_idx;
1698 if (key.len > sizeof(key.data)) {
57d6e91a 1699 brcmf_err("Too long key length (%u)\n", key.len);
f09d0c02
HM
1700 return -EINVAL;
1701 }
1702 memcpy(key.data, sme->key, key.len);
1703 key.flags = BRCMF_PRIMARY_KEY;
1704 switch (sec->cipher_pairwise) {
1705 case WLAN_CIPHER_SUITE_WEP40:
1706 key.algo = CRYPTO_ALGO_WEP1;
1707 break;
1708 case WLAN_CIPHER_SUITE_WEP104:
1709 key.algo = CRYPTO_ALGO_WEP128;
1710 break;
1711 default:
57d6e91a
AS
1712 brcmf_err("Invalid algorithm (%d)\n",
1713 sme->crypto.ciphers_pairwise[0]);
f09d0c02
HM
1714 return -EINVAL;
1715 }
1716 /* Set the new key/index */
16886735
AS
1717 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1718 key.len, key.index, key.algo);
1719 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
118eb304 1720 err = send_key_to_dongle(netdev_priv(ndev), &key);
f09d0c02
HM
1721 if (err)
1722 return err;
1723
1724 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
16886735 1725 brcmf_dbg(CONN, "set auth_type to shared key\n");
f09d0c02 1726 val = WL_AUTH_SHARED_KEY; /* shared key */
ac24be6f 1727 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
f09d0c02 1728 if (err)
57d6e91a 1729 brcmf_err("set auth failed (%d)\n", err);
5b435de0
AS
1730 }
1731 return err;
1732}
1733
cbb1ec94
AS
1734static
1735enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1736 enum nl80211_auth_type type)
1737{
c08437b4
AS
1738 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1739 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1740 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1741 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
cbb1ec94
AS
1742 }
1743 return type;
1744}
1745
5b435de0
AS
1746static s32
1747brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
cbb1ec94 1748 struct cfg80211_connect_params *sme)
5b435de0 1749{
27a68fe3 1750 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 1751 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1752 struct ieee80211_channel *chan = sme->channel;
1753 struct brcmf_join_params join_params;
1754 size_t join_params_size;
4b5800fe
JB
1755 const struct brcmf_tlv *rsn_ie;
1756 const struct brcmf_vs_tlv *wpa_ie;
1757 const void *ie;
89286dc9
HM
1758 u32 ie_len;
1759 struct brcmf_ext_join_params_le *ext_join_params;
1701261d 1760 u16 chanspec;
5b435de0 1761 s32 err = 0;
e9a6ca82 1762 u32 ssid_len;
5b435de0 1763
d96b801f 1764 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1765 if (!check_vif_up(ifp->vif))
5b435de0
AS
1766 return -EIO;
1767
1768 if (!sme->ssid) {
57d6e91a 1769 brcmf_err("Invalid ssid\n");
5b435de0
AS
1770 return -EOPNOTSUPP;
1771 }
1772
89286dc9
HM
1773 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1774 /* A normal (non P2P) connection request setup. */
1775 ie = NULL;
1776 ie_len = 0;
1777 /* find the WPA_IE */
1778 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1779 if (wpa_ie) {
1780 ie = wpa_ie;
1781 ie_len = wpa_ie->len + TLV_HDR_LEN;
1782 } else {
1783 /* find the RSN_IE */
4b5800fe
JB
1784 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1785 sme->ie_len,
89286dc9
HM
1786 WLAN_EID_RSN);
1787 if (rsn_ie) {
1788 ie = rsn_ie;
1789 ie_len = rsn_ie->len + TLV_HDR_LEN;
1790 }
1791 }
1792 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1793 }
1794
1795 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1796 sme->ie, sme->ie_len);
1797 if (err)
1798 brcmf_err("Set Assoc REQ IE Failed\n");
1799 else
1800 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1801
c1179033 1802 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1803
1804 if (chan) {
27a68fe3 1805 cfg->channel =
5b435de0 1806 ieee80211_frequency_to_channel(chan->center_freq);
83cf17aa 1807 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
1701261d
HM
1808 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1809 cfg->channel, chan->center_freq, chanspec);
1810 } else {
27a68fe3 1811 cfg->channel = 0;
1701261d
HM
1812 chanspec = 0;
1813 }
5b435de0 1814
647c9ae0 1815 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
5b435de0
AS
1816
1817 err = brcmf_set_wpa_version(ndev, sme);
1818 if (err) {
57d6e91a 1819 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
5b435de0
AS
1820 goto done;
1821 }
1822
cbb1ec94 1823 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
5b435de0
AS
1824 err = brcmf_set_auth_type(ndev, sme);
1825 if (err) {
57d6e91a 1826 brcmf_err("wl_set_auth_type failed (%d)\n", err);
5b435de0
AS
1827 goto done;
1828 }
1829
87b7e9e2 1830 err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
5b435de0 1831 if (err) {
57d6e91a 1832 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
5b435de0
AS
1833 goto done;
1834 }
1835
1836 err = brcmf_set_key_mgmt(ndev, sme);
1837 if (err) {
57d6e91a 1838 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
5b435de0
AS
1839 goto done;
1840 }
1841
f09d0c02 1842 err = brcmf_set_sharedkey(ndev, sme);
5b435de0 1843 if (err) {
57d6e91a 1844 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
5b435de0
AS
1845 goto done;
1846 }
1847
89286dc9
HM
1848 /* Join with specific BSSID and cached SSID
1849 * If SSID is zero join based on BSSID only
1850 */
1851 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1852 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1853 if (cfg->channel)
1854 join_params_size += sizeof(u16);
1855 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1856 if (ext_join_params == NULL) {
1857 err = -ENOMEM;
1858 goto done;
1859 }
e9a6ca82
HM
1860 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1861 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1862 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1863 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1864 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1865 ext_join_params->ssid_le.SSID, ssid_len);
63dd99e6 1866
89286dc9
HM
1867 /* Set up join scan parameters */
1868 ext_join_params->scan_le.scan_type = -1;
89286dc9
HM
1869 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1870
1871 if (sme->bssid)
1872 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1873 else
93803b33 1874 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
89286dc9
HM
1875
1876 if (cfg->channel) {
1877 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1878
1879 ext_join_params->assoc_le.chanspec_list[0] =
1880 cpu_to_le16(chanspec);
63dd99e6
HM
1881 /* Increase dwell time to receive probe response or detect
1882 * beacon from target AP at a noisy air only during connect
1883 * command.
1884 */
1885 ext_join_params->scan_le.active_time =
1886 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1887 ext_join_params->scan_le.passive_time =
1888 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1889 /* To sync with presence period of VSDB GO send probe request
1890 * more frequently. Probe request will be stopped when it gets
1891 * probe response from target AP/GO.
1892 */
1893 ext_join_params->scan_le.nprobes =
1894 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1895 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1896 } else {
1897 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
1898 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
1899 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
89286dc9
HM
1900 }
1901
1902 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1903 join_params_size);
1904 kfree(ext_join_params);
1905 if (!err)
1906 /* This is it. join command worked, we are done */
1907 goto done;
1908
1909 /* join command failed, fallback to set ssid */
5b435de0
AS
1910 memset(&join_params, 0, sizeof(join_params));
1911 join_params_size = sizeof(join_params.ssid_le);
1912
e9a6ca82
HM
1913 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
1914 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
5b435de0 1915
89286dc9
HM
1916 if (sme->bssid)
1917 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1918 else
93803b33 1919 eth_broadcast_addr(join_params.params_le.bssid);
5b435de0 1920
1701261d
HM
1921 if (cfg->channel) {
1922 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1923 join_params.params_le.chanspec_num = cpu_to_le32(1);
1924 join_params_size += sizeof(join_params.params_le);
1925 }
c1179033 1926 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1927 &join_params, join_params_size);
5b435de0 1928 if (err)
89286dc9 1929 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
5b435de0
AS
1930
1931done:
1932 if (err)
c1179033 1933 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
d96b801f 1934 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1935 return err;
1936}
1937
1938static s32
1939brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1940 u16 reason_code)
1941{
0abb5f21
AS
1942 struct brcmf_if *ifp = netdev_priv(ndev);
1943 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1944 struct brcmf_scb_val_le scbval;
1945 s32 err = 0;
1946
d96b801f 1947 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
ce81e317 1948 if (!check_vif_up(ifp->vif))
5b435de0
AS
1949 return -EIO;
1950
c1179033 1951 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
4f3fff14 1952 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
80279fb7 1953 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
5b435de0 1954
06bb123e 1955 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
5b435de0 1956 scbval.val = cpu_to_le32(reason_code);
c1179033 1957 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
ac24be6f 1958 &scbval, sizeof(scbval));
5b435de0 1959 if (err)
57d6e91a 1960 brcmf_err("error (%d)\n", err);
5b435de0 1961
d96b801f 1962 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1963 return err;
1964}
1965
1966static s32
c8442118 1967brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
d3f31134 1968 enum nl80211_tx_power_setting type, s32 mbm)
5b435de0 1969{
27a68fe3 1970 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1971 struct net_device *ndev = cfg_to_ndev(cfg);
1972 struct brcmf_if *ifp = netdev_priv(ndev);
60dc35ef
HM
1973 s32 err;
1974 s32 disable;
1975 u32 qdbm = 127;
5b435de0 1976
60dc35ef 1977 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
ce81e317 1978 if (!check_vif_up(ifp->vif))
5b435de0
AS
1979 return -EIO;
1980
1981 switch (type) {
1982 case NL80211_TX_POWER_AUTOMATIC:
1983 break;
1984 case NL80211_TX_POWER_LIMITED:
5b435de0 1985 case NL80211_TX_POWER_FIXED:
60dc35ef 1986 if (mbm < 0) {
57d6e91a 1987 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
5b435de0
AS
1988 err = -EINVAL;
1989 goto done;
1990 }
60dc35ef
HM
1991 qdbm = MBM_TO_DBM(4 * mbm);
1992 if (qdbm > 127)
1993 qdbm = 127;
1994 qdbm |= WL_TXPWR_OVERRIDE;
5b435de0 1995 break;
60dc35ef
HM
1996 default:
1997 brcmf_err("Unsupported type %d\n", type);
1998 err = -EINVAL;
1999 goto done;
5b435de0
AS
2000 }
2001 /* Make sure radio is off or on as far as software is concerned */
2002 disable = WL_RADIO_SW_DISABLE << 16;
ac24be6f 2003 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
5b435de0 2004 if (err)
57d6e91a 2005 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
5b435de0 2006
60dc35ef 2007 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
5b435de0 2008 if (err)
57d6e91a 2009 brcmf_err("qtxpower error (%d)\n", err);
5b435de0
AS
2010
2011done:
60dc35ef 2012 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
5b435de0
AS
2013 return err;
2014}
2015
60dc35ef
HM
2016static s32
2017brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2018 s32 *dbm)
5b435de0 2019{
27a68fe3 2020 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
60dc35ef
HM
2021 struct net_device *ndev = cfg_to_ndev(cfg);
2022 struct brcmf_if *ifp = netdev_priv(ndev);
2023 s32 qdbm = 0;
2024 s32 err;
5b435de0 2025
d96b801f 2026 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2027 if (!check_vif_up(ifp->vif))
5b435de0
AS
2028 return -EIO;
2029
60dc35ef 2030 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
5b435de0 2031 if (err) {
57d6e91a 2032 brcmf_err("error (%d)\n", err);
5b435de0
AS
2033 goto done;
2034 }
60dc35ef 2035 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
5b435de0
AS
2036
2037done:
60dc35ef 2038 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
5b435de0
AS
2039 return err;
2040}
2041
2042static s32
2043brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
60dc35ef 2044 u8 key_idx, bool unicast, bool multicast)
5b435de0 2045{
0abb5f21 2046 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2047 u32 index;
2048 u32 wsec;
2049 s32 err = 0;
2050
d96b801f 2051 brcmf_dbg(TRACE, "Enter\n");
16886735 2052 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 2053 if (!check_vif_up(ifp->vif))
5b435de0
AS
2054 return -EIO;
2055
0abb5f21 2056 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2057 if (err) {
57d6e91a 2058 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
5b435de0
AS
2059 goto done;
2060 }
2061
2062 if (wsec & WEP_ENABLED) {
2063 /* Just select a new current key */
2064 index = key_idx;
0abb5f21 2065 err = brcmf_fil_cmd_int_set(ifp,
ac24be6f 2066 BRCMF_C_SET_KEY_PRIMARY, index);
5b435de0 2067 if (err)
57d6e91a 2068 brcmf_err("error (%d)\n", err);
5b435de0
AS
2069 }
2070done:
d96b801f 2071 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2072 return err;
2073}
2074
2075static s32
2076brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
2077 u8 key_idx, const u8 *mac_addr, struct key_params *params)
2078{
992f6068 2079 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2080 struct brcmf_wsec_key key;
5b435de0 2081 s32 err = 0;
992f6068 2082 u8 keybuf[8];
5b435de0
AS
2083
2084 memset(&key, 0, sizeof(key));
2085 key.index = (u32) key_idx;
2086 /* Instead of bcast for ea address for default wep keys,
2087 driver needs it to be Null */
2088 if (!is_multicast_ether_addr(mac_addr))
2089 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
2090 key.len = (u32) params->key_len;
2091 /* check for key index change */
2092 if (key.len == 0) {
2093 /* key delete */
118eb304 2094 err = send_key_to_dongle(ifp, &key);
5b435de0 2095 if (err)
57d6e91a 2096 brcmf_err("key delete error (%d)\n", err);
5b435de0
AS
2097 } else {
2098 if (key.len > sizeof(key.data)) {
57d6e91a 2099 brcmf_err("Invalid key length (%d)\n", key.len);
5b435de0
AS
2100 return -EINVAL;
2101 }
2102
16886735 2103 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
5b435de0
AS
2104 memcpy(key.data, params->key, key.len);
2105
967fe2c8 2106 if (!brcmf_is_apmode(ifp->vif) &&
992f6068
HM
2107 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
2108 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
5b435de0
AS
2109 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2110 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2111 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2112 }
2113
2114 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
2115 if (params->seq && params->seq_len == 6) {
2116 /* rx iv */
2117 u8 *ivptr;
2118 ivptr = (u8 *) params->seq;
2119 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2120 (ivptr[3] << 8) | ivptr[2];
2121 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2122 key.iv_initialized = true;
2123 }
2124
2125 switch (params->cipher) {
2126 case WLAN_CIPHER_SUITE_WEP40:
2127 key.algo = CRYPTO_ALGO_WEP1;
16886735 2128 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2129 break;
2130 case WLAN_CIPHER_SUITE_WEP104:
2131 key.algo = CRYPTO_ALGO_WEP128;
16886735 2132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
2133 break;
2134 case WLAN_CIPHER_SUITE_TKIP:
2135 key.algo = CRYPTO_ALGO_TKIP;
16886735 2136 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
2137 break;
2138 case WLAN_CIPHER_SUITE_AES_CMAC:
2139 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 2140 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
2141 break;
2142 case WLAN_CIPHER_SUITE_CCMP:
2143 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 2144 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
2145 break;
2146 default:
57d6e91a 2147 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
2148 return -EINVAL;
2149 }
118eb304 2150 err = send_key_to_dongle(ifp, &key);
f09d0c02 2151 if (err)
57d6e91a 2152 brcmf_err("wsec_key error (%d)\n", err);
5b435de0
AS
2153 }
2154 return err;
2155}
2156
2157static s32
2158brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
2159 u8 key_idx, bool pairwise, const u8 *mac_addr,
2160 struct key_params *params)
2161{
0abb5f21 2162 struct brcmf_if *ifp = netdev_priv(ndev);
118eb304 2163 struct brcmf_wsec_key *key;
5b435de0
AS
2164 s32 val;
2165 s32 wsec;
2166 s32 err = 0;
2167 u8 keybuf[8];
2168
d96b801f 2169 brcmf_dbg(TRACE, "Enter\n");
16886735 2170 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 2171 if (!check_vif_up(ifp->vif))
5b435de0
AS
2172 return -EIO;
2173
118eb304
HM
2174 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2175 /* we ignore this key index in this case */
2176 brcmf_err("invalid key index (%d)\n", key_idx);
2177 return -EINVAL;
2178 }
2179
787eb033
DK
2180 if (mac_addr &&
2181 (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2182 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
d96b801f 2183 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2184 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
2185 }
5b435de0 2186
118eb304
HM
2187 key = &ifp->vif->profile.key[key_idx];
2188 memset(key, 0, sizeof(*key));
5b435de0 2189
118eb304
HM
2190 if (params->key_len > sizeof(key->data)) {
2191 brcmf_err("Too long key length (%u)\n", params->key_len);
5b435de0
AS
2192 err = -EINVAL;
2193 goto done;
2194 }
118eb304
HM
2195 key->len = params->key_len;
2196 key->index = key_idx;
5b435de0 2197
118eb304
HM
2198 memcpy(key->data, params->key, key->len);
2199
2200 key->flags = BRCMF_PRIMARY_KEY;
5b435de0
AS
2201 switch (params->cipher) {
2202 case WLAN_CIPHER_SUITE_WEP40:
118eb304 2203 key->algo = CRYPTO_ALGO_WEP1;
f09d0c02 2204 val = WEP_ENABLED;
16886735 2205 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2206 break;
2207 case WLAN_CIPHER_SUITE_WEP104:
118eb304 2208 key->algo = CRYPTO_ALGO_WEP128;
f09d0c02 2209 val = WEP_ENABLED;
16886735 2210 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
2211 break;
2212 case WLAN_CIPHER_SUITE_TKIP:
967fe2c8 2213 if (!brcmf_is_apmode(ifp->vif)) {
992f6068 2214 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
118eb304
HM
2215 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2216 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2217 memcpy(&key->data[16], keybuf, sizeof(keybuf));
1a873342 2218 }
118eb304 2219 key->algo = CRYPTO_ALGO_TKIP;
f09d0c02 2220 val = TKIP_ENABLED;
16886735 2221 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
2222 break;
2223 case WLAN_CIPHER_SUITE_AES_CMAC:
118eb304 2224 key->algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 2225 val = AES_ENABLED;
16886735 2226 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
2227 break;
2228 case WLAN_CIPHER_SUITE_CCMP:
118eb304 2229 key->algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 2230 val = AES_ENABLED;
16886735 2231 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
2232 break;
2233 default:
57d6e91a 2234 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
2235 err = -EINVAL;
2236 goto done;
2237 }
2238
118eb304 2239 err = send_key_to_dongle(ifp, key);
5b435de0
AS
2240 if (err)
2241 goto done;
2242
0abb5f21 2243 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2244 if (err) {
57d6e91a 2245 brcmf_err("get wsec error (%d)\n", err);
5b435de0
AS
2246 goto done;
2247 }
5b435de0 2248 wsec |= val;
0abb5f21 2249 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
5b435de0 2250 if (err) {
57d6e91a 2251 brcmf_err("set wsec error (%d)\n", err);
5b435de0
AS
2252 goto done;
2253 }
2254
5b435de0 2255done:
d96b801f 2256 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2257 return err;
2258}
2259
2260static s32
2261brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2262 u8 key_idx, bool pairwise, const u8 *mac_addr)
2263{
0abb5f21 2264 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2265 struct brcmf_wsec_key key;
2266 s32 err = 0;
5b435de0 2267
d96b801f 2268 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2269 if (!check_vif_up(ifp->vif))
5b435de0
AS
2270 return -EIO;
2271
118eb304 2272 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
256c374f 2273 /* we ignore this key index in this case */
256c374f
HM
2274 return -EINVAL;
2275 }
2276
5b435de0
AS
2277 memset(&key, 0, sizeof(key));
2278
2279 key.index = (u32) key_idx;
2280 key.flags = BRCMF_PRIMARY_KEY;
2281 key.algo = CRYPTO_ALGO_OFF;
2282
16886735 2283 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
5b435de0
AS
2284
2285 /* Set the new key/index */
118eb304 2286 err = send_key_to_dongle(ifp, &key);
5b435de0 2287
d96b801f 2288 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2289 return err;
2290}
2291
2292static s32
2293brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2294 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2295 void (*callback) (void *cookie, struct key_params * params))
2296{
2297 struct key_params params;
0abb5f21
AS
2298 struct brcmf_if *ifp = netdev_priv(ndev);
2299 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2300 struct brcmf_cfg80211_security *sec;
2301 s32 wsec;
2302 s32 err = 0;
2303
d96b801f 2304 brcmf_dbg(TRACE, "Enter\n");
16886735 2305 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 2306 if (!check_vif_up(ifp->vif))
5b435de0
AS
2307 return -EIO;
2308
2309 memset(&params, 0, sizeof(params));
2310
0abb5f21 2311 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2312 if (err) {
57d6e91a 2313 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
5b435de0
AS
2314 /* Ignore this error, may happen during DISASSOC */
2315 err = -EAGAIN;
2316 goto done;
2317 }
c5bf53a8 2318 if (wsec & WEP_ENABLED) {
06bb123e 2319 sec = &profile->sec;
5b435de0
AS
2320 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2321 params.cipher = WLAN_CIPHER_SUITE_WEP40;
16886735 2322 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2323 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2324 params.cipher = WLAN_CIPHER_SUITE_WEP104;
16886735 2325 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0 2326 }
c5bf53a8 2327 } else if (wsec & TKIP_ENABLED) {
5b435de0 2328 params.cipher = WLAN_CIPHER_SUITE_TKIP;
16886735 2329 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
c5bf53a8 2330 } else if (wsec & AES_ENABLED) {
5b435de0 2331 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
16886735 2332 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
c5bf53a8 2333 } else {
57d6e91a 2334 brcmf_err("Invalid algo (0x%x)\n", wsec);
5b435de0
AS
2335 err = -EINVAL;
2336 goto done;
2337 }
2338 callback(cookie, &params);
2339
2340done:
d96b801f 2341 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2342 return err;
2343}
2344
2345static s32
2346brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2347 struct net_device *ndev, u8 key_idx)
2348{
647c9ae0 2349 brcmf_dbg(INFO, "Not supported\n");
5b435de0
AS
2350
2351 return -EOPNOTSUPP;
2352}
2353
118eb304
HM
2354static void
2355brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2356{
2357 s32 err;
2358 u8 key_idx;
2359 struct brcmf_wsec_key *key;
2360 s32 wsec;
2361
2362 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2363 key = &ifp->vif->profile.key[key_idx];
2364 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2365 (key->algo == CRYPTO_ALGO_WEP128))
2366 break;
2367 }
2368 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2369 return;
2370
2371 err = send_key_to_dongle(ifp, key);
2372 if (err) {
2373 brcmf_err("Setting WEP key failed (%d)\n", err);
2374 return;
2375 }
2376 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2377 if (err) {
2378 brcmf_err("get wsec error (%d)\n", err);
2379 return;
2380 }
2381 wsec |= WEP_ENABLED;
2382 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2383 if (err)
2384 brcmf_err("set wsec error (%d)\n", err);
2385}
2386
1f0dc59a
AS
2387static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2388{
2389 struct nl80211_sta_flag_update *sfu;
2390
2391 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2392 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2393 sfu = &si->sta_flags;
2394 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2395 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2396 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2397 BIT(NL80211_STA_FLAG_AUTHORIZED);
2398 if (fw_sta_flags & BRCMF_STA_WME)
2399 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2400 if (fw_sta_flags & BRCMF_STA_AUTHE)
2401 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2402 if (fw_sta_flags & BRCMF_STA_ASSOC)
2403 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2404 if (fw_sta_flags & BRCMF_STA_AUTHO)
2405 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2406}
2407
2408static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2409{
2410 struct {
2411 __le32 len;
2412 struct brcmf_bss_info_le bss_le;
2413 } *buf;
2414 u16 capability;
2415 int err;
2416
2417 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2418 if (!buf)
2419 return;
2420
2421 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2422 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2423 WL_BSS_INFO_MAX);
2424 if (err) {
2425 brcmf_err("Failed to get bss info (%d)\n", err);
2426 return;
2427 }
2428 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2429 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2430 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2431 capability = le16_to_cpu(buf->bss_le.capability);
2432 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2433 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2434 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2435 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2436 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2437 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2438}
2439
3f5893d1
HM
2440static s32
2441brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2442 struct station_info *sinfo)
2443{
2444 struct brcmf_scb_val_le scbval;
2445 struct brcmf_pktcnt_le pktcnt;
2446 s32 err;
2447 u32 rate;
2448 u32 rssi;
2449
2450 /* Get the current tx rate */
2451 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2452 if (err < 0) {
2453 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2454 return err;
2455 }
2456 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2457 sinfo->txrate.legacy = rate * 5;
2458
2459 memset(&scbval, 0, sizeof(scbval));
2460 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2461 sizeof(scbval));
2462 if (err) {
2463 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2464 return err;
2465 }
2466 rssi = le32_to_cpu(scbval.val);
2467 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2468 sinfo->signal = rssi;
2469
2470 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2471 sizeof(pktcnt));
2472 if (err) {
2473 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2474 return err;
2475 }
2476 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2477 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2478 BIT(NL80211_STA_INFO_TX_PACKETS) |
2479 BIT(NL80211_STA_INFO_TX_FAILED);
2480 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2481 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2482 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2483 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2484
2485 return 0;
2486}
2487
5b435de0
AS
2488static s32
2489brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
3b3a0162 2490 const u8 *mac, struct station_info *sinfo)
5b435de0 2491{
0abb5f21 2492 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2493 s32 err = 0;
81f5dcb8 2494 struct brcmf_sta_info_le sta_info_le;
1f0dc59a
AS
2495 u32 sta_flags;
2496 u32 is_tdls_peer;
cae355dc
HM
2497 s32 total_rssi;
2498 s32 count_rssi;
2499 u32 i;
5b435de0 2500
d96b801f 2501 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
ce81e317 2502 if (!check_vif_up(ifp->vif))
5b435de0
AS
2503 return -EIO;
2504
3f5893d1
HM
2505 if (brcmf_is_ibssmode(ifp->vif))
2506 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2507
1f0dc59a
AS
2508 memset(&sta_info_le, 0, sizeof(sta_info_le));
2509 memcpy(&sta_info_le, mac, ETH_ALEN);
2510 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2511 &sta_info_le,
2512 sizeof(sta_info_le));
2513 is_tdls_peer = !err;
2514 if (err) {
0abb5f21 2515 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
ac24be6f 2516 &sta_info_le,
81f5dcb8 2517 sizeof(sta_info_le));
1a873342 2518 if (err < 0) {
57d6e91a 2519 brcmf_err("GET STA INFO failed, %d\n", err);
1a873342
HM
2520 goto done;
2521 }
1f0dc59a
AS
2522 }
2523 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2524 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2525 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2526 sta_flags = le32_to_cpu(sta_info_le.flags);
2527 brcmf_convert_sta_flags(sta_flags, sinfo);
2528 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2529 if (is_tdls_peer)
2530 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2531 else
2532 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2533 if (sta_flags & BRCMF_STA_ASSOC) {
2534 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2535 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2536 brcmf_fill_bss_param(ifp, sinfo);
2537 }
2538 if (sta_flags & BRCMF_STA_SCBSTATS) {
2539 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2540 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2541 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2542 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2543 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2544 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2545 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2546 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2547 if (sinfo->tx_packets) {
319090bf 2548 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
124d5172
HM
2549 sinfo->txrate.legacy =
2550 le32_to_cpu(sta_info_le.tx_rate) / 100;
7f6c562d 2551 }
1f0dc59a
AS
2552 if (sinfo->rx_packets) {
2553 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
124d5172
HM
2554 sinfo->rxrate.legacy =
2555 le32_to_cpu(sta_info_le.rx_rate) / 100;
1a873342 2556 }
1f0dc59a
AS
2557 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2558 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2559 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2560 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2561 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2562 }
cae355dc
HM
2563 total_rssi = 0;
2564 count_rssi = 0;
2565 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2566 if (sta_info_le.rssi[i]) {
2567 sinfo->chain_signal_avg[count_rssi] =
2568 sta_info_le.rssi[i];
2569 sinfo->chain_signal[count_rssi] =
2570 sta_info_le.rssi[i];
2571 total_rssi += sta_info_le.rssi[i];
2572 count_rssi++;
2573 }
2574 }
2575 if (count_rssi) {
2576 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2577 sinfo->chains = count_rssi;
2578
2579 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2580 total_rssi /= count_rssi;
2581 sinfo->signal = total_rssi;
2582 }
1f0dc59a 2583 }
5b435de0 2584done:
d96b801f 2585 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2586 return err;
2587}
2588
bf2a7e04
HM
2589static int
2590brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2591 int idx, u8 *mac, struct station_info *sinfo)
2592{
2593 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2594 struct brcmf_if *ifp = netdev_priv(ndev);
2595 s32 err;
2596
2597 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2598
2599 if (idx == 0) {
2600 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2601 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2602 &cfg->assoclist,
2603 sizeof(cfg->assoclist));
2604 if (err) {
2605 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2606 err);
2607 cfg->assoclist.count = 0;
2608 return -EOPNOTSUPP;
2609 }
2610 }
2611 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2612 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2613 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2614 }
2615 return -ENOENT;
2616}
2617
5b435de0
AS
2618static s32
2619brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2620 bool enabled, s32 timeout)
2621{
2622 s32 pm;
2623 s32 err = 0;
27a68fe3 2624 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2625 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2626
d96b801f 2627 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2628
2629 /*
2630 * Powersave enable/disable request is coming from the
2631 * cfg80211 even before the interface is up. In that
2632 * scenario, driver will be storing the power save
27a68fe3 2633 * preference in cfg struct to apply this to
5b435de0
AS
2634 * FW later while initializing the dongle
2635 */
27a68fe3 2636 cfg->pwr_save = enabled;
ce81e317 2637 if (!check_vif_up(ifp->vif)) {
5b435de0 2638
647c9ae0 2639 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
5b435de0
AS
2640 goto done;
2641 }
2642
2643 pm = enabled ? PM_FAST : PM_OFF;
102fd0d6
HM
2644 /* Do not enable the power save after assoc if it is a p2p interface */
2645 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2646 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2647 pm = PM_OFF;
2648 }
647c9ae0 2649 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2650
c1179033 2651 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2652 if (err) {
2653 if (err == -ENODEV)
57d6e91a 2654 brcmf_err("net_device is not ready yet\n");
5b435de0 2655 else
57d6e91a 2656 brcmf_err("error (%d)\n", err);
5b435de0
AS
2657 }
2658done:
d96b801f 2659 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2660 return err;
2661}
2662
27a68fe3 2663static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2664 struct brcmf_bss_info_le *bi)
5b435de0 2665{
27a68fe3 2666 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2667 struct ieee80211_channel *notify_channel;
2668 struct cfg80211_bss *bss;
2669 struct ieee80211_supported_band *band;
83cf17aa 2670 struct brcmu_chan ch;
5b435de0
AS
2671 u16 channel;
2672 u32 freq;
5b435de0
AS
2673 u16 notify_capability;
2674 u16 notify_interval;
2675 u8 *notify_ie;
2676 size_t notify_ielen;
2677 s32 notify_signal;
2678
2679 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2680 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2681 return 0;
2682 }
2683
83cf17aa
FL
2684 if (!bi->ctl_ch) {
2685 ch.chspec = le16_to_cpu(bi->chanspec);
2686 cfg->d11inf.decchspec(&ch);
2687 bi->ctl_ch = ch.chnum;
2688 }
2689 channel = bi->ctl_ch;
5b435de0
AS
2690
2691 if (channel <= CH_MAX_2G_CHANNEL)
2692 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2693 else
2694 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2695
2696 freq = ieee80211_channel_to_frequency(channel, band->band);
2697 notify_channel = ieee80211_get_channel(wiphy, freq);
2698
5b435de0
AS
2699 notify_capability = le16_to_cpu(bi->capability);
2700 notify_interval = le16_to_cpu(bi->beacon_period);
2701 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2702 notify_ielen = le32_to_cpu(bi->ie_length);
2703 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2704
16886735
AS
2705 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2706 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2707 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2708 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2709 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0 2710
5bc8c1f2
JB
2711 bss = cfg80211_inform_bss(wiphy, notify_channel,
2712 CFG80211_BSS_FTYPE_UNKNOWN,
2713 (const u8 *)bi->BSSID,
2714 0, notify_capability,
2715 notify_interval, notify_ie,
2716 notify_ielen, notify_signal,
2717 GFP_KERNEL);
5b435de0 2718
e78946e1
FL
2719 if (!bss)
2720 return -ENOMEM;
2721
5b112d3d 2722 cfg80211_put_bss(wiphy, bss);
5b435de0 2723
12f32370 2724 return 0;
5b435de0
AS
2725}
2726
6f09be0a
RV
2727static struct brcmf_bss_info_le *
2728next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2729{
2730 if (bss == NULL)
2731 return list->bss_info_le;
2732 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2733 le32_to_cpu(bss->length));
2734}
2735
27a68fe3 2736static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2737{
2738 struct brcmf_scan_results *bss_list;
d34bf64f 2739 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2740 s32 err = 0;
2741 int i;
2742
ef8596e1 2743 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
0ecd8164
AS
2744 if (bss_list->count != 0 &&
2745 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2746 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2747 bss_list->version);
5b435de0
AS
2748 return -EOPNOTSUPP;
2749 }
4e8a008e 2750 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2751 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2752 bi = next_bss_le(bss_list, bi);
27a68fe3 2753 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2754 if (err)
2755 break;
2756 }
2757 return err;
2758}
2759
b0a79088
HM
2760static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2761 struct net_device *ndev, const u8 *bssid)
5b435de0 2762{
27a68fe3 2763 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2764 struct ieee80211_channel *notify_channel;
d34bf64f 2765 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2766 struct ieee80211_supported_band *band;
e78946e1 2767 struct cfg80211_bss *bss;
83cf17aa 2768 struct brcmu_chan ch;
5b435de0
AS
2769 u8 *buf = NULL;
2770 s32 err = 0;
5b435de0 2771 u32 freq;
5b435de0
AS
2772 u16 notify_capability;
2773 u16 notify_interval;
2774 u8 *notify_ie;
2775 size_t notify_ielen;
2776 s32 notify_signal;
2777
d96b801f 2778 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2779
2780 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2781 if (buf == NULL) {
2782 err = -ENOMEM;
2783 goto CleanUp;
2784 }
2785
2786 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2787
ac24be6f
AS
2788 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2789 buf, WL_BSS_INFO_MAX);
5b435de0 2790 if (err) {
57d6e91a 2791 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2792 goto CleanUp;
2793 }
2794
d34bf64f 2795 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0 2796
83cf17aa
FL
2797 ch.chspec = le16_to_cpu(bi->chanspec);
2798 cfg->d11inf.decchspec(&ch);
5b435de0 2799
83cf17aa 2800 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
2801 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2802 else
2803 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2804
83cf17aa 2805 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
b0a79088 2806 cfg->channel = freq;
5b435de0
AS
2807 notify_channel = ieee80211_get_channel(wiphy, freq);
2808
5b435de0
AS
2809 notify_capability = le16_to_cpu(bi->capability);
2810 notify_interval = le16_to_cpu(bi->beacon_period);
2811 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2812 notify_ielen = le32_to_cpu(bi->ie_length);
2813 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2814
83cf17aa 2815 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
16886735
AS
2816 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2817 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2818 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2819
5bc8c1f2
JB
2820 bss = cfg80211_inform_bss(wiphy, notify_channel,
2821 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2822 notify_capability, notify_interval,
2823 notify_ie, notify_ielen, notify_signal,
2824 GFP_KERNEL);
5b435de0 2825
e78946e1
FL
2826 if (!bss) {
2827 err = -ENOMEM;
2828 goto CleanUp;
2829 }
2830
5b112d3d 2831 cfg80211_put_bss(wiphy, bss);
e78946e1 2832
5b435de0
AS
2833CleanUp:
2834
2835 kfree(buf);
2836
d96b801f 2837 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2838
2839 return err;
2840}
2841
89286dc9
HM
2842static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2843 struct brcmf_if *ifp)
1a873342 2844{
d34bf64f 2845 struct brcmf_bss_info_le *bi;
4b5800fe 2846 const struct brcmf_tlv *tim;
5b435de0
AS
2847 u16 beacon_interval;
2848 u8 dtim_period;
2849 size_t ie_len;
2850 u8 *ie;
2851 s32 err = 0;
2852
d96b801f 2853 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2854 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2855 return err;
2856
27a68fe3 2857 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2858 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2859 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2860 if (err) {
57d6e91a 2861 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2862 goto update_bss_info_out;
2863 }
2864
27a68fe3
AS
2865 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2866 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2867 if (err)
2868 goto update_bss_info_out;
2869
2870 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2871 ie_len = le32_to_cpu(bi->ie_length);
2872 beacon_interval = le16_to_cpu(bi->beacon_period);
2873
f8e4b412 2874 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2875 if (tim)
2876 dtim_period = tim->data[1];
2877 else {
2878 /*
2879 * active scan was done so we could not get dtim
2880 * information out of probe response.
2881 * so we speficially query dtim information to dongle.
2882 */
2883 u32 var;
ac24be6f 2884 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2885 if (err) {
57d6e91a 2886 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2887 goto update_bss_info_out;
2888 }
2889 dtim_period = (u8)var;
2890 }
2891
5b435de0 2892update_bss_info_out:
d96b801f 2893 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2894 return err;
2895}
2896
18e2f61d 2897void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2898{
27a68fe3 2899 struct escan_info *escan = &cfg->escan_info;
5b435de0 2900
c1179033 2901 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2902 if (cfg->scan_request) {
108a4bee 2903 escan->escan_state = WL_ESCAN_STATE_IDLE;
a0f472ac 2904 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
5b435de0 2905 }
c1179033
AS
2906 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2907 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2908}
2909
e756af5b
HM
2910static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2911{
27a68fe3
AS
2912 struct brcmf_cfg80211_info *cfg =
2913 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2914 escan_timeout_work);
2915
ef8596e1 2916 brcmf_inform_bss(cfg);
a0f472ac 2917 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
e756af5b
HM
2918}
2919
2920static void brcmf_escan_timeout(unsigned long data)
2921{
27a68fe3
AS
2922 struct brcmf_cfg80211_info *cfg =
2923 (struct brcmf_cfg80211_info *)data;
e756af5b 2924
27a68fe3 2925 if (cfg->scan_request) {
57d6e91a 2926 brcmf_err("timer expired\n");
f0799895 2927 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2928 }
2929}
2930
2931static s32
83cf17aa
FL
2932brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2933 struct brcmf_bss_info_le *bss,
e756af5b
HM
2934 struct brcmf_bss_info_le *bss_info_le)
2935{
83cf17aa
FL
2936 struct brcmu_chan ch_bss, ch_bss_info_le;
2937
2938 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2939 cfg->d11inf.decchspec(&ch_bss);
2940 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2941 cfg->d11inf.decchspec(&ch_bss_info_le);
2942
e756af5b 2943 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
83cf17aa 2944 ch_bss.band == ch_bss_info_le.band &&
e756af5b
HM
2945 bss_info_le->SSID_len == bss->SSID_len &&
2946 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
6f5838a4
AS
2947 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2948 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2949 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2950 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2951
e756af5b
HM
2952 /* preserve max RSSI if the measurements are
2953 * both on-channel or both off-channel
2954 */
029591f3 2955 if (bss_info_rssi > bss_rssi)
e756af5b 2956 bss->RSSI = bss_info_le->RSSI;
6f5838a4
AS
2957 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2958 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
e756af5b
HM
2959 /* preserve the on-channel rssi measurement
2960 * if the new measurement is off channel
2961 */
2962 bss->RSSI = bss_info_le->RSSI;
6f5838a4 2963 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
e756af5b
HM
2964 }
2965 return 1;
2966 }
2967 return 0;
2968}
2969
2970static s32
1993732e 2971brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2972 const struct brcmf_event_msg *e, void *data)
2973{
1993732e 2974 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e756af5b 2975 s32 status;
e756af5b
HM
2976 struct brcmf_escan_result_le *escan_result_le;
2977 struct brcmf_bss_info_le *bss_info_le;
2978 struct brcmf_bss_info_le *bss = NULL;
2979 u32 bi_length;
2980 struct brcmf_scan_results *list;
2981 u32 i;
97ed15c7 2982 bool aborted;
e756af5b 2983
5c36b99a 2984 status = e->status;
e756af5b 2985
a0f472ac 2986 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
37a869ec 2987 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
e756af5b
HM
2988 return -EPERM;
2989 }
2990
2991 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2992 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2993 escan_result_le = (struct brcmf_escan_result_le *) data;
2994 if (!escan_result_le) {
57d6e91a 2995 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2996 goto exit;
2997 }
e756af5b 2998 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2999 brcmf_err("Invalid bss_count %d: ignoring\n",
3000 escan_result_le->bss_count);
e756af5b
HM
3001 goto exit;
3002 }
3003 bss_info_le = &escan_result_le->bss_info_le;
3004
6eda4e2c
HM
3005 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3006 goto exit;
3007
3008 if (!cfg->scan_request) {
3009 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3010 goto exit;
3011 }
3012
e756af5b
HM
3013 bi_length = le32_to_cpu(bss_info_le->length);
3014 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3015 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
3016 brcmf_err("Invalid bss_info length %d: ignoring\n",
3017 bi_length);
e756af5b
HM
3018 goto exit;
3019 }
3020
27a68fe3 3021 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
3022 BIT(NL80211_IFTYPE_ADHOC))) {
3023 if (le16_to_cpu(bss_info_le->capability) &
3024 WLAN_CAPABILITY_IBSS) {
57d6e91a 3025 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
3026 goto exit;
3027 }
3028 }
3029
3030 list = (struct brcmf_scan_results *)
27a68fe3 3031 cfg->escan_info.escan_buf;
d5367334 3032 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 3033 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
3034 goto exit;
3035 }
3036
3037 for (i = 0; i < list->count; i++) {
3038 bss = bss ? (struct brcmf_bss_info_le *)
3039 ((unsigned char *)bss +
3040 le32_to_cpu(bss->length)) : list->bss_info_le;
83cf17aa
FL
3041 if (brcmf_compare_update_same_bss(cfg, bss,
3042 bss_info_le))
e756af5b
HM
3043 goto exit;
3044 }
d5367334
HM
3045 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3046 bi_length);
e756af5b
HM
3047 list->version = le32_to_cpu(bss_info_le->version);
3048 list->buflen += bi_length;
3049 list->count++;
3050 } else {
27a68fe3 3051 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
3052 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3053 goto exit;
27a68fe3 3054 if (cfg->scan_request) {
27a68fe3 3055 brcmf_inform_bss(cfg);
97ed15c7 3056 aborted = status != BRCMF_E_STATUS_SUCCESS;
ef8596e1 3057 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
e756af5b 3058 } else
6eda4e2c
HM
3059 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3060 status);
e756af5b
HM
3061 }
3062exit:
12f32370 3063 return 0;
e756af5b
HM
3064}
3065
27a68fe3 3066static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 3067{
5c36b99a
AS
3068 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3069 brcmf_cfg80211_escan_handler);
f0799895
HM
3070 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3071 /* Init scan_timeout timer */
3072 init_timer(&cfg->escan_timeout);
3073 cfg->escan_timeout.data = (unsigned long) cfg;
3074 cfg->escan_timeout.function = brcmf_escan_timeout;
3075 INIT_WORK(&cfg->escan_timeout_work,
3076 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
3077}
3078
5419f7f1
HM
3079/* PFN result doesn't have all the info which are required by the supplicant
3080 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3081 * via wl_inform_single_bss in the required format. Escan does require the
3082 * scan request in the form of cfg80211_scan_request. For timebeing, create
3083 * cfg80211_scan_request one out of the received PNO event.
3084 */
3021ad9a 3085static s32
5419f7f1
HM
3086brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3087 const struct brcmf_event_msg *e, void *data)
3021ad9a
HM
3088{
3089 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5419f7f1
HM
3090 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3091 struct cfg80211_scan_request *request = NULL;
3092 struct cfg80211_ssid *ssid = NULL;
3093 struct ieee80211_channel *channel = NULL;
3094 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3095 int err = 0;
3096 int channel_req = 0;
3097 int band = 0;
3021ad9a 3098 struct brcmf_pno_scanresults_le *pfn_result;
5419f7f1
HM
3099 u32 result_count;
3100 u32 status;
3021ad9a
HM
3101
3102 brcmf_dbg(SCAN, "Enter\n");
3103
0aedbcaf
HM
3104 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3105 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3106 return 0;
3107 }
3108
3021ad9a 3109 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
5419f7f1 3110 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3021ad9a
HM
3111 return 0;
3112 }
3113
5419f7f1
HM
3114 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3115 result_count = le32_to_cpu(pfn_result->count);
3116 status = le32_to_cpu(pfn_result->status);
3021ad9a 3117
5419f7f1
HM
3118 /* PFN event is limited to fit 512 bytes so we may get
3119 * multiple NET_FOUND events. For now place a warning here.
3120 */
3121 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3122 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3123 if (result_count > 0) {
3124 int i;
3021ad9a 3125
5419f7f1
HM
3126 request = kzalloc(sizeof(*request), GFP_KERNEL);
3127 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3128 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3129 if (!request || !ssid || !channel) {
3130 err = -ENOMEM;
3131 goto out_err;
3132 }
3021ad9a 3133
5419f7f1
HM
3134 request->wiphy = wiphy;
3135 data += sizeof(struct brcmf_pno_scanresults_le);
3136 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3021ad9a 3137
5419f7f1
HM
3138 for (i = 0; i < result_count; i++) {
3139 netinfo = &netinfo_start[i];
3140 if (!netinfo) {
3141 brcmf_err("Invalid netinfo ptr. index: %d\n",
3142 i);
3143 err = -EINVAL;
3144 goto out_err;
3145 }
aeb64225 3146
5419f7f1
HM
3147 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3148 netinfo->SSID, netinfo->channel);
3149 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3150 ssid[i].ssid_len = netinfo->SSID_len;
3151 request->n_ssids++;
aeb64225 3152
5419f7f1
HM
3153 channel_req = netinfo->channel;
3154 if (channel_req <= CH_MAX_2G_CHANNEL)
3155 band = NL80211_BAND_2GHZ;
3156 else
3157 band = NL80211_BAND_5GHZ;
3158 channel[i].center_freq =
3159 ieee80211_channel_to_frequency(channel_req,
3160 band);
3161 channel[i].band = band;
3162 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3163 request->channels[i] = &channel[i];
3164 request->n_channels++;
3165 }
aeb64225 3166
5419f7f1
HM
3167 /* assign parsed ssid array */
3168 if (request->n_ssids)
3169 request->ssids = &ssid[0];
aeb64225 3170
5419f7f1
HM
3171 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3172 /* Abort any on-going scan */
3173 brcmf_abort_scanning(cfg);
aeb64225 3174 }
5419f7f1
HM
3175
3176 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3177 cfg->escan_info.run = brcmf_run_escan;
3178 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3179 if (err) {
3180 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3181 goto out_err;
3021ad9a 3182 }
5419f7f1
HM
3183 cfg->sched_escan = true;
3184 cfg->scan_request = request;
aeb64225 3185 } else {
5419f7f1
HM
3186 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3187 goto out_err;
aeb64225 3188 }
aeb64225 3189
5419f7f1
HM
3190 kfree(ssid);
3191 kfree(channel);
3192 kfree(request);
3193 return 0;
aeb64225 3194
5419f7f1
HM
3195out_err:
3196 kfree(ssid);
3197 kfree(channel);
3198 kfree(request);
3199 cfg80211_sched_scan_stopped(wiphy);
3200 return err;
aeb64225
HM
3201}
3202
5419f7f1 3203static int brcmf_dev_pno_clean(struct net_device *ndev)
5b435de0 3204{
5419f7f1 3205 int ret;
4eb3af7c 3206
5419f7f1
HM
3207 /* Disable pfn */
3208 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3209 if (ret == 0) {
3210 /* clear pfn */
3211 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3212 NULL, 0);
3213 }
3214 if (ret < 0)
3215 brcmf_err("failed code %d\n", ret);
5b435de0 3216
5419f7f1
HM
3217 return ret;
3218}
3219
3220static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3221 struct cfg80211_sched_scan_request *request)
3222{
3223 struct brcmf_pno_param_le pfn_param;
3224 struct brcmf_pno_macaddr_le pfn_mac;
3225 s32 err;
3226 u8 *mac_mask;
3227 int i;
3228
3229 memset(&pfn_param, 0, sizeof(pfn_param));
3230 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3231
3232 /* set extra pno params */
3233 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3234 pfn_param.repeat = BRCMF_PNO_REPEAT;
3235 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3236
3237 /* set up pno scan fr */
3238 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3239
3240 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3241 sizeof(pfn_param));
3242 if (err) {
3243 brcmf_err("pfn_set failed, err=%d\n", err);
3244 return err;
3245 }
3246
3247 /* Find out if mac randomization should be turned on */
3248 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3249 return 0;
3250
3251 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3252 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3253
3254 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3255 mac_mask = request->mac_addr_mask;
3256 for (i = 0; i < ETH_ALEN; i++) {
3257 pfn_mac.mac[i] &= mac_mask[i];
3258 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3259 }
3260 /* Clear multi bit */
3261 pfn_mac.mac[0] &= 0xFE;
3262 /* Set locally administered */
3263 pfn_mac.mac[0] |= 0x02;
3264
3265 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3266 sizeof(pfn_mac));
3267 if (err)
3268 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3269
3270 return err;
3271}
3272
3273static int
3274brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3275 struct net_device *ndev,
3276 struct cfg80211_sched_scan_request *request)
3277{
3278 struct brcmf_if *ifp = netdev_priv(ndev);
3279 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3280 struct brcmf_pno_net_param_le pfn;
3281 int i;
3282 int ret = 0;
3283
3284 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3285 request->n_match_sets, request->n_ssids);
3286 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3287 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3288 return -EAGAIN;
3289 }
3290 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3291 brcmf_err("Scanning suppressed: status (%lu)\n",
3292 cfg->scan_status);
3293 return -EAGAIN;
3294 }
3295
3296 if (!request->n_ssids || !request->n_match_sets) {
3297 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3298 request->n_ssids);
3299 return -EINVAL;
3300 }
3301
3302 if (request->n_ssids > 0) {
3303 for (i = 0; i < request->n_ssids; i++) {
3304 /* Active scan req for ssids */
3305 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3306 request->ssids[i].ssid);
3307
3308 /* match_set ssids is a supert set of n_ssid list,
3309 * so we need not add these set separately.
3310 */
3311 }
3312 }
3313
3314 if (request->n_match_sets > 0) {
3315 /* clean up everything */
3316 ret = brcmf_dev_pno_clean(ndev);
3317 if (ret < 0) {
3318 brcmf_err("failed error=%d\n", ret);
3319 return ret;
3320 }
3321
3322 /* configure pno */
3323 if (brcmf_dev_pno_config(ifp, request))
3324 return -EINVAL;
3325
3326 /* configure each match set */
3327 for (i = 0; i < request->n_match_sets; i++) {
3328 struct cfg80211_ssid *ssid;
3329 u32 ssid_len;
3330
3331 ssid = &request->match_sets[i].ssid;
3332 ssid_len = ssid->ssid_len;
3333
3334 if (!ssid_len) {
3335 brcmf_err("skip broadcast ssid\n");
3336 continue;
3337 }
3338 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3339 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3340 pfn.wsec = cpu_to_le32(0);
3341 pfn.infra = cpu_to_le32(1);
3342 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3343 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3344 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3345 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3346 sizeof(pfn));
3347 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3348 ret == 0 ? "set" : "failed", ssid->ssid);
3349 }
3350 /* Enable the PNO */
3351 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3352 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3353 return -EINVAL;
3354 }
3355 } else {
3356 return -EINVAL;
3357 }
3358
3359 return 0;
3360}
3361
3362static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3363 struct net_device *ndev)
3364{
3365 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3366
3367 brcmf_dbg(SCAN, "enter\n");
3368 brcmf_dev_pno_clean(ndev);
3369 if (cfg->sched_escan)
3370 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3371 return 0;
3372}
3373
3374static __always_inline void brcmf_delay(u32 ms)
3375{
3376 if (ms < 1000 / HZ) {
3377 cond_resched();
3378 mdelay(ms);
3379 } else {
3380 msleep(ms);
3381 }
3382}
3383
3384static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3385 u8 *pattern, u32 patternsize, u8 *mask,
3386 u32 packet_offset)
3387{
3388 struct brcmf_fil_wowl_pattern_le *filter;
3389 u32 masksize;
3390 u32 patternoffset;
3391 u8 *buf;
3392 u32 bufsize;
3393 s32 ret;
3394
3395 masksize = (patternsize + 7) / 8;
3396 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3397
3398 bufsize = sizeof(*filter) + patternsize + masksize;
3399 buf = kzalloc(bufsize, GFP_KERNEL);
3400 if (!buf)
3401 return -ENOMEM;
3402 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3403
3404 memcpy(filter->cmd, cmd, 4);
3405 filter->masksize = cpu_to_le32(masksize);
3406 filter->offset = cpu_to_le32(packet_offset);
3407 filter->patternoffset = cpu_to_le32(patternoffset);
3408 filter->patternsize = cpu_to_le32(patternsize);
3409 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3410
3411 if ((mask) && (masksize))
3412 memcpy(buf + sizeof(*filter), mask, masksize);
3413 if ((pattern) && (patternsize))
3414 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3415
3416 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3417
3418 kfree(buf);
3419 return ret;
3420}
3421
3422static s32
3423brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3424 void *data)
3425{
3426 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3427 struct brcmf_pno_scanresults_le *pfn_result;
3428 struct brcmf_pno_net_info_le *netinfo;
3429
3430 brcmf_dbg(SCAN, "Enter\n");
3431
0aedbcaf
HM
3432 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3433 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3434 return 0;
3435 }
3436
5419f7f1
HM
3437 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3438
3439 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3440 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3441 return 0;
3442 }
3443
3444 if (le32_to_cpu(pfn_result->count) < 1) {
3445 brcmf_err("Invalid result count, expected 1 (%d)\n",
3446 le32_to_cpu(pfn_result->count));
3447 return -EINVAL;
3448 }
3449
3450 data += sizeof(struct brcmf_pno_scanresults_le);
3451 netinfo = (struct brcmf_pno_net_info_le *)data;
3452 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3453 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3454 cfg->wowl.nd->n_channels = 1;
3455 cfg->wowl.nd->channels[0] =
3456 ieee80211_channel_to_frequency(netinfo->channel,
3457 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3458 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3459 cfg->wowl.nd_info->n_matches = 1;
3460 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3461
3462 /* Inform (the resume task) that the net detect information was recvd */
3463 cfg->wowl.nd_data_completed = true;
3464 wake_up(&cfg->wowl.nd_data_wait);
3465
3466 return 0;
3467}
3468
3469#ifdef CONFIG_PM
3470
3471static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3472{
3473 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3474 struct brcmf_wowl_wakeind_le wake_ind_le;
3475 struct cfg80211_wowlan_wakeup wakeup_data;
3476 struct cfg80211_wowlan_wakeup *wakeup;
3477 u32 wakeind;
3478 s32 err;
3479 int timeout;
3480
3481 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3482 sizeof(wake_ind_le));
3483 if (err) {
3484 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3485 return;
3486 }
3487
3488 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3489 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
3490 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3491 BRCMF_WOWL_PFN_FOUND)) {
3492 wakeup = &wakeup_data;
3493 memset(&wakeup_data, 0, sizeof(wakeup_data));
3494 wakeup_data.pattern_idx = -1;
3495
3496 if (wakeind & BRCMF_WOWL_MAGIC) {
3497 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3498 wakeup_data.magic_pkt = true;
3499 }
3500 if (wakeind & BRCMF_WOWL_DIS) {
3501 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3502 wakeup_data.disconnect = true;
3503 }
3504 if (wakeind & BRCMF_WOWL_BCN) {
3505 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3506 wakeup_data.disconnect = true;
3507 }
3508 if (wakeind & BRCMF_WOWL_RETR) {
3509 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3510 wakeup_data.disconnect = true;
3511 }
3512 if (wakeind & BRCMF_WOWL_NET) {
3513 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3514 /* For now always map to pattern 0, no API to get
3515 * correct information available at the moment.
3516 */
3517 wakeup_data.pattern_idx = 0;
3518 }
3519 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3520 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3521 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3522 cfg->wowl.nd_data_completed,
3523 BRCMF_ND_INFO_TIMEOUT);
3524 if (!timeout)
3525 brcmf_err("No result for wowl net detect\n");
3526 else
3527 wakeup_data.net_detect = cfg->wowl.nd_info;
3528 }
5c22fb85
HM
3529 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3530 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3531 wakeup_data.gtk_rekey_failure = true;
3532 }
5419f7f1
HM
3533 } else {
3534 wakeup = NULL;
3535 }
3536 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3537}
3538
3539#else
3540
3541static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3542{
3543}
3544
3545#endif /* CONFIG_PM */
3546
3547static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3548{
3549 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3550 struct net_device *ndev = cfg_to_ndev(cfg);
3551 struct brcmf_if *ifp = netdev_priv(ndev);
3552
3553 brcmf_dbg(TRACE, "Enter\n");
3554
3555 if (cfg->wowl.active) {
3556 brcmf_report_wowl_wakeind(wiphy, ifp);
3557 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3558 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
73ef9e64
HM
3559 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3560 brcmf_configure_arp_nd_offload(ifp, true);
4eb3af7c 3561 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
3021ad9a
HM
3562 cfg->wowl.pre_pmmode);
3563 cfg->wowl.active = false;
3564 if (cfg->wowl.nd_enabled) {
3565 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3566 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3567 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3568 brcmf_notify_sched_scan_results);
3569 cfg->wowl.nd_enabled = false;
3570 }
4eb3af7c 3571 }
5b435de0
AS
3572 return 0;
3573}
3574
4eb3af7c
HM
3575static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3576 struct brcmf_if *ifp,
3577 struct cfg80211_wowlan *wowl)
3578{
3579 u32 wowl_config;
b9a82f89 3580 u32 i;
4eb3af7c
HM
3581
3582 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3583
73ef9e64
HM
3584 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3585 brcmf_configure_arp_nd_offload(ifp, false);
3021ad9a 3586 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
4eb3af7c
HM
3587 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3588
3589 wowl_config = 0;
3590 if (wowl->disconnect)
b9a82f89 3591 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
4eb3af7c 3592 if (wowl->magic_pkt)
b9a82f89
HM
3593 wowl_config |= BRCMF_WOWL_MAGIC;
3594 if ((wowl->patterns) && (wowl->n_patterns)) {
3595 wowl_config |= BRCMF_WOWL_NET;
3596 for (i = 0; i < wowl->n_patterns; i++) {
3597 brcmf_config_wowl_pattern(ifp, "add",
3598 (u8 *)wowl->patterns[i].pattern,
3599 wowl->patterns[i].pattern_len,
3600 (u8 *)wowl->patterns[i].mask,
3601 wowl->patterns[i].pkt_offset);
3602 }
3603 }
3021ad9a
HM
3604 if (wowl->nd_config) {
3605 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3606 wowl->nd_config);
3607 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3608
3609 cfg->wowl.nd_data_completed = false;
3610 cfg->wowl.nd_enabled = true;
3611 /* Now reroute the event for PFN to the wowl function. */
3612 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3613 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3614 brcmf_wowl_nd_results);
3615 }
5c22fb85
HM
3616 if (wowl->gtk_rekey_failure)
3617 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
3021ad9a
HM
3618 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3619 wowl_config |= BRCMF_WOWL_UNASSOC;
3620
aeb64225 3621 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
4eb3af7c
HM
3622 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3623 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3624 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
3021ad9a 3625 cfg->wowl.active = true;
4eb3af7c
HM
3626}
3627
5b435de0 3628static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
4eb3af7c 3629 struct cfg80211_wowlan *wowl)
5b435de0 3630{
27a68fe3
AS
3631 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3632 struct net_device *ndev = cfg_to_ndev(cfg);
4eb3af7c 3633 struct brcmf_if *ifp = netdev_priv(ndev);
7d641072 3634 struct brcmf_cfg80211_vif *vif;
5b435de0 3635
d96b801f 3636 brcmf_dbg(TRACE, "Enter\n");
5b435de0 3637
4eb3af7c 3638 /* if the primary net_device is not READY there is nothing
7d641072 3639 * we can do but pray resume goes smoothly.
5b435de0 3640 */
4eb3af7c 3641 if (!check_vif_up(ifp->vif))
7d641072 3642 goto exit;
5b435de0 3643
3021ad9a
HM
3644 /* Stop scheduled scan */
3645 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3646 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3647
7d641072
AS
3648 /* end any scanning */
3649 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 3650 brcmf_abort_scanning(cfg);
5b435de0 3651
4eb3af7c
HM
3652 if (wowl == NULL) {
3653 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3654 list_for_each_entry(vif, &cfg->vif_list, list) {
3655 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3656 continue;
3657 /* While going to suspend if associated with AP
3658 * disassociate from AP to save power while system is
3659 * in suspended state
3660 */
9b7a0ddc 3661 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
4eb3af7c
HM
3662 /* Make sure WPA_Supplicant receives all the event
3663 * generated due to DISASSOC call to the fw to keep
5419f7f1
HM
3664 * the state fw and WPA_Supplicant state consistent
3665 */
3666 brcmf_delay(500);
e5806072 3667 }
5419f7f1
HM
3668 /* Configure MPC */
3669 brcmf_set_mpc(ifp, 1);
e5806072 3670
e5806072 3671 } else {
5419f7f1
HM
3672 /* Configure WOWL paramaters */
3673 brcmf_configure_wowl(cfg, ifp, wowl);
e5806072
AS
3674 }
3675
5419f7f1
HM
3676exit:
3677 brcmf_dbg(TRACE, "Exit\n");
3678 /* clear any scanning activity */
3679 cfg->scan_status = 0;
e5806072 3680 return 0;
e5806072
AS
3681}
3682
5419f7f1
HM
3683static __used s32
3684brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
e5806072 3685{
5419f7f1 3686 struct brcmf_pmk_list_le *pmk_list;
48ed16e8 3687 int i;
5419f7f1
HM
3688 u32 npmk;
3689 s32 err;
e5806072 3690
5419f7f1
HM
3691 pmk_list = &cfg->pmk_list;
3692 npmk = le32_to_cpu(pmk_list->npmk);
48ed16e8 3693
5419f7f1
HM
3694 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3695 for (i = 0; i < npmk; i++)
3696 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
48ed16e8 3697
5419f7f1
HM
3698 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3699 sizeof(*pmk_list));
48ed16e8
HM
3700
3701 return err;
e5806072
AS
3702}
3703
5419f7f1
HM
3704static s32
3705brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3706 struct cfg80211_pmksa *pmksa)
e5806072 3707{
5419f7f1 3708 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 3709 struct brcmf_if *ifp = netdev_priv(ndev);
5419f7f1
HM
3710 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3711 s32 err;
3712 u32 npmk, i;
e5806072 3713
5419f7f1
HM
3714 brcmf_dbg(TRACE, "Enter\n");
3715 if (!check_vif_up(ifp->vif))
3716 return -EIO;
e5806072 3717
5419f7f1
HM
3718 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3719 for (i = 0; i < npmk; i++)
3720 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
3721 break;
3722 if (i < BRCMF_MAXPMKID) {
3723 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3724 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3725 if (i == npmk) {
3726 npmk++;
3727 cfg->pmk_list.npmk = cpu_to_le32(npmk);
3728 }
3729 } else {
3730 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
e5806072
AS
3731 return -EINVAL;
3732 }
3733
5419f7f1
HM
3734 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3735 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3736 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3737 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3738 pmk[npmk].pmkid[i + 3]);
e5806072 3739
5419f7f1 3740 err = brcmf_update_pmklist(cfg, ifp);
e5806072 3741
5419f7f1
HM
3742 brcmf_dbg(TRACE, "Exit\n");
3743 return err;
3744}
e5806072 3745
5419f7f1
HM
3746static s32
3747brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3748 struct cfg80211_pmksa *pmksa)
3749{
3750 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3751 struct brcmf_if *ifp = netdev_priv(ndev);
3752 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3753 s32 err;
3754 u32 npmk, i;
e5806072 3755
5419f7f1
HM
3756 brcmf_dbg(TRACE, "Enter\n");
3757 if (!check_vif_up(ifp->vif))
3758 return -EIO;
e5806072 3759
5419f7f1 3760 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
e5806072 3761
5419f7f1
HM
3762 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3763 for (i = 0; i < npmk; i++)
3764 if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
3765 break;
3766
3767 if ((npmk > 0) && (i < npmk)) {
3768 for (; i < (npmk - 1); i++) {
3769 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3770 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
3771 WLAN_PMKID_LEN);
e5806072 3772 }
5419f7f1
HM
3773 memset(&pmk[i], 0, sizeof(*pmk));
3774 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
e5806072 3775 } else {
5419f7f1 3776 brcmf_err("Cache entry not found\n");
e5806072
AS
3777 return -EINVAL;
3778 }
3779
5419f7f1
HM
3780 err = brcmf_update_pmklist(cfg, ifp);
3781
3782 brcmf_dbg(TRACE, "Exit\n");
3783 return err;
3784
e5806072
AS
3785}
3786
5419f7f1
HM
3787static s32
3788brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
e5806072 3789{
27a68fe3 3790 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5419f7f1
HM
3791 struct brcmf_if *ifp = netdev_priv(ndev);
3792 s32 err;
3793
3794 brcmf_dbg(TRACE, "Enter\n");
3795 if (!check_vif_up(ifp->vif))
3796 return -EIO;
3797
3798 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3799 err = brcmf_update_pmklist(cfg, ifp);
3800
3801 brcmf_dbg(TRACE, "Exit\n");
3802 return err;
e5806072 3803
e5806072 3804}
e5806072 3805
1f170110 3806static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3807{
3808 s32 err;
3809
3810 /* set auth */
ac24be6f 3811 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3812 if (err < 0) {
57d6e91a 3813 brcmf_err("auth error %d\n", err);
1a873342
HM
3814 return err;
3815 }
3816 /* set wsec */
ac24be6f 3817 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3818 if (err < 0) {
57d6e91a 3819 brcmf_err("wsec error %d\n", err);
1a873342
HM
3820 return err;
3821 }
3822 /* set upper-layer auth */
ac24be6f 3823 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3824 if (err < 0) {
57d6e91a 3825 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3826 return err;
3827 }
3828
3829 return 0;
3830}
3831
3832static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3833{
3834 if (is_rsn_ie)
3835 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3836
3837 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3838}
3839
3840static s32
a44aa400 3841brcmf_configure_wpaie(struct brcmf_if *ifp,
4b5800fe
JB
3842 const struct brcmf_vs_tlv *wpa_ie,
3843 bool is_rsn_ie)
1a873342
HM
3844{
3845 u32 auth = 0; /* d11 open authentication */
3846 u16 count;
3847 s32 err = 0;
3848 s32 len = 0;
3849 u32 i;
3850 u32 wsec;
3851 u32 pval = 0;
3852 u32 gval = 0;
3853 u32 wpa_auth = 0;
3854 u32 offset;
3855 u8 *data;
3856 u16 rsn_cap;
3857 u32 wme_bss_disable;
3858
d96b801f 3859 brcmf_dbg(TRACE, "Enter\n");
1a873342
HM
3860 if (wpa_ie == NULL)
3861 goto exit;
3862
3863 len = wpa_ie->len + TLV_HDR_LEN;
3864 data = (u8 *)wpa_ie;
619c5a9a 3865 offset = TLV_HDR_LEN;
1a873342
HM
3866 if (!is_rsn_ie)
3867 offset += VS_IE_FIXED_HDR_LEN;
619c5a9a
HM
3868 else
3869 offset += WPA_IE_VERSION_LEN;
1a873342
HM
3870
3871 /* check for multicast cipher suite */
3872 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3873 err = -EINVAL;
57d6e91a 3874 brcmf_err("no multicast cipher suite\n");
1a873342
HM
3875 goto exit;
3876 }
3877
3878 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3879 err = -EINVAL;
57d6e91a 3880 brcmf_err("ivalid OUI\n");
1a873342
HM
3881 goto exit;
3882 }
3883 offset += TLV_OUI_LEN;
3884
3885 /* pick up multicast cipher */
3886 switch (data[offset]) {
3887 case WPA_CIPHER_NONE:
3888 gval = 0;
3889 break;
3890 case WPA_CIPHER_WEP_40:
3891 case WPA_CIPHER_WEP_104:
3892 gval = WEP_ENABLED;
3893 break;
3894 case WPA_CIPHER_TKIP:
3895 gval = TKIP_ENABLED;
3896 break;
3897 case WPA_CIPHER_AES_CCM:
3898 gval = AES_ENABLED;
3899 break;
3900 default:
3901 err = -EINVAL;
57d6e91a 3902 brcmf_err("Invalid multi cast cipher info\n");
1a873342
HM
3903 goto exit;
3904 }
3905
3906 offset++;
3907 /* walk thru unicast cipher list and pick up what we recognize */
3908 count = data[offset] + (data[offset + 1] << 8);
3909 offset += WPA_IE_SUITE_COUNT_LEN;
3910 /* Check for unicast suite(s) */
3911 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3912 err = -EINVAL;
57d6e91a 3913 brcmf_err("no unicast cipher suite\n");
1a873342
HM
3914 goto exit;
3915 }
3916 for (i = 0; i < count; i++) {
3917 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3918 err = -EINVAL;
57d6e91a 3919 brcmf_err("ivalid OUI\n");
1a873342
HM
3920 goto exit;
3921 }
3922 offset += TLV_OUI_LEN;
3923 switch (data[offset]) {
3924 case WPA_CIPHER_NONE:
3925 break;
3926 case WPA_CIPHER_WEP_40:
3927 case WPA_CIPHER_WEP_104:
3928 pval |= WEP_ENABLED;
3929 break;
3930 case WPA_CIPHER_TKIP:
3931 pval |= TKIP_ENABLED;
3932 break;
3933 case WPA_CIPHER_AES_CCM:
3934 pval |= AES_ENABLED;
3935 break;
3936 default:
57d6e91a 3937 brcmf_err("Ivalid unicast security info\n");
1a873342
HM
3938 }
3939 offset++;
3940 }
3941 /* walk thru auth management suite list and pick up what we recognize */
3942 count = data[offset] + (data[offset + 1] << 8);
3943 offset += WPA_IE_SUITE_COUNT_LEN;
3944 /* Check for auth key management suite(s) */
3945 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3946 err = -EINVAL;
57d6e91a 3947 brcmf_err("no auth key mgmt suite\n");
1a873342
HM
3948 goto exit;
3949 }
3950 for (i = 0; i < count; i++) {
3951 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3952 err = -EINVAL;
57d6e91a 3953 brcmf_err("ivalid OUI\n");
1a873342
HM
3954 goto exit;
3955 }
3956 offset += TLV_OUI_LEN;
3957 switch (data[offset]) {
3958 case RSN_AKM_NONE:
d96b801f 3959 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
1a873342
HM
3960 wpa_auth |= WPA_AUTH_NONE;
3961 break;
3962 case RSN_AKM_UNSPECIFIED:
d96b801f 3963 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
1a873342
HM
3964 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3965 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3966 break;
3967 case RSN_AKM_PSK:
d96b801f 3968 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
1a873342
HM
3969 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3970 (wpa_auth |= WPA_AUTH_PSK);
3971 break;
3972 default:
57d6e91a 3973 brcmf_err("Ivalid key mgmt info\n");
1a873342
HM
3974 }
3975 offset++;
3976 }
3977
3978 if (is_rsn_ie) {
3979 wme_bss_disable = 1;
3980 if ((offset + RSN_CAP_LEN) <= len) {
3981 rsn_cap = data[offset] + (data[offset + 1] << 8);
3982 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3983 wme_bss_disable = 0;
3984 }
3985 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3986 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3987 wme_bss_disable);
1a873342 3988 if (err < 0) {
57d6e91a 3989 brcmf_err("wme_bss_disable error %d\n", err);
1a873342
HM
3990 goto exit;
3991 }
3992 }
3993 /* FOR WPS , set SES_OW_ENABLED */
3994 wsec = (pval | gval | SES_OW_ENABLED);
3995
3996 /* set auth */
ac24be6f 3997 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342 3998 if (err < 0) {
57d6e91a 3999 brcmf_err("auth error %d\n", err);
1a873342
HM
4000 goto exit;
4001 }
4002 /* set wsec */
ac24be6f 4003 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342 4004 if (err < 0) {
57d6e91a 4005 brcmf_err("wsec error %d\n", err);
1a873342
HM
4006 goto exit;
4007 }
4008 /* set upper-layer auth */
ac24be6f 4009 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342 4010 if (err < 0) {
57d6e91a 4011 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
4012 goto exit;
4013 }
4014
4015exit:
4016 return err;
4017}
4018
4019static s32
3082b9be 4020brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
4021 struct parsed_vndr_ies *vndr_ies)
4022{
1a873342
HM
4023 struct brcmf_vs_tlv *vndrie;
4024 struct brcmf_tlv *ie;
4025 struct parsed_vndr_ie_info *parsed_info;
4026 s32 remaining_len;
4027
4028 remaining_len = (s32)vndr_ie_len;
4029 memset(vndr_ies, 0, sizeof(*vndr_ies));
4030
4031 ie = (struct brcmf_tlv *)vndr_ie_buf;
4032 while (ie) {
4033 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4034 goto next;
4035 vndrie = (struct brcmf_vs_tlv *)ie;
4036 /* len should be bigger than OUI length + one */
4037 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
57d6e91a
AS
4038 brcmf_err("invalid vndr ie. length is too small %d\n",
4039 vndrie->len);
1a873342
HM
4040 goto next;
4041 }
4042 /* if wpa or wme ie, do not add ie */
4043 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4044 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4045 (vndrie->oui_type == WME_OUI_TYPE))) {
d96b801f 4046 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
1a873342
HM
4047 goto next;
4048 }
4049
4050 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4051
4052 /* save vndr ie information */
4053 parsed_info->ie_ptr = (char *)vndrie;
4054 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4055 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4056
4057 vndr_ies->count++;
4058
d96b801f
AS
4059 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4060 parsed_info->vndrie.oui[0],
4061 parsed_info->vndrie.oui[1],
4062 parsed_info->vndrie.oui[2],
4063 parsed_info->vndrie.oui_type);
1a873342 4064
9f440b7b 4065 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
1a873342
HM
4066 break;
4067next:
b41fc3d7
HM
4068 remaining_len -= (ie->len + TLV_HDR_LEN);
4069 if (remaining_len <= TLV_HDR_LEN)
1a873342
HM
4070 ie = NULL;
4071 else
b41fc3d7
HM
4072 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4073 TLV_HDR_LEN);
1a873342 4074 }
12f32370 4075 return 0;
1a873342
HM
4076}
4077
4078static u32
4079brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4080{
4081
1a873342
HM
4082 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4083 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4084
362126cd 4085 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
1a873342 4086
362126cd 4087 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
1a873342
HM
4088
4089 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4090
4091 return ie_len + VNDR_IE_HDR_SIZE;
4092}
4093
1332e26e
AS
4094s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4095 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 4096{
1332e26e
AS
4097 struct brcmf_if *ifp;
4098 struct vif_saved_ie *saved_ie;
1a873342
HM
4099 s32 err = 0;
4100 u8 *iovar_ie_buf;
4101 u8 *curr_ie_buf;
4102 u8 *mgmt_ie_buf = NULL;
3e4f319d 4103 int mgmt_ie_buf_len;
81118d16 4104 u32 *mgmt_ie_len;
1a873342
HM
4105 u32 del_add_ie_buf_len = 0;
4106 u32 total_ie_buf_len = 0;
4107 u32 parsed_ie_buf_len = 0;
4108 struct parsed_vndr_ies old_vndr_ies;
4109 struct parsed_vndr_ies new_vndr_ies;
4110 struct parsed_vndr_ie_info *vndrie_info;
4111 s32 i;
4112 u8 *ptr;
3e4f319d 4113 int remained_buf_len;
1a873342 4114
1332e26e
AS
4115 if (!vif)
4116 return -ENODEV;
4117 ifp = vif->ifp;
4118 saved_ie = &vif->saved_ie;
4119
37a869ec
HM
4120 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4121 pktflag);
1a873342
HM
4122 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4123 if (!iovar_ie_buf)
4124 return -ENOMEM;
4125 curr_ie_buf = iovar_ie_buf;
89286dc9
HM
4126 switch (pktflag) {
4127 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4128 mgmt_ie_buf = saved_ie->probe_req_ie;
4129 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4130 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4131 break;
4132 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4133 mgmt_ie_buf = saved_ie->probe_res_ie;
4134 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4135 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4136 break;
4137 case BRCMF_VNDR_IE_BEACON_FLAG:
4138 mgmt_ie_buf = saved_ie->beacon_ie;
4139 mgmt_ie_len = &saved_ie->beacon_ie_len;
4140 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4141 break;
4142 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4143 mgmt_ie_buf = saved_ie->assoc_req_ie;
4144 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4145 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4146 break;
4147 default:
4148 err = -EPERM;
4149 brcmf_err("not suitable type\n");
4150 goto exit;
1a873342
HM
4151 }
4152
4153 if (vndr_ie_len > mgmt_ie_buf_len) {
4154 err = -ENOMEM;
57d6e91a 4155 brcmf_err("extra IE size too big\n");
1a873342
HM
4156 goto exit;
4157 }
4158
4159 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4160 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4161 ptr = curr_ie_buf;
4162 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4163 for (i = 0; i < new_vndr_ies.count; i++) {
4164 vndrie_info = &new_vndr_ies.ie_info[i];
4165 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4166 vndrie_info->ie_len);
4167 parsed_ie_buf_len += vndrie_info->ie_len;
4168 }
4169 }
4170
b41fc3d7 4171 if (mgmt_ie_buf && *mgmt_ie_len) {
1a873342
HM
4172 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4173 (memcmp(mgmt_ie_buf, curr_ie_buf,
4174 parsed_ie_buf_len) == 0)) {
d96b801f 4175 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
1a873342
HM
4176 goto exit;
4177 }
4178
4179 /* parse old vndr_ie */
4180 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4181
4182 /* make a command to delete old ie */
4183 for (i = 0; i < old_vndr_ies.count; i++) {
4184 vndrie_info = &old_vndr_ies.ie_info[i];
4185
d96b801f
AS
4186 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4187 vndrie_info->vndrie.id,
4188 vndrie_info->vndrie.len,
4189 vndrie_info->vndrie.oui[0],
4190 vndrie_info->vndrie.oui[1],
4191 vndrie_info->vndrie.oui[2]);
1a873342
HM
4192
4193 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4194 vndrie_info->ie_ptr,
4195 vndrie_info->ie_len,
4196 "del");
4197 curr_ie_buf += del_add_ie_buf_len;
4198 total_ie_buf_len += del_add_ie_buf_len;
4199 }
4200 }
4201
4202 *mgmt_ie_len = 0;
4203 /* Add if there is any extra IE */
4204 if (mgmt_ie_buf && parsed_ie_buf_len) {
4205 ptr = mgmt_ie_buf;
4206
4207 remained_buf_len = mgmt_ie_buf_len;
4208
4209 /* make a command to add new ie */
4210 for (i = 0; i < new_vndr_ies.count; i++) {
4211 vndrie_info = &new_vndr_ies.ie_info[i];
4212
b41fc3d7
HM
4213 /* verify remained buf size before copy data */
4214 if (remained_buf_len < (vndrie_info->vndrie.len +
4215 VNDR_IE_VSIE_OFFSET)) {
57d6e91a
AS
4216 brcmf_err("no space in mgmt_ie_buf: len left %d",
4217 remained_buf_len);
b41fc3d7
HM
4218 break;
4219 }
4220 remained_buf_len -= (vndrie_info->ie_len +
4221 VNDR_IE_VSIE_OFFSET);
4222
d96b801f
AS
4223 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4224 vndrie_info->vndrie.id,
4225 vndrie_info->vndrie.len,
4226 vndrie_info->vndrie.oui[0],
4227 vndrie_info->vndrie.oui[1],
4228 vndrie_info->vndrie.oui[2]);
1a873342
HM
4229
4230 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4231 vndrie_info->ie_ptr,
4232 vndrie_info->ie_len,
4233 "add");
1a873342
HM
4234
4235 /* save the parsed IE in wl struct */
4236 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4237 vndrie_info->ie_len);
4238 *mgmt_ie_len += vndrie_info->ie_len;
4239
4240 curr_ie_buf += del_add_ie_buf_len;
4241 total_ie_buf_len += del_add_ie_buf_len;
4242 }
4243 }
4244 if (total_ie_buf_len) {
c1179033 4245 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 4246 total_ie_buf_len);
1a873342 4247 if (err)
57d6e91a 4248 brcmf_err("vndr ie set error : %d\n", err);
1a873342
HM
4249 }
4250
4251exit:
4252 kfree(iovar_ie_buf);
4253 return err;
4254}
4255
5f4f9f11
AS
4256s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4257{
4258 s32 pktflags[] = {
4259 BRCMF_VNDR_IE_PRBREQ_FLAG,
4260 BRCMF_VNDR_IE_PRBRSP_FLAG,
4261 BRCMF_VNDR_IE_BEACON_FLAG
4262 };
4263 int i;
4264
4265 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4266 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4267
4268 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4269 return 0;
4270}
4271
a0f07959
HM
4272static s32
4273brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4274 struct cfg80211_beacon_data *beacon)
4275{
4276 s32 err;
4277
4278 /* Set Beacon IEs to FW */
4279 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4280 beacon->tail, beacon->tail_len);
4281 if (err) {
4282 brcmf_err("Set Beacon IE Failed\n");
4283 return err;
4284 }
4285 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4286
4287 /* Set Probe Response IEs to FW */
4288 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4289 beacon->proberesp_ies,
4290 beacon->proberesp_ies_len);
4291 if (err)
4292 brcmf_err("Set Probe Resp IE Failed\n");
4293 else
4294 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4295
4296 return err;
4297}
4298
1a873342
HM
4299static s32
4300brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4301 struct cfg80211_ap_settings *settings)
4302{
4303 s32 ie_offset;
1c9d30cf 4304 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
ac24be6f 4305 struct brcmf_if *ifp = netdev_priv(ndev);
4b5800fe 4306 const struct brcmf_tlv *ssid_ie;
98027769 4307 const struct brcmf_tlv *country_ie;
1a873342 4308 struct brcmf_ssid_le ssid_le;
1a873342 4309 s32 err = -EPERM;
4b5800fe
JB
4310 const struct brcmf_tlv *rsn_ie;
4311 const struct brcmf_vs_tlv *wpa_ie;
1a873342 4312 struct brcmf_join_params join_params;
a0f07959
HM
4313 enum nl80211_iftype dev_role;
4314 struct brcmf_fil_bss_enable_le bss_enable;
06c01585 4315 u16 chanspec;
a44aa400 4316 bool mbss;
98027769 4317 int is_11d;
1a873342 4318
06c01585
AS
4319 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4320 settings->chandef.chan->hw_value,
4321 settings->chandef.center_freq1, settings->chandef.width,
a9a56878 4322 settings->beacon_interval, settings->dtim_period);
d96b801f
AS
4323 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4324 settings->ssid, settings->ssid_len, settings->auth_type,
4325 settings->inactivity_timeout);
426d0a56 4326 dev_role = ifp->vif->wdev.iftype;
a44aa400 4327 mbss = ifp->vif->mbss;
1a873342 4328
98027769
AS
4329 /* store current 11d setting */
4330 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4331 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4332 settings->beacon.tail_len,
4333 WLAN_EID_COUNTRY);
4334 is_11d = country_ie ? 1 : 0;
4335
1a873342
HM
4336 memset(&ssid_le, 0, sizeof(ssid_le));
4337 if (settings->ssid == NULL || settings->ssid_len == 0) {
4338 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4339 ssid_ie = brcmf_parse_tlvs(
4340 (u8 *)&settings->beacon.head[ie_offset],
4341 settings->beacon.head_len - ie_offset,
4342 WLAN_EID_SSID);
4343 if (!ssid_ie)
4344 return -EINVAL;
4345
4346 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4347 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
d96b801f 4348 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
1a873342
HM
4349 } else {
4350 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4351 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4352 }
4353
a44aa400
HM
4354 if (!mbss) {
4355 brcmf_set_mpc(ifp, 0);
52f22fb2 4356 brcmf_configure_arp_nd_offload(ifp, false);
a44aa400 4357 }
1a873342
HM
4358
4359 /* find the RSN_IE */
4360 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4361 settings->beacon.tail_len, WLAN_EID_RSN);
4362
4363 /* find the WPA_IE */
4364 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4365 settings->beacon.tail_len);
4366
1a873342 4367 if ((wpa_ie != NULL || rsn_ie != NULL)) {
d96b801f 4368 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
1a873342
HM
4369 if (wpa_ie != NULL) {
4370 /* WPA IE */
a44aa400 4371 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
1a873342
HM
4372 if (err < 0)
4373 goto exit;
1a873342 4374 } else {
a44aa400
HM
4375 struct brcmf_vs_tlv *tmp_ie;
4376
4377 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4378
1a873342 4379 /* RSN IE */
a44aa400 4380 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
1a873342
HM
4381 if (err < 0)
4382 goto exit;
1a873342 4383 }
1a873342 4384 } else {
d96b801f 4385 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
1f170110 4386 brcmf_configure_opensecurity(ifp);
1a873342 4387 }
1a873342 4388
a0f07959 4389 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
1a873342 4390
a44aa400
HM
4391 if (!mbss) {
4392 chanspec = chandef_to_chanspec(&cfg->d11inf,
4393 &settings->chandef);
4394 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
1a873342 4395 if (err < 0) {
a44aa400
HM
4396 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4397 chanspec, err);
1a873342
HM
4398 goto exit;
4399 }
a44aa400 4400
98027769
AS
4401 if (is_11d != ifp->vif->is_11d) {
4402 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4403 is_11d);
4404 if (err < 0) {
4405 brcmf_err("Regulatory Set Error, %d\n", err);
4406 goto exit;
4407 }
4408 }
a44aa400
HM
4409 if (settings->beacon_interval) {
4410 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4411 settings->beacon_interval);
4412 if (err < 0) {
4413 brcmf_err("Beacon Interval Set Error, %d\n",
4414 err);
4415 goto exit;
4416 }
4417 }
4418 if (settings->dtim_period) {
4419 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4420 settings->dtim_period);
4421 if (err < 0) {
4422 brcmf_err("DTIM Interval Set Error, %d\n", err);
4423 goto exit;
4424 }
1a873342 4425 }
a0f07959 4426
8abffd81
HM
4427 if ((dev_role == NL80211_IFTYPE_AP) &&
4428 ((ifp->ifidx == 0) ||
4429 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
a44aa400
HM
4430 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4431 if (err < 0) {
4432 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4433 goto exit;
4434 }
4435 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4436 }
4437
4438 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
a0f07959 4439 if (err < 0) {
a44aa400 4440 brcmf_err("SET INFRA error %d\n", err);
a0f07959
HM
4441 goto exit;
4442 }
98027769
AS
4443 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4444 /* Multiple-BSS should use same 11d configuration */
4445 err = -EINVAL;
4446 goto exit;
1a873342 4447 }
a0f07959 4448 if (dev_role == NL80211_IFTYPE_AP) {
a44aa400
HM
4449 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4450 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4451
a0f07959
HM
4452 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4453 if (err < 0) {
4454 brcmf_err("setting AP mode failed %d\n", err);
4455 goto exit;
4456 }
4457 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4458 if (err < 0) {
4459 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4460 goto exit;
4461 }
118eb304
HM
4462 /* On DOWN the firmware removes the WEP keys, reconfigure
4463 * them if they were set.
4464 */
4465 brcmf_cfg80211_reconfigure_wep(ifp);
a0f07959
HM
4466
4467 memset(&join_params, 0, sizeof(join_params));
4468 /* join parameters starts with ssid */
4469 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4470 /* create softap */
4471 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4472 &join_params, sizeof(join_params));
4473 if (err < 0) {
4474 brcmf_err("SET SSID error (%d)\n", err);
4475 goto exit;
4476 }
4477 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4478 } else {
4479 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4480 sizeof(ssid_le));
4481 if (err < 0) {
4482 brcmf_err("setting ssid failed %d\n", err);
4483 goto exit;
4484 }
37a869ec 4485 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
a0f07959
HM
4486 bss_enable.enable = cpu_to_le32(1);
4487 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4488 sizeof(bss_enable));
4489 if (err < 0) {
4490 brcmf_err("bss_enable config failed %d\n", err);
4491 goto exit;
4492 }
4493
4494 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4495 }
c1179033 4496 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
92121e69 4497 brcmf_net_setcarrier(ifp, true);
1a873342
HM
4498
4499exit:
a44aa400 4500 if ((err) && (!mbss)) {
f96aa07e 4501 brcmf_set_mpc(ifp, 1);
52f22fb2 4502 brcmf_configure_arp_nd_offload(ifp, true);
b3657453 4503 }
1a873342
HM
4504 return err;
4505}
4506
4507static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4508{
c1179033 4509 struct brcmf_if *ifp = netdev_priv(ndev);
5c33a942 4510 s32 err;
426d0a56 4511 struct brcmf_fil_bss_enable_le bss_enable;
5c33a942 4512 struct brcmf_join_params join_params;
1a873342 4513
d96b801f 4514 brcmf_dbg(TRACE, "Enter\n");
1a873342 4515
426d0a56 4516 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
1a873342
HM
4517 /* Due to most likely deauths outstanding we sleep */
4518 /* first to make sure they get processed by fw. */
4519 msleep(400);
5c33a942 4520
a44aa400
HM
4521 if (ifp->vif->mbss) {
4522 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4523 return err;
4524 }
4525
5c33a942
HM
4526 memset(&join_params, 0, sizeof(join_params));
4527 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4528 &join_params, sizeof(join_params));
4529 if (err < 0)
4530 brcmf_err("SET SSID error (%d)\n", err);
a44aa400 4531 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
5c33a942 4532 if (err < 0)
a44aa400 4533 brcmf_err("BRCMF_C_DOWN error %d\n", err);
5c33a942
HM
4534 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4535 if (err < 0)
4536 brcmf_err("setting AP mode failed %d\n", err);
4537 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4538 if (err < 0)
4539 brcmf_err("setting INFRA mode failed %d\n", err);
a44aa400
HM
4540 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4541 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
98027769
AS
4542 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4543 ifp->vif->is_11d);
4544 if (err < 0)
4545 brcmf_err("restoring REGULATORY setting failed %d\n",
4546 err);
a44aa400
HM
4547 /* Bring device back up so it can be used again */
4548 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4549 if (err < 0)
4550 brcmf_err("BRCMF_C_UP error %d\n", err);
426d0a56 4551 } else {
37a869ec 4552 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
426d0a56
HM
4553 bss_enable.enable = cpu_to_le32(0);
4554 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4555 sizeof(bss_enable));
4556 if (err < 0)
4557 brcmf_err("bss_enable config failed %d\n", err);
1a873342 4558 }
f96aa07e 4559 brcmf_set_mpc(ifp, 1);
52f22fb2 4560 brcmf_configure_arp_nd_offload(ifp, true);
426d0a56 4561 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
92121e69 4562 brcmf_net_setcarrier(ifp, false);
426d0a56 4563
1a873342
HM
4564 return err;
4565}
4566
a0f07959
HM
4567static s32
4568brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4569 struct cfg80211_beacon_data *info)
4570{
a0f07959
HM
4571 struct brcmf_if *ifp = netdev_priv(ndev);
4572 s32 err;
4573
4574 brcmf_dbg(TRACE, "Enter\n");
4575
a0f07959
HM
4576 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4577
4578 return err;
4579}
4580
1a873342
HM
4581static int
4582brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
89c771e5 4583 struct station_del_parameters *params)
1a873342 4584{
a0f07959 4585 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342 4586 struct brcmf_scb_val_le scbval;
0abb5f21 4587 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
4588 s32 err;
4589
89c771e5 4590 if (!params->mac)
1a873342
HM
4591 return -EFAULT;
4592
89c771e5 4593 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
1a873342 4594
a0f07959
HM
4595 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4596 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ce81e317 4597 if (!check_vif_up(ifp->vif))
1a873342
HM
4598 return -EIO;
4599
89c771e5 4600 memcpy(&scbval.ea, params->mac, ETH_ALEN);
ba8b6ae6 4601 scbval.val = cpu_to_le32(params->reason_code);
0abb5f21 4602 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 4603 &scbval, sizeof(scbval));
1a873342 4604 if (err)
57d6e91a 4605 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
7ab6acd0 4606
d96b801f 4607 brcmf_dbg(TRACE, "Exit\n");
1a873342
HM
4608 return err;
4609}
4610
6b89dcb3
HM
4611static int
4612brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4613 const u8 *mac, struct station_parameters *params)
4614{
4615 struct brcmf_if *ifp = netdev_priv(ndev);
4616 s32 err;
4617
4618 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4619 params->sta_flags_mask, params->sta_flags_set);
4620
4621 /* Ignore all 00 MAC */
4622 if (is_zero_ether_addr(mac))
4623 return 0;
4624
4625 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4626 return 0;
4627
4628 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4629 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4630 (void *)mac, ETH_ALEN);
4631 else
4632 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4633 (void *)mac, ETH_ALEN);
4634 if (err < 0)
4635 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4636
4637 return err;
4638}
0de8aace
HM
4639
4640static void
4641brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4642 struct wireless_dev *wdev,
4643 u16 frame_type, bool reg)
4644{
7fa2e352 4645 struct brcmf_cfg80211_vif *vif;
0de8aace
HM
4646 u16 mgmt_type;
4647
4648 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4649
4650 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
7fa2e352 4651 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
0de8aace
HM
4652 if (reg)
4653 vif->mgmt_rx_reg |= BIT(mgmt_type);
4654 else
318a64ce 4655 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
0de8aace
HM
4656}
4657
4658
4659static int
4660brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
b176e629 4661 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
0de8aace
HM
4662{
4663 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
b176e629
AO
4664 struct ieee80211_channel *chan = params->chan;
4665 const u8 *buf = params->buf;
4666 size_t len = params->len;
0de8aace
HM
4667 const struct ieee80211_mgmt *mgmt;
4668 struct brcmf_cfg80211_vif *vif;
4669 s32 err = 0;
4670 s32 ie_offset;
4671 s32 ie_len;
18e2f61d
HM
4672 struct brcmf_fil_action_frame_le *action_frame;
4673 struct brcmf_fil_af_params_le *af_params;
4674 bool ack;
4675 s32 chan_nr;
c2ff8cad 4676 u32 freq;
0de8aace
HM
4677
4678 brcmf_dbg(TRACE, "Enter\n");
4679
4680 *cookie = 0;
4681
4682 mgmt = (const struct ieee80211_mgmt *)buf;
4683
a0f07959
HM
4684 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4685 brcmf_err("Driver only allows MGMT packet type\n");
4686 return -EPERM;
4687 }
0de8aace 4688
c2ff8cad
AQ
4689 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4690
a0f07959
HM
4691 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4692 /* Right now the only reason to get a probe response */
4693 /* is for p2p listen response or for p2p GO from */
4694 /* wpa_supplicant. Unfortunately the probe is send */
4695 /* on primary ndev, while dongle wants it on the p2p */
4696 /* vif. Since this is only reason for a probe */
4697 /* response to be sent, the vif is taken from cfg. */
4698 /* If ever desired to send proberesp for non p2p */
4699 /* response then data should be checked for */
4700 /* "DIRECT-". Note in future supplicant will take */
4701 /* dedicated p2p wdev to do this and then this 'hack'*/
4702 /* is not needed anymore. */
4703 ie_offset = DOT11_MGMT_HDR_LEN +
4704 DOT11_BCN_PRB_FIXED_LEN;
4705 ie_len = len - ie_offset;
a0f07959 4706 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
0de8aace 4707 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
a0f07959
HM
4708 err = brcmf_vif_set_mgmt_ie(vif,
4709 BRCMF_VNDR_IE_PRBRSP_FLAG,
4710 &buf[ie_offset],
4711 ie_len);
4712 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4713 GFP_KERNEL);
18e2f61d
HM
4714 } else if (ieee80211_is_action(mgmt->frame_control)) {
4715 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4716 if (af_params == NULL) {
4717 brcmf_err("unable to allocate frame\n");
4718 err = -ENOMEM;
4719 goto exit;
4720 }
4721 action_frame = &af_params->action_frame;
4722 /* Add the packet Id */
4723 action_frame->packet_id = cpu_to_le32(*cookie);
4724 /* Add BSSID */
4725 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4726 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4727 /* Add the length exepted for 802.11 header */
4728 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
c2ff8cad
AQ
4729 /* Add the channel. Use the one specified as parameter if any or
4730 * the current one (got from the firmware) otherwise
4731 */
4732 if (chan)
4733 freq = chan->center_freq;
4734 else
4735 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4736 &freq);
4737 chan_nr = ieee80211_frequency_to_channel(freq);
18e2f61d
HM
4738 af_params->channel = cpu_to_le32(chan_nr);
4739
4740 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4741 le16_to_cpu(action_frame->len));
4742
4743 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
86a9c4a2 4744 *cookie, le16_to_cpu(action_frame->len), freq);
18e2f61d 4745
7fa2e352 4746 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
18e2f61d
HM
4747 af_params);
4748
4749 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4750 GFP_KERNEL);
4751 kfree(af_params);
a0f07959
HM
4752 } else {
4753 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4754 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
0de8aace 4755 }
a0f07959 4756
18e2f61d 4757exit:
0de8aace
HM
4758 return err;
4759}
4760
4761
4762static int
4763brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4764 struct wireless_dev *wdev,
4765 u64 cookie)
4766{
4767 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4768 struct brcmf_cfg80211_vif *vif;
4769 int err = 0;
4770
4771 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4772
4773 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4774 if (vif == NULL) {
4775 brcmf_err("No p2p device available for probe response\n");
4776 err = -ENODEV;
4777 goto exit;
4778 }
4779 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4780exit:
4781 return err;
4782}
4783
61730d4d
PH
4784static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4785 struct wireless_dev *wdev,
4786 enum nl80211_crit_proto_id proto,
4787 u16 duration)
4788{
4789 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4790 struct brcmf_cfg80211_vif *vif;
4791
4792 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4793
4794 /* only DHCP support for now */
4795 if (proto != NL80211_CRIT_PROTO_DHCP)
4796 return -EINVAL;
4797
4798 /* suppress and abort scanning */
4799 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4800 brcmf_abort_scanning(cfg);
4801
4802 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4803}
4804
4805static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4806 struct wireless_dev *wdev)
4807{
4808 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4809 struct brcmf_cfg80211_vif *vif;
4810
4811 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4812
4813 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4814 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4815}
4816
70b7d94b
HM
4817static s32
4818brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4819 const struct brcmf_event_msg *e, void *data)
4820{
4821 switch (e->reason) {
4822 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4823 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4824 break;
4825 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4826 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4827 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4828 break;
4829 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4830 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4831 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4832 break;
4833 }
4834
4835 return 0;
4836}
4837
89c2f382
AS
4838static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4839{
4840 int ret;
4841
4842 switch (oper) {
4843 case NL80211_TDLS_DISCOVERY_REQ:
4844 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4845 break;
4846 case NL80211_TDLS_SETUP:
4847 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4848 break;
4849 case NL80211_TDLS_TEARDOWN:
4850 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4851 break;
4852 default:
4853 brcmf_err("unsupported operation: %d\n", oper);
4854 ret = -EOPNOTSUPP;
4855 }
4856 return ret;
4857}
4858
4859static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
3b3a0162 4860 struct net_device *ndev, const u8 *peer,
89c2f382
AS
4861 enum nl80211_tdls_operation oper)
4862{
4863 struct brcmf_if *ifp;
4864 struct brcmf_tdls_iovar_le info;
4865 int ret = 0;
4866
4867 ret = brcmf_convert_nl80211_tdls_oper(oper);
4868 if (ret < 0)
4869 return ret;
4870
4871 ifp = netdev_priv(ndev);
4872 memset(&info, 0, sizeof(info));
4873 info.mode = (u8)ret;
4874 if (peer)
4875 memcpy(info.ea, peer, ETH_ALEN);
4876
4877 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4878 &info, sizeof(info));
4879 if (ret < 0)
4880 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4881
4882 return ret;
4883}
4884
5c22fb85
HM
4885#ifdef CONFIG_PM
4886static int
4887brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
4888 struct cfg80211_gtk_rekey_data *gtk)
4889{
4890 struct brcmf_if *ifp = netdev_priv(ndev);
4891 struct brcmf_gtk_keyinfo_le gtk_le;
4892 int ret;
4893
4894 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
4895
4896 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
4897 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
4898 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
4899 sizeof(gtk_le.replay_counter));
4900
4901 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
4902 sizeof(gtk_le));
4903 if (ret < 0)
4904 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
4905
4906 return ret;
4907}
4908#endif
4909
4910static struct cfg80211_ops brcmf_cfg80211_ops = {
9f440b7b
AS
4911 .add_virtual_intf = brcmf_cfg80211_add_iface,
4912 .del_virtual_intf = brcmf_cfg80211_del_iface,
5b435de0
AS
4913 .change_virtual_intf = brcmf_cfg80211_change_iface,
4914 .scan = brcmf_cfg80211_scan,
4915 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4916 .join_ibss = brcmf_cfg80211_join_ibss,
4917 .leave_ibss = brcmf_cfg80211_leave_ibss,
4918 .get_station = brcmf_cfg80211_get_station,
bf2a7e04 4919 .dump_station = brcmf_cfg80211_dump_station,
5b435de0
AS
4920 .set_tx_power = brcmf_cfg80211_set_tx_power,
4921 .get_tx_power = brcmf_cfg80211_get_tx_power,
4922 .add_key = brcmf_cfg80211_add_key,
4923 .del_key = brcmf_cfg80211_del_key,
4924 .get_key = brcmf_cfg80211_get_key,
4925 .set_default_key = brcmf_cfg80211_config_default_key,
4926 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4927 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
5b435de0
AS
4928 .connect = brcmf_cfg80211_connect,
4929 .disconnect = brcmf_cfg80211_disconnect,
4930 .suspend = brcmf_cfg80211_suspend,
4931 .resume = brcmf_cfg80211_resume,
4932 .set_pmksa = brcmf_cfg80211_set_pmksa,
4933 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4934 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4935 .start_ap = brcmf_cfg80211_start_ap,
4936 .stop_ap = brcmf_cfg80211_stop_ap,
a0f07959 4937 .change_beacon = brcmf_cfg80211_change_beacon,
1a873342 4938 .del_station = brcmf_cfg80211_del_station,
6b89dcb3 4939 .change_station = brcmf_cfg80211_change_station,
e5806072
AS
4940 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4941 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
0de8aace
HM
4942 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4943 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4944 .remain_on_channel = brcmf_p2p_remain_on_channel,
4945 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
27f10e38
AS
4946 .start_p2p_device = brcmf_p2p_start_device,
4947 .stop_p2p_device = brcmf_p2p_stop_device,
61730d4d
PH
4948 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4949 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
89c2f382 4950 .tdls_oper = brcmf_cfg80211_tdls_oper,
5b435de0
AS
4951};
4952
3eacf866 4953struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
9f440b7b
AS
4954 enum nl80211_iftype type,
4955 bool pm_block)
3eacf866 4956{
a44aa400 4957 struct brcmf_cfg80211_vif *vif_walk;
3eacf866 4958 struct brcmf_cfg80211_vif *vif;
a44aa400 4959 bool mbss;
5b435de0 4960
33a6b157 4961 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
9f440b7b 4962 sizeof(*vif));
3eacf866
AS
4963 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4964 if (!vif)
4965 return ERR_PTR(-ENOMEM);
4966
4967 vif->wdev.wiphy = cfg->wiphy;
9f440b7b 4968 vif->wdev.iftype = type;
5b435de0 4969
3eacf866 4970 vif->pm_block = pm_block;
3eacf866 4971
6ac4f4ed
AS
4972 brcmf_init_prof(&vif->profile);
4973
a44aa400
HM
4974 if (type == NL80211_IFTYPE_AP) {
4975 mbss = false;
4976 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
4977 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
4978 mbss = true;
4979 break;
4980 }
4981 }
4982 vif->mbss = mbss;
4983 }
4984
3eacf866 4985 list_add_tail(&vif->list, &cfg->vif_list);
3eacf866 4986 return vif;
5b435de0
AS
4987}
4988
427dec5f 4989void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4990{
3eacf866 4991 list_del(&vif->list);
3eacf866 4992 kfree(vif);
5b435de0
AS
4993}
4994
9df4d542
AS
4995void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4996{
4997 struct brcmf_cfg80211_vif *vif;
4998 struct brcmf_if *ifp;
4999
5000 ifp = netdev_priv(ndev);
5001 vif = ifp->vif;
5002
95ef1239
AS
5003 if (vif)
5004 brcmf_free_vif(vif);
9df4d542
AS
5005 free_netdev(ndev);
5006}
5007
903e0eee 5008static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
5b435de0 5009{
5c36b99a
AS
5010 u32 event = e->event_code;
5011 u32 status = e->status;
5b435de0
AS
5012
5013 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
16886735 5014 brcmf_dbg(CONN, "Processing set ssid\n");
5b435de0
AS
5015 return true;
5016 }
5017
5018 return false;
5019}
5020
903e0eee 5021static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
5b435de0 5022{
5c36b99a
AS
5023 u32 event = e->event_code;
5024 u16 flags = e->flags;
5b435de0 5025
68ca395f
HM
5026 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5027 (event == BRCMF_E_DISASSOC_IND) ||
5028 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
16886735 5029 brcmf_dbg(CONN, "Processing link down\n");
5b435de0
AS
5030 return true;
5031 }
5032 return false;
5033}
5034
27a68fe3 5035static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
5036 const struct brcmf_event_msg *e)
5037{
5c36b99a
AS
5038 u32 event = e->event_code;
5039 u32 status = e->status;
5b435de0
AS
5040
5041 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
16886735
AS
5042 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5043 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
5044 return true;
5045 }
5046
5047 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
16886735 5048 brcmf_dbg(CONN, "Processing connecting & no network found\n");
5b435de0
AS
5049 return true;
5050 }
5051
5052 return false;
5053}
5054
27a68fe3 5055static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 5056{
27a68fe3 5057 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
5058
5059 kfree(conn_info->req_ie);
5060 conn_info->req_ie = NULL;
5061 conn_info->req_ie_len = 0;
5062 kfree(conn_info->resp_ie);
5063 conn_info->resp_ie = NULL;
5064 conn_info->resp_ie_len = 0;
5065}
5066
89286dc9
HM
5067static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5068 struct brcmf_if *ifp)
5b435de0 5069{
c4e382d2 5070 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 5071 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
5072 u32 req_len;
5073 u32 resp_len;
5074 s32 err = 0;
5075
27a68fe3 5076 brcmf_clear_assoc_ies(cfg);
5b435de0 5077
ac24be6f
AS
5078 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5079 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0 5080 if (err) {
57d6e91a 5081 brcmf_err("could not get assoc info (%d)\n", err);
5b435de0
AS
5082 return err;
5083 }
c4e382d2 5084 assoc_info =
27a68fe3 5085 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
5086 req_len = le32_to_cpu(assoc_info->req_len);
5087 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 5088 if (req_len) {
ac24be6f 5089 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
5090 cfg->extra_buf,
5091 WL_ASSOC_INFO_MAX);
5b435de0 5092 if (err) {
57d6e91a 5093 brcmf_err("could not get assoc req (%d)\n", err);
5b435de0
AS
5094 return err;
5095 }
5096 conn_info->req_ie_len = req_len;
5097 conn_info->req_ie =
27a68fe3 5098 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
5099 GFP_KERNEL);
5100 } else {
5101 conn_info->req_ie_len = 0;
5102 conn_info->req_ie = NULL;
5103 }
5104 if (resp_len) {
ac24be6f 5105 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
5106 cfg->extra_buf,
5107 WL_ASSOC_INFO_MAX);
5b435de0 5108 if (err) {
57d6e91a 5109 brcmf_err("could not get assoc resp (%d)\n", err);
5b435de0
AS
5110 return err;
5111 }
5112 conn_info->resp_ie_len = resp_len;
5113 conn_info->resp_ie =
27a68fe3 5114 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
5115 GFP_KERNEL);
5116 } else {
5117 conn_info->resp_ie_len = 0;
5118 conn_info->resp_ie = NULL;
5119 }
16886735
AS
5120 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5121 conn_info->req_ie_len, conn_info->resp_ie_len);
5b435de0
AS
5122
5123 return err;
5124}
5125
5126static s32
27a68fe3 5127brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
5128 struct net_device *ndev,
5129 const struct brcmf_event_msg *e)
5130{
c1179033
AS
5131 struct brcmf_if *ifp = netdev_priv(ndev);
5132 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
5133 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5134 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 5135 struct ieee80211_channel *notify_channel = NULL;
5b435de0 5136 struct ieee80211_supported_band *band;
a180b83b 5137 struct brcmf_bss_info_le *bi;
83cf17aa 5138 struct brcmu_chan ch;
5b435de0
AS
5139 u32 freq;
5140 s32 err = 0;
a180b83b 5141 u8 *buf;
5b435de0 5142
d96b801f 5143 brcmf_dbg(TRACE, "Enter\n");
5b435de0 5144
89286dc9 5145 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 5146 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9 5147 brcmf_update_bss_info(cfg, ifp);
5b435de0 5148
a180b83b
FL
5149 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5150 if (buf == NULL) {
5151 err = -ENOMEM;
5152 goto done;
5153 }
5154
5155 /* data sent to dongle has to be little endian */
5156 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 5157 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 5158 buf, WL_BSS_INFO_MAX);
a180b83b
FL
5159
5160 if (err)
5161 goto done;
5b435de0 5162
a180b83b 5163 bi = (struct brcmf_bss_info_le *)(buf + 4);
83cf17aa
FL
5164 ch.chspec = le16_to_cpu(bi->chanspec);
5165 cfg->d11inf.decchspec(&ch);
5b435de0 5166
83cf17aa 5167 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
5168 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5169 else
5170 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5171
83cf17aa 5172 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
5173 notify_channel = ieee80211_get_channel(wiphy, freq);
5174
a180b83b
FL
5175done:
5176 kfree(buf);
06bb123e 5177 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
5178 conn_info->req_ie, conn_info->req_ie_len,
5179 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16886735 5180 brcmf_dbg(CONN, "Report roaming result\n");
5b435de0 5181
c1179033 5182 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
d96b801f 5183 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
5184 return err;
5185}
5186
5187static s32
27a68fe3 5188brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
5189 struct net_device *ndev, const struct brcmf_event_msg *e,
5190 bool completed)
5191{
c1179033
AS
5192 struct brcmf_if *ifp = netdev_priv(ndev);
5193 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 5194 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0 5195
d96b801f 5196 brcmf_dbg(TRACE, "Enter\n");
5b435de0 5197
c1179033
AS
5198 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5199 &ifp->vif->sme_state)) {
5b435de0 5200 if (completed) {
89286dc9 5201 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 5202 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9
HM
5203 brcmf_update_bss_info(cfg, ifp);
5204 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5205 &ifp->vif->sme_state);
5b435de0
AS
5206 }
5207 cfg80211_connect_result(ndev,
06bb123e 5208 (u8 *)profile->bssid,
5b435de0
AS
5209 conn_info->req_ie,
5210 conn_info->req_ie_len,
5211 conn_info->resp_ie,
5212 conn_info->resp_ie_len,
5213 completed ? WLAN_STATUS_SUCCESS :
5214 WLAN_STATUS_AUTH_TIMEOUT,
5215 GFP_KERNEL);
16886735
AS
5216 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5217 completed ? "succeeded" : "failed");
5b435de0 5218 }
d96b801f 5219 brcmf_dbg(TRACE, "Exit\n");
12f32370 5220 return 0;
5b435de0
AS
5221}
5222
5223static s32
27a68fe3 5224brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
5225 struct net_device *ndev,
5226 const struct brcmf_event_msg *e, void *data)
5227{
a44aa400 5228 struct brcmf_if *ifp = netdev_priv(ndev);
7ee29602 5229 static int generation;
5c36b99a
AS
5230 u32 event = e->event_code;
5231 u32 reason = e->reason;
1a873342
HM
5232 struct station_info sinfo;
5233
16886735 5234 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
5f4f9f11
AS
5235 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5236 ndev != cfg_to_ndev(cfg)) {
5237 brcmf_dbg(CONN, "AP mode link down\n");
5238 complete(&cfg->vif_disabled);
a44aa400 5239 if (ifp->vif->mbss)
ee6e3a34 5240 brcmf_remove_interface(ifp);
5f4f9f11
AS
5241 return 0;
5242 }
1a873342 5243
1a873342 5244 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
7ee29602
HM
5245 (reason == BRCMF_E_STATUS_SUCCESS)) {
5246 memset(&sinfo, 0, sizeof(sinfo));
1a873342 5247 if (!data) {
57d6e91a 5248 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
1a873342
HM
5249 return -EINVAL;
5250 }
5251 sinfo.assoc_req_ies = data;
7ee29602 5252 sinfo.assoc_req_ies_len = e->datalen;
1a873342
HM
5253 generation++;
5254 sinfo.generation = generation;
7ee29602 5255 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
1a873342
HM
5256 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5257 (event == BRCMF_E_DEAUTH_IND) ||
5258 (event == BRCMF_E_DEAUTH)) {
7ee29602 5259 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
1a873342 5260 }
7ee29602 5261 return 0;
1a873342
HM
5262}
5263
5b435de0 5264static s32
1993732e 5265brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
5266 const struct brcmf_event_msg *e, void *data)
5267{
1993732e
AS
5268 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5269 struct net_device *ndev = ifp->ndev;
c1179033 5270 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
fe94f3a4 5271 struct ieee80211_channel *chan;
5b435de0
AS
5272 s32 err = 0;
5273
8851cce0
HM
5274 if ((e->event_code == BRCMF_E_DEAUTH) ||
5275 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5276 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5277 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5278 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5279 }
5280
967fe2c8 5281 if (brcmf_is_apmode(ifp->vif)) {
27a68fe3 5282 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
903e0eee 5283 } else if (brcmf_is_linkup(e)) {
16886735 5284 brcmf_dbg(CONN, "Linkup\n");
128ce3b6 5285 if (brcmf_is_ibssmode(ifp->vif)) {
b0a79088 5286 brcmf_inform_ibss(cfg, ndev, e->addr);
fe94f3a4 5287 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
6c8c4f72 5288 memcpy(profile->bssid, e->addr, ETH_ALEN);
fe94f3a4 5289 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
c1179033
AS
5290 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5291 &ifp->vif->sme_state);
5292 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5293 &ifp->vif->sme_state);
5b435de0 5294 } else
27a68fe3 5295 brcmf_bss_connect_done(cfg, ndev, e, true);
92121e69 5296 brcmf_net_setcarrier(ifp, true);
903e0eee 5297 } else if (brcmf_is_linkdown(e)) {
16886735 5298 brcmf_dbg(CONN, "Linkdown\n");
128ce3b6 5299 if (!brcmf_is_ibssmode(ifp->vif)) {
27a68fe3 5300 brcmf_bss_connect_done(cfg, ndev, e, false);
42e0ed0d
HM
5301 brcmf_link_down(ifp->vif,
5302 brcmf_map_fw_linkdown_reason(e));
5303 brcmf_init_prof(ndev_to_prof(ndev));
5304 if (ndev != cfg_to_ndev(cfg))
5305 complete(&cfg->vif_disabled);
5306 brcmf_net_setcarrier(ifp, false);
5b435de0 5307 }
27a68fe3 5308 } else if (brcmf_is_nonetwork(cfg, e)) {
128ce3b6 5309 if (brcmf_is_ibssmode(ifp->vif))
c1179033
AS
5310 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5311 &ifp->vif->sme_state);
5b435de0 5312 else
27a68fe3 5313 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
5314 }
5315
5316 return err;
5317}
5318
5319static s32
1993732e 5320brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
5321 const struct brcmf_event_msg *e, void *data)
5322{
1993732e 5323 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5c36b99a
AS
5324 u32 event = e->event_code;
5325 u32 status = e->status;
5b435de0
AS
5326
5327 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 5328 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 5329 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 5330 else
1993732e 5331 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
5332 }
5333
12f32370 5334 return 0;
5b435de0
AS
5335}
5336
5337static s32
1993732e 5338brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
5339 const struct brcmf_event_msg *e, void *data)
5340{
5c36b99a 5341 u16 flags = e->flags;
5b435de0
AS
5342 enum nl80211_key_type key_type;
5343
5344 if (flags & BRCMF_EVENT_MSG_GROUP)
5345 key_type = NL80211_KEYTYPE_GROUP;
5346 else
5347 key_type = NL80211_KEYTYPE_PAIRWISE;
5348
1993732e 5349 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
5350 NULL, GFP_KERNEL);
5351
5352 return 0;
5353}
5354
d3c0b633
AS
5355static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5356 const struct brcmf_event_msg *e, void *data)
5357{
5358 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5359 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5360 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5361 struct brcmf_cfg80211_vif *vif;
5362
37a869ec 5363 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
d3c0b633 5364 ifevent->action, ifevent->flags, ifevent->ifidx,
37a869ec 5365 ifevent->bsscfgidx);
d3c0b633 5366
d3c0b633
AS
5367 mutex_lock(&event->vif_event_lock);
5368 event->action = ifevent->action;
5369 vif = event->vif;
5370
5371 switch (ifevent->action) {
5372 case BRCMF_E_IF_ADD:
5373 /* waiting process may have timed out */
dc4a787c
WY
5374 if (!cfg->vif_event.vif) {
5375 mutex_unlock(&event->vif_event_lock);
d3c0b633 5376 return -EBADF;
dc4a787c 5377 }
d3c0b633
AS
5378
5379 ifp->vif = vif;
5380 vif->ifp = ifp;
01b8e7db
AS
5381 if (ifp->ndev) {
5382 vif->wdev.netdev = ifp->ndev;
5383 ifp->ndev->ieee80211_ptr = &vif->wdev;
5384 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5385 }
d3c0b633
AS
5386 mutex_unlock(&event->vif_event_lock);
5387 wake_up(&event->vif_wq);
4b3a89de 5388 return 0;
d3c0b633
AS
5389
5390 case BRCMF_E_IF_DEL:
d3c0b633
AS
5391 mutex_unlock(&event->vif_event_lock);
5392 /* event may not be upon user request */
5393 if (brcmf_cfg80211_vif_event_armed(cfg))
5394 wake_up(&event->vif_wq);
5395 return 0;
5396
7a5c1f64
HM
5397 case BRCMF_E_IF_CHANGE:
5398 mutex_unlock(&event->vif_event_lock);
5399 wake_up(&event->vif_wq);
5400 return 0;
5401
d3c0b633
AS
5402 default:
5403 mutex_unlock(&event->vif_event_lock);
5404 break;
5405 }
5406 return -EINVAL;
5407}
5408
5b435de0
AS
5409static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5410{
5b435de0
AS
5411 conf->frag_threshold = (u32)-1;
5412 conf->rts_threshold = (u32)-1;
5413 conf->retry_short = (u32)-1;
5414 conf->retry_long = (u32)-1;
5b435de0
AS
5415}
5416
5c36b99a 5417static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 5418{
5c36b99a
AS
5419 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5420 brcmf_notify_connect_status);
5421 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5422 brcmf_notify_connect_status);
5423 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5424 brcmf_notify_connect_status);
5425 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5426 brcmf_notify_connect_status);
5427 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5428 brcmf_notify_connect_status);
5429 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5430 brcmf_notify_connect_status);
5431 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5432 brcmf_notify_roaming_status);
5433 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5434 brcmf_notify_mic_status);
5435 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5436 brcmf_notify_connect_status);
5437 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5438 brcmf_notify_sched_scan_results);
d3c0b633
AS
5439 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5440 brcmf_notify_vif_event);
0de8aace 5441 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
6eda4e2c 5442 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
0de8aace
HM
5443 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5444 brcmf_p2p_notify_listen_complete);
e6da3400
HM
5445 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5446 brcmf_p2p_notify_action_frame_rx);
18e2f61d
HM
5447 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5448 brcmf_p2p_notify_action_tx_complete);
6eda4e2c
HM
5449 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5450 brcmf_p2p_notify_action_tx_complete);
5b435de0
AS
5451}
5452
27a68fe3
AS
5453static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
5454{
27a68fe3
AS
5455 kfree(cfg->conf);
5456 cfg->conf = NULL;
27a68fe3
AS
5457 kfree(cfg->extra_buf);
5458 cfg->extra_buf = NULL;
3021ad9a
HM
5459 kfree(cfg->wowl.nd);
5460 cfg->wowl.nd = NULL;
5461 kfree(cfg->wowl.nd_info);
5462 cfg->wowl.nd_info = NULL;
d5367334
HM
5463 kfree(cfg->escan_info.escan_buf);
5464 cfg->escan_info.escan_buf = NULL;
27a68fe3
AS
5465}
5466
5467static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
5468{
27a68fe3
AS
5469 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5470 if (!cfg->conf)
5b435de0 5471 goto init_priv_mem_out;
27a68fe3
AS
5472 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5473 if (!cfg->extra_buf)
5b435de0 5474 goto init_priv_mem_out;
3021ad9a
HM
5475 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5476 if (!cfg->wowl.nd)
5477 goto init_priv_mem_out;
5478 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5479 sizeof(struct cfg80211_wowlan_nd_match *),
5480 GFP_KERNEL);
5481 if (!cfg->wowl.nd_info)
5482 goto init_priv_mem_out;
d5367334
HM
5483 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5484 if (!cfg->escan_info.escan_buf)
5485 goto init_priv_mem_out;
5b435de0
AS
5486
5487 return 0;
5488
5489init_priv_mem_out:
27a68fe3 5490 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
5491
5492 return -ENOMEM;
5493}
5494
27a68fe3 5495static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5496{
5497 s32 err = 0;
5498
27a68fe3
AS
5499 cfg->scan_request = NULL;
5500 cfg->pwr_save = true;
68ca395f
HM
5501 cfg->active_scan = true; /* we do active scan per default */
5502 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 5503 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
5504 if (err)
5505 return err;
5c36b99a 5506 brcmf_register_event_handlers(cfg);
27a68fe3 5507 mutex_init(&cfg->usr_sync);
27a68fe3
AS
5508 brcmf_init_escan(cfg);
5509 brcmf_init_conf(cfg->conf);
5f4f9f11 5510 init_completion(&cfg->vif_disabled);
5b435de0
AS
5511 return err;
5512}
5513
27a68fe3 5514static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 5515{
27a68fe3 5516 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
5517 brcmf_abort_scanning(cfg);
5518 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
5519}
5520
d3c0b633
AS
5521static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5522{
5523 init_waitqueue_head(&event->vif_wq);
d3c0b633
AS
5524 mutex_init(&event->vif_event_lock);
5525}
5526
1119e23e 5527static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
5b435de0 5528{
1119e23e
HM
5529 s32 err;
5530 u32 bcn_timeout;
f588bc0c
AS
5531 __le32 roamtrigger[2];
5532 __le32 roam_delta[2];
5b435de0 5533
1119e23e 5534 /* Configure beacon timeout value based upon roaming setting */
7d34b056 5535 if (ifp->drvr->settings->roamoff)
1119e23e
HM
5536 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5537 else
5538 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5539 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5540 if (err) {
5541 brcmf_err("bcn_timeout error (%d)\n", err);
5542 goto roam_setup_done;
5b435de0
AS
5543 }
5544
1119e23e
HM
5545 /* Enable/Disable built-in roaming to allow supplicant to take care of
5546 * roaming.
5b435de0 5547 */
68ca395f 5548 brcmf_dbg(INFO, "Internal Roaming = %s\n",
7d34b056
HM
5549 ifp->drvr->settings->roamoff ? "Off" : "On");
5550 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5551 ifp->drvr->settings->roamoff);
5b435de0 5552 if (err) {
57d6e91a 5553 brcmf_err("roam_off error (%d)\n", err);
1119e23e 5554 goto roam_setup_done;
5b435de0
AS
5555 }
5556
f588bc0c
AS
5557 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5558 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5559 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 5560 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0 5561 if (err) {
57d6e91a 5562 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
1119e23e 5563 goto roam_setup_done;
5b435de0
AS
5564 }
5565
f588bc0c
AS
5566 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5567 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5568 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 5569 (void *)roam_delta, sizeof(roam_delta));
5b435de0 5570 if (err) {
57d6e91a 5571 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
1119e23e 5572 goto roam_setup_done;
5b435de0
AS
5573 }
5574
1119e23e 5575roam_setup_done:
5b435de0
AS
5576 return err;
5577}
5578
5579static s32
1678ba8e 5580brcmf_dongle_scantime(struct brcmf_if *ifp)
5b435de0
AS
5581{
5582 s32 err = 0;
5583
ac24be6f 5584 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
1678ba8e 5585 BRCMF_SCAN_CHANNEL_TIME);
5b435de0 5586 if (err) {
1678ba8e 5587 brcmf_err("Scan assoc time error (%d)\n", err);
5b435de0
AS
5588 goto dongle_scantime_out;
5589 }
ac24be6f 5590 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
1678ba8e 5591 BRCMF_SCAN_UNASSOC_TIME);
5b435de0 5592 if (err) {
1678ba8e 5593 brcmf_err("Scan unassoc time error (%d)\n", err);
5b435de0
AS
5594 goto dongle_scantime_out;
5595 }
5596
ac24be6f 5597 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
1678ba8e 5598 BRCMF_SCAN_PASSIVE_TIME);
5b435de0 5599 if (err) {
1678ba8e 5600 brcmf_err("Scan passive time error (%d)\n", err);
5b435de0
AS
5601 goto dongle_scantime_out;
5602 }
5603
5604dongle_scantime_out:
5605 return err;
5606}
5607
b48d8916
AS
5608static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5609 struct brcmu_chan *ch)
5610{
5611 u32 ht40_flag;
d48200ba 5612
b48d8916
AS
5613 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5614 if (ch->sb == BRCMU_CHAN_SB_U) {
5615 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5616 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5617 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5618 } else {
5619 /* It should be one of
5620 * IEEE80211_CHAN_NO_HT40 or
5621 * IEEE80211_CHAN_NO_HT40PLUS
5622 */
5623 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5624 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5625 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5626 }
5627}
5628
5629static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5630 u32 bw_cap[])
d48200ba
HM
5631{
5632 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
b48d8916
AS
5633 struct ieee80211_supported_band *band;
5634 struct ieee80211_channel *channel;
5635 struct wiphy *wiphy;
d48200ba 5636 struct brcmf_chanspec_list *list;
83cf17aa 5637 struct brcmu_chan ch;
b48d8916 5638 int err;
d48200ba
HM
5639 u8 *pbuf;
5640 u32 i, j;
5641 u32 total;
b48d8916 5642 u32 chaninfo;
d48200ba 5643 u32 index;
d48200ba
HM
5644
5645 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5646
5647 if (pbuf == NULL)
5648 return -ENOMEM;
5649
5650 list = (struct brcmf_chanspec_list *)pbuf;
5651
5652 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5653 BRCMF_DCMD_MEDLEN);
5654 if (err) {
5655 brcmf_err("get chanspecs error (%d)\n", err);
b48d8916 5656 goto fail_pbuf;
d48200ba
HM
5657 }
5658
b48d8916 5659 wiphy = cfg_to_wiphy(cfg);
58de92d2
AS
5660 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5661 if (band)
5662 for (i = 0; i < band->n_channels; i++)
5663 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5664 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5665 if (band)
5666 for (i = 0; i < band->n_channels; i++)
5667 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
d48200ba
HM
5668
5669 total = le32_to_cpu(list->count);
5670 for (i = 0; i < total; i++) {
83cf17aa
FL
5671 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5672 cfg->d11inf.decchspec(&ch);
d48200ba 5673
83cf17aa 5674 if (ch.band == BRCMU_CHAN_BAND_2G) {
b48d8916 5675 band = wiphy->bands[IEEE80211_BAND_2GHZ];
83cf17aa 5676 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
b48d8916 5677 band = wiphy->bands[IEEE80211_BAND_5GHZ];
d48200ba 5678 } else {
2375d970 5679 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
d48200ba
HM
5680 continue;
5681 }
58de92d2
AS
5682 if (!band)
5683 continue;
b48d8916 5684 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
2375d970 5685 ch.bw == BRCMU_CHAN_BW_40)
d48200ba 5686 continue;
b48d8916 5687 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
ee942ecc
AS
5688 ch.bw == BRCMU_CHAN_BW_80)
5689 continue;
b48d8916
AS
5690
5691 channel = band->channels;
5692 index = band->n_channels;
5693 for (j = 0; j < band->n_channels; j++) {
5694 if (channel[j].hw_value == ch.chnum) {
5695 index = j;
d48200ba
HM
5696 break;
5697 }
5698 }
b48d8916
AS
5699 channel[index].center_freq =
5700 ieee80211_channel_to_frequency(ch.chnum, band->band);
5701 channel[index].hw_value = ch.chnum;
5702
5703 /* assuming the chanspecs order is HT20,
5704 * HT40 upper, HT40 lower, and VHT80.
5705 */
5706 if (ch.bw == BRCMU_CHAN_BW_80) {
5707 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5708 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5709 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5710 } else {
58de92d2
AS
5711 /* enable the channel and disable other bandwidths
5712 * for now as mentioned order assure they are enabled
5713 * for subsequent chanspecs.
ee942ecc 5714 */
b48d8916
AS
5715 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5716 IEEE80211_CHAN_NO_80MHZ;
5717 ch.bw = BRCMU_CHAN_BW_20;
5718 cfg->d11inf.encchspec(&ch);
5719 chaninfo = ch.chspec;
5720 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5721 &chaninfo);
5722 if (!err) {
5723 if (chaninfo & WL_CHAN_RADAR)
5724 channel[index].flags |=
5725 (IEEE80211_CHAN_RADAR |
5726 IEEE80211_CHAN_NO_IR);
5727 if (chaninfo & WL_CHAN_PASSIVE)
5728 channel[index].flags |=
5729 IEEE80211_CHAN_NO_IR;
d48200ba 5730 }
d48200ba
HM
5731 }
5732 }
b48d8916 5733
b48d8916 5734fail_pbuf:
d48200ba
HM
5735 kfree(pbuf);
5736 return err;
5737}
5738
b48d8916 5739static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
aa70b4fa 5740{
b48d8916
AS
5741 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5742 struct ieee80211_supported_band *band;
aa70b4fa 5743 struct brcmf_fil_bwcap_le band_bwcap;
b48d8916
AS
5744 struct brcmf_chanspec_list *list;
5745 u8 *pbuf;
aa70b4fa
AS
5746 u32 val;
5747 int err;
b48d8916
AS
5748 struct brcmu_chan ch;
5749 u32 num_chan;
5750 int i, j;
aa70b4fa
AS
5751
5752 /* verify support for bw_cap command */
5753 val = WLC_BAND_5G;
5754 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5755
5756 if (!err) {
5757 /* only set 2G bandwidth using bw_cap command */
5758 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5759 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5760 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5761 sizeof(band_bwcap));
5762 } else {
5763 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5764 val = WLC_N_BW_40ALL;
5765 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5766 }
b48d8916
AS
5767
5768 if (!err) {
5769 /* update channel info in 2G band */
5770 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5771
5772 if (pbuf == NULL)
5773 return -ENOMEM;
5774
5775 ch.band = BRCMU_CHAN_BAND_2G;
5776 ch.bw = BRCMU_CHAN_BW_40;
fac7d2a3 5777 ch.sb = BRCMU_CHAN_SB_NONE;
b48d8916
AS
5778 ch.chnum = 0;
5779 cfg->d11inf.encchspec(&ch);
5780
5781 /* pass encoded chanspec in query */
5782 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5783
5784 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5785 BRCMF_DCMD_MEDLEN);
5786 if (err) {
5787 brcmf_err("get chanspecs error (%d)\n", err);
5788 kfree(pbuf);
5789 return err;
5790 }
5791
5792 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5793 list = (struct brcmf_chanspec_list *)pbuf;
5794 num_chan = le32_to_cpu(list->count);
5795 for (i = 0; i < num_chan; i++) {
5796 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5797 cfg->d11inf.decchspec(&ch);
5798 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5799 continue;
5800 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5801 continue;
5802 for (j = 0; j < band->n_channels; j++) {
5803 if (band->channels[j].hw_value == ch.chnum)
5804 break;
5805 }
5806 if (WARN_ON(j == band->n_channels))
5807 continue;
5808
5809 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5810 }
fac7d2a3 5811 kfree(pbuf);
b48d8916 5812 }
aa70b4fa
AS
5813 return err;
5814}
5815
2375d970
AS
5816static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5817{
5818 u32 band, mimo_bwcap;
5819 int err;
5820
5821 band = WLC_BAND_2G;
5822 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5823 if (!err) {
5824 bw_cap[IEEE80211_BAND_2GHZ] = band;
5825 band = WLC_BAND_5G;
5826 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5827 if (!err) {
5828 bw_cap[IEEE80211_BAND_5GHZ] = band;
5829 return;
5830 }
5831 WARN_ON(1);
5832 return;
5833 }
5834 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5835 mimo_bwcap = 0;
5836 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5837 if (err)
5838 /* assume 20MHz if firmware does not give a clue */
5839 mimo_bwcap = WLC_N_BW_20ALL;
5840
5841 switch (mimo_bwcap) {
5842 case WLC_N_BW_40ALL:
5843 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5844 /* fall-thru */
5845 case WLC_N_BW_20IN2G_40IN5G:
5846 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5847 /* fall-thru */
5848 case WLC_N_BW_20ALL:
5849 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5850 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5851 break;
5852 default:
5853 brcmf_err("invalid mimo_bw_cap value\n");
5854 }
5855}
d48200ba 5856
18d6c535
AS
5857static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5858 u32 bw_cap[2], u32 nchain)
5859{
5860 band->ht_cap.ht_supported = true;
5861 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5862 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5863 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5864 }
5865 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5866 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5867 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5868 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5869 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5870 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5871}
5872
5873static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5874{
5875 u16 mcs_map;
5876 int i;
5877
5878 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5879 mcs_map = (mcs_map << 2) | supp;
5880
5881 return cpu_to_le16(mcs_map);
5882}
5883
5884static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
7bf65aa9
HM
5885 u32 bw_cap[2], u32 nchain, u32 txstreams,
5886 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
18d6c535
AS
5887{
5888 __le16 mcs_map;
5889
5890 /* not allowed in 2.4G band */
5891 if (band->band == IEEE80211_BAND_2GHZ)
5892 return;
5893
5894 band->vht_cap.vht_supported = true;
5895 /* 80MHz is mandatory */
5896 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5897 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5898 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5899 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5900 }
5901 /* all support 256-QAM */
5902 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5903 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5904 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
7bf65aa9
HM
5905
5906 /* Beamforming support information */
5907 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
5908 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
5909 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
5910 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
5911 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
5912 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
5913 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
5914 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
5915
5916 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
5917 band->vht_cap.cap |=
5918 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
5919 band->vht_cap.cap |= ((txstreams - 1) <<
5920 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
5921 band->vht_cap.cap |=
5922 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
5923 }
18d6c535
AS
5924}
5925
b48d8916 5926static int brcmf_setup_wiphybands(struct wiphy *wiphy)
5b435de0 5927{
b48d8916 5928 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
ac24be6f 5929 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
18d6c535
AS
5930 u32 nmode = 0;
5931 u32 vhtmode = 0;
b48d8916 5932 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
4aca7a18
DK
5933 u32 rxchain;
5934 u32 nchain;
b48d8916 5935 int err;
d48200ba 5936 s32 i;
2375d970 5937 struct ieee80211_supported_band *band;
7bf65aa9
HM
5938 u32 txstreams = 0;
5939 u32 txbf_bfe_cap = 0;
5940 u32 txbf_bfr_cap = 0;
5b435de0 5941
18d6c535 5942 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
d48200ba
HM
5943 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5944 if (err) {
5945 brcmf_err("nmode error (%d)\n", err);
5946 } else {
2375d970 5947 brcmf_get_bwcap(ifp, bw_cap);
d48200ba 5948 }
18d6c535
AS
5949 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5950 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5951 bw_cap[IEEE80211_BAND_5GHZ]);
d48200ba 5952
4aca7a18
DK
5953 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5954 if (err) {
5955 brcmf_err("rxchain error (%d)\n", err);
5956 nchain = 1;
5957 } else {
5958 for (nchain = 0; rxchain; nchain++)
5959 rxchain = rxchain & (rxchain - 1);
5960 }
5961 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5962
b48d8916 5963 err = brcmf_construct_chaninfo(cfg, bw_cap);
d48200ba 5964 if (err) {
b48d8916 5965 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
d48200ba
HM
5966 return err;
5967 }
5968
7bf65aa9
HM
5969 if (vhtmode) {
5970 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
5971 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
5972 &txbf_bfe_cap);
5973 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
5974 &txbf_bfr_cap);
5975 }
5976
b48d8916
AS
5977 wiphy = cfg_to_wiphy(cfg);
5978 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5979 band = wiphy->bands[i];
5980 if (band == NULL)
2375d970 5981 continue;
d48200ba 5982
18d6c535
AS
5983 if (nmode)
5984 brcmf_update_ht_cap(band, bw_cap, nchain);
5985 if (vhtmode)
7bf65aa9
HM
5986 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
5987 txbf_bfe_cap, txbf_bfr_cap);
d48200ba
HM
5988 }
5989
b48d8916 5990 return 0;
5b435de0
AS
5991}
5992
aa70b4fa
AS
5993static const struct ieee80211_txrx_stypes
5994brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5995 [NL80211_IFTYPE_STATION] = {
5996 .tx = 0xffff,
5997 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5998 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5999 },
6000 [NL80211_IFTYPE_P2P_CLIENT] = {
6001 .tx = 0xffff,
6002 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6003 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6004 },
6005 [NL80211_IFTYPE_P2P_GO] = {
6006 .tx = 0xffff,
6007 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6008 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6009 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6010 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6011 BIT(IEEE80211_STYPE_AUTH >> 4) |
6012 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6013 BIT(IEEE80211_STYPE_ACTION >> 4)
6014 },
6015 [NL80211_IFTYPE_P2P_DEVICE] = {
6016 .tx = 0xffff,
6017 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6018 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6019 }
6020};
6021
0882dda3
AS
6022/**
6023 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6024 *
6025 * @wiphy: wiphy object.
6026 * @ifp: interface object needed for feat module api.
6027 *
6028 * The interface modes and combinations are determined dynamically here
6029 * based on firmware functionality.
6030 *
6031 * no p2p and no mbss:
6032 *
6033 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6034 *
6035 * no p2p and mbss:
6036 *
6037 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6038 * #AP <= 4, matching BI, channels = 1, 4 total
6039 *
6040 * p2p, no mchan, and mbss:
6041 *
6042 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6043 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6044 * #AP <= 4, matching BI, channels = 1, 4 total
6045 *
6046 * p2p, mchan, and mbss:
6047 *
6048 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6049 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6050 * #AP <= 4, matching BI, channels = 1, 4 total
6051 */
2e5f66fe
PF
6052static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6053{
6054 struct ieee80211_iface_combination *combo = NULL;
0882dda3
AS
6055 struct ieee80211_iface_limit *c0_limits = NULL;
6056 struct ieee80211_iface_limit *p2p_limits = NULL;
6057 struct ieee80211_iface_limit *mbss_limits = NULL;
6058 bool mbss, p2p;
6059 int i, c, n_combos;
6060
6061 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6062 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
2e5f66fe 6063
0882dda3
AS
6064 n_combos = 1 + !!p2p + !!mbss;
6065 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
2e5f66fe
PF
6066 if (!combo)
6067 goto err;
6068
0882dda3
AS
6069 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6070 if (!c0_limits)
2e5f66fe
PF
6071 goto err;
6072
0882dda3
AS
6073 if (p2p) {
6074 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6075 if (!p2p_limits)
6076 goto err;
6077 }
6078
6079 if (mbss) {
6080 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6081 if (!mbss_limits)
6082 goto err;
6083 }
6084
2e5f66fe
PF
6085 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6086 BIT(NL80211_IFTYPE_ADHOC) |
6087 BIT(NL80211_IFTYPE_AP);
6088
0882dda3
AS
6089 c = 0;
6090 i = 0;
6091 combo[c].num_different_channels = 1;
6092 c0_limits[i].max = 1;
6093 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6094 if (p2p) {
6095 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6096 combo[c].num_different_channels = 2;
2e5f66fe
PF
6097 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6098 BIT(NL80211_IFTYPE_P2P_GO) |
6099 BIT(NL80211_IFTYPE_P2P_DEVICE);
0882dda3
AS
6100 c0_limits[i].max = 1;
6101 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6102 c0_limits[i].max = 1;
6103 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6104 BIT(NL80211_IFTYPE_P2P_GO);
6105 } else {
6106 c0_limits[i].max = 1;
6107 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6108 }
6109 combo[c].max_interfaces = i;
6110 combo[c].n_limits = i;
6111 combo[c].limits = c0_limits;
6112
6113 if (p2p) {
6114 c++;
6115 i = 0;
6116 combo[c].num_different_channels = 1;
6117 p2p_limits[i].max = 1;
6118 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6119 p2p_limits[i].max = 1;
6120 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6121 p2p_limits[i].max = 1;
6122 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6123 p2p_limits[i].max = 1;
6124 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6125 combo[c].max_interfaces = i;
6126 combo[c].n_limits = i;
6127 combo[c].limits = p2p_limits;
6128 }
6129
6130 if (mbss) {
6131 c++;
6132 combo[c].beacon_int_infra_match = true;
6133 combo[c].num_different_channels = 1;
6134 mbss_limits[0].max = 4;
6135 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
6136 combo[c].max_interfaces = 4;
6137 combo[c].n_limits = 1;
6138 combo[c].limits = mbss_limits;
6139 }
6140 wiphy->n_iface_combinations = n_combos;
2e5f66fe 6141 wiphy->iface_combinations = combo;
2e5f66fe
PF
6142 return 0;
6143
6144err:
0882dda3
AS
6145 kfree(c0_limits);
6146 kfree(p2p_limits);
6147 kfree(mbss_limits);
2e5f66fe
PF
6148 kfree(combo);
6149 return -ENOMEM;
6150}
6151
aa70b4fa
AS
6152static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6153{
6154 /* scheduled scan settings */
6155 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6156 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6157 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6158 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6159}
6160
4eb3af7c 6161#ifdef CONFIG_PM
3021ad9a 6162static struct wiphy_wowlan_support brcmf_wowlan_support = {
4eb3af7c 6163 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
b9a82f89
HM
6164 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6165 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6166 .pattern_min_len = 1,
6167 .max_pkt_offset = 1500,
4eb3af7c
HM
6168};
6169#endif
6170
3021ad9a 6171static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
4eb3af7c
HM
6172{
6173#ifdef CONFIG_PM
3021ad9a 6174 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3021ad9a
HM
6175
6176 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
5c22fb85
HM
6177 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6178 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6179 init_waitqueue_head(&cfg->wowl.nd_data_wait);
3021ad9a
HM
6180 }
6181 }
5c22fb85
HM
6182 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6183 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6184 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6185 }
6186
4eb3af7c
HM
6187 wiphy->wowlan = &brcmf_wowlan_support;
6188#endif
6189}
6190
b48d8916 6191static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
aa70b4fa 6192{
e3faa866 6193 struct brcmf_pub *drvr = ifp->drvr;
50f32e2d 6194 const struct ieee80211_iface_combination *combo;
58de92d2 6195 struct ieee80211_supported_band *band;
50f32e2d 6196 u16 max_interfaces = 0;
58de92d2
AS
6197 __le32 bandlist[3];
6198 u32 n_bands;
6199 int err, i;
6200
aa70b4fa
AS
6201 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6202 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6c404f34 6203 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
2e5f66fe
PF
6204
6205 err = brcmf_setup_ifmodes(wiphy, ifp);
6206 if (err)
6207 return err;
6208
50f32e2d
RM
6209 for (i = 0, combo = wiphy->iface_combinations;
6210 i < wiphy->n_iface_combinations; i++, combo++) {
6211 max_interfaces = max(max_interfaces, combo->max_interfaces);
6212 }
6213
6214 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6215 i++) {
e3faa866
RM
6216 u8 *addr = drvr->addresses[i].addr;
6217
6218 memcpy(addr, drvr->mac, ETH_ALEN);
6219 if (i) {
6220 addr[0] |= BIT(1);
6221 addr[ETH_ALEN - 1] ^= i;
6222 }
6223 }
6224 wiphy->addresses = drvr->addresses;
6225 wiphy->n_addresses = i;
6226
aa70b4fa
AS
6227 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
6228 wiphy->cipher_suites = __wl_cipher_suites;
6229 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
6230 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6231 WIPHY_FLAG_OFFCHAN_TX |
a7b82d47
HM
6232 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6233 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6234 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
7d34b056 6235 if (!ifp->drvr->settings->roamoff)
aa70b4fa
AS
6236 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6237 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6238 wiphy->max_remain_on_channel_duration = 5000;
7a7a87dc
AS
6239 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6240 brcmf_wiphy_pno_params(wiphy);
aa70b4fa
AS
6241
6242 /* vendor commands/events support */
6243 wiphy->vendor_commands = brcmf_vendor_cmds;
6244 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6245
4eb3af7c 6246 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
3021ad9a 6247 brcmf_wiphy_wowl_params(wiphy, ifp);
58de92d2
AS
6248 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6249 sizeof(bandlist));
6250 if (err) {
6251 brcmf_err("could not obtain band info: err=%d\n", err);
6252 return err;
6253 }
6254 /* first entry in bandlist is number of bands */
6255 n_bands = le32_to_cpu(bandlist[0]);
6256 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6257 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6258 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6259 GFP_KERNEL);
6260 if (!band)
6261 return -ENOMEM;
6262
6263 band->channels = kmemdup(&__wl_2ghz_channels,
6264 sizeof(__wl_2ghz_channels),
6265 GFP_KERNEL);
6266 if (!band->channels) {
6267 kfree(band);
6268 return -ENOMEM;
6269 }
6270
6271 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
6272 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
6273 }
6274 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6275 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6276 GFP_KERNEL);
6277 if (!band)
6278 return -ENOMEM;
6279
6280 band->channels = kmemdup(&__wl_5ghz_channels,
6281 sizeof(__wl_5ghz_channels),
6282 GFP_KERNEL);
6283 if (!band->channels) {
6284 kfree(band);
6285 return -ENOMEM;
6286 }
6287
6288 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
6289 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
6290 }
6291 }
6292 err = brcmf_setup_wiphybands(wiphy);
6293 return err;
5b435de0
AS
6294}
6295
27a68fe3 6296static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
6297{
6298 struct net_device *ndev;
6299 struct wireless_dev *wdev;
40a23296 6300 struct brcmf_if *ifp;
5b435de0
AS
6301 s32 power_mode;
6302 s32 err = 0;
6303
27a68fe3 6304 if (cfg->dongle_up)
5b435de0
AS
6305 return err;
6306
27a68fe3 6307 ndev = cfg_to_ndev(cfg);
5b435de0 6308 wdev = ndev->ieee80211_ptr;
40a23296
HM
6309 ifp = netdev_priv(ndev);
6310
6311 /* make sure RF is ready for work */
6312 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5b435de0 6313
1678ba8e 6314 brcmf_dongle_scantime(ifp);
5b435de0 6315
27a68fe3 6316 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
40a23296 6317 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5b435de0
AS
6318 if (err)
6319 goto default_conf_out;
647c9ae0
AS
6320 brcmf_dbg(INFO, "power save set to %s\n",
6321 (power_mode ? "enabled" : "disabled"));
5b435de0 6322
1119e23e 6323 err = brcmf_dongle_roam(ifp);
5b435de0
AS
6324 if (err)
6325 goto default_conf_out;
5dd161ff
FL
6326 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6327 NULL, NULL);
40a23296 6328 if (err)
5b435de0 6329 goto default_conf_out;
5b435de0 6330
52f22fb2 6331 brcmf_configure_arp_nd_offload(ifp, true);
b3657453 6332
27a68fe3 6333 cfg->dongle_up = true;
40a23296 6334default_conf_out:
5b435de0
AS
6335
6336 return err;
6337
6338}
6339
bdf5ff51 6340static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5b435de0 6341{
c1179033 6342 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 6343
bdf5ff51 6344 return brcmf_config_dongle(ifp->drvr->config);
5b435de0
AS
6345}
6346
bdf5ff51 6347static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5b435de0 6348{
bdf5ff51 6349 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
c1179033 6350
5b435de0
AS
6351 /*
6352 * While going down, if associated with AP disassociate
6353 * from AP to save power
6354 */
903e0eee 6355 if (check_vif_up(ifp->vif)) {
9b7a0ddc 6356 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
5b435de0
AS
6357
6358 /* Make sure WPA_Supplicant receives all the event
6359 generated due to DISASSOC call to the fw to keep
6360 the state fw and WPA_Supplicant state consistent
6361 */
6362 brcmf_delay(500);
6363 }
6364
27a68fe3 6365 brcmf_abort_scanning(cfg);
c1179033 6366 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 6367
5b435de0
AS
6368 return 0;
6369}
6370
bdf5ff51 6371s32 brcmf_cfg80211_up(struct net_device *ndev)
5b435de0 6372{
bdf5ff51
AS
6373 struct brcmf_if *ifp = netdev_priv(ndev);
6374 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
6375 s32 err = 0;
6376
27a68fe3 6377 mutex_lock(&cfg->usr_sync);
bdf5ff51 6378 err = __brcmf_cfg80211_up(ifp);
27a68fe3 6379 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
6380
6381 return err;
6382}
6383
bdf5ff51 6384s32 brcmf_cfg80211_down(struct net_device *ndev)
5b435de0 6385{
bdf5ff51
AS
6386 struct brcmf_if *ifp = netdev_priv(ndev);
6387 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
6388 s32 err = 0;
6389
27a68fe3 6390 mutex_lock(&cfg->usr_sync);
bdf5ff51 6391 err = __brcmf_cfg80211_down(ifp);
27a68fe3 6392 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
6393
6394 return err;
6395}
6396
a7965fbb
AS
6397enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6398{
6399 struct wireless_dev *wdev = &ifp->vif->wdev;
6400
6401 return wdev->iftype;
6402}
6403
bfe81975
HM
6404bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6405 unsigned long state)
9f440b7b
AS
6406{
6407 struct brcmf_cfg80211_vif *vif;
9f440b7b
AS
6408
6409 list_for_each_entry(vif, &cfg->vif_list, list) {
6410 if (test_bit(state, &vif->sme_state))
e843bb19 6411 return true;
9f440b7b 6412 }
e843bb19 6413 return false;
9f440b7b 6414}
d3c0b633
AS
6415
6416static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6417 u8 action)
6418{
6419 u8 evt_action;
6420
6421 mutex_lock(&event->vif_event_lock);
6422 evt_action = event->action;
6423 mutex_unlock(&event->vif_event_lock);
6424 return evt_action == action;
6425}
6426
6427void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6428 struct brcmf_cfg80211_vif *vif)
6429{
6430 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6431
6432 mutex_lock(&event->vif_event_lock);
6433 event->vif = vif;
6434 event->action = 0;
6435 mutex_unlock(&event->vif_event_lock);
6436}
6437
6438bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6439{
6440 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6441 bool armed;
6442
6443 mutex_lock(&event->vif_event_lock);
6444 armed = event->vif != NULL;
6445 mutex_unlock(&event->vif_event_lock);
6446
6447 return armed;
6448}
a9eb0c4b
AS
6449
6450int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6451 u8 action, ulong timeout)
d3c0b633
AS
6452{
6453 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6454
6455 return wait_event_timeout(event->vif_wq,
6456 vif_event_equals(event, action), timeout);
6457}
6458
73345fd2
HM
6459static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6460 struct brcmf_fil_country_le *ccreq)
6461{
4d792895
HM
6462 struct brcmfmac_pd_cc *country_codes;
6463 struct brcmfmac_pd_cc_entry *cc;
73345fd2
HM
6464 s32 found_index;
6465 int i;
6466
6467 country_codes = drvr->settings->country_codes;
6468 if (!country_codes) {
6469 brcmf_dbg(TRACE, "No country codes configured for device\n");
6470 return -EINVAL;
6471 }
6472
6473 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6474 (alpha2[1] == ccreq->country_abbrev[1])) {
6475 brcmf_dbg(TRACE, "Country code already set\n");
6476 return -EAGAIN;
6477 }
6478
6479 found_index = -1;
6480 for (i = 0; i < country_codes->table_size; i++) {
6481 cc = &country_codes->table[i];
6482 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6483 found_index = i;
6484 if ((cc->iso3166[0] == alpha2[0]) &&
6485 (cc->iso3166[1] == alpha2[1])) {
6486 found_index = i;
6487 break;
6488 }
6489 }
6490 if (found_index == -1) {
6491 brcmf_dbg(TRACE, "No country code match found\n");
6492 return -EINVAL;
6493 }
6494 memset(ccreq, 0, sizeof(*ccreq));
6495 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6496 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6497 BRCMF_COUNTRY_BUF_SZ);
6498 ccreq->country_abbrev[0] = alpha2[0];
6499 ccreq->country_abbrev[1] = alpha2[1];
6500 ccreq->country_abbrev[2] = 0;
6501
6502 return 0;
6503}
6504
63db1a49
AS
6505static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6506 struct regulatory_request *req)
6507{
6508 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6509 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6510 struct brcmf_fil_country_le ccreq;
73345fd2 6511 s32 err;
63db1a49
AS
6512 int i;
6513
63db1a49
AS
6514 /* ignore non-ISO3166 country codes */
6515 for (i = 0; i < sizeof(req->alpha2); i++)
6516 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
73345fd2
HM
6517 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6518 req->alpha2[0], req->alpha2[1]);
63db1a49
AS
6519 return;
6520 }
73345fd2
HM
6521
6522 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6523 req->alpha2[0], req->alpha2[1]);
6524
6525 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6526 if (err) {
6527 brcmf_err("Country code iovar returned err = %d\n", err);
6528 return;
6529 }
6530
6531 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6532 if (err)
6533 return;
6534
6535 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6536 if (err) {
6537 brcmf_err("Firmware rejected country setting\n");
8afe0ece
AS
6538 return;
6539 }
6540 brcmf_setup_wiphybands(wiphy);
63db1a49
AS
6541}
6542
b48d8916
AS
6543static void brcmf_free_wiphy(struct wiphy *wiphy)
6544{
0882dda3
AS
6545 int i;
6546
58de92d2
AS
6547 if (!wiphy)
6548 return;
6549
0882dda3
AS
6550 if (wiphy->iface_combinations) {
6551 for (i = 0; i < wiphy->n_iface_combinations; i++)
6552 kfree(wiphy->iface_combinations[i].limits);
6553 }
b48d8916
AS
6554 kfree(wiphy->iface_combinations);
6555 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6556 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6557 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6558 }
6559 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6560 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6561 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6562 }
6563 wiphy_free(wiphy);
6564}
6565
ccfd1e81 6566struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
ae7c03f6
HM
6567 struct device *busdev,
6568 bool p2pdev_forced)
ccfd1e81 6569{
46f3b6ee 6570 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
ccfd1e81
AS
6571 struct brcmf_cfg80211_info *cfg;
6572 struct wiphy *wiphy;
5c22fb85 6573 struct cfg80211_ops *ops;
ccfd1e81
AS
6574 struct brcmf_cfg80211_vif *vif;
6575 struct brcmf_if *ifp;
6576 s32 err = 0;
6577 s32 io_type;
b48d8916 6578 u16 *cap = NULL;
ccfd1e81
AS
6579
6580 if (!ndev) {
6581 brcmf_err("ndev is invalid\n");
6582 return NULL;
6583 }
6584
5c22fb85
HM
6585 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
6586 if (!ops)
6587 return NULL;
6588
6589 memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
ccfd1e81 6590 ifp = netdev_priv(ndev);
5c22fb85
HM
6591#ifdef CONFIG_PM
6592 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6593 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6594#endif
6595 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
b48d8916
AS
6596 if (!wiphy) {
6597 brcmf_err("Could not allocate wiphy device\n");
ccfd1e81 6598 return NULL;
b48d8916 6599 }
6896f4fb 6600 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
b48d8916 6601 set_wiphy_dev(wiphy, busdev);
ccfd1e81
AS
6602
6603 cfg = wiphy_priv(wiphy);
6604 cfg->wiphy = wiphy;
5c22fb85 6605 cfg->ops = ops;
ccfd1e81
AS
6606 cfg->pub = drvr;
6607 init_vif_event(&cfg->vif_event);
6608 INIT_LIST_HEAD(&cfg->vif_list);
6609
6610 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
b48d8916
AS
6611 if (IS_ERR(vif))
6612 goto wiphy_out;
ccfd1e81
AS
6613
6614 vif->ifp = ifp;
6615 vif->wdev.netdev = ndev;
6616 ndev->ieee80211_ptr = &vif->wdev;
6617 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6618
6619 err = wl_init_priv(cfg);
6620 if (err) {
6621 brcmf_err("Failed to init iwm_priv (%d)\n", err);
b48d8916
AS
6622 brcmf_free_vif(vif);
6623 goto wiphy_out;
ccfd1e81
AS
6624 }
6625 ifp->vif = vif;
6626
b48d8916
AS
6627 /* determine d11 io type before wiphy setup */
6628 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
ccfd1e81 6629 if (err) {
b48d8916
AS
6630 brcmf_err("Failed to get D11 version (%d)\n", err);
6631 goto priv_out;
ccfd1e81 6632 }
b48d8916
AS
6633 cfg->d11inf.io_type = (u8)io_type;
6634 brcmu_d11_attach(&cfg->d11inf);
6635
6636 err = brcmf_setup_wiphy(wiphy, ifp);
6637 if (err < 0)
6638 goto priv_out;
6639
6640 brcmf_dbg(INFO, "Registering custom regulatory\n");
63db1a49 6641 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
b48d8916
AS
6642 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6643 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6644
6645 /* firmware defaults to 40MHz disabled in 2G band. We signal
6646 * cfg80211 here that we do and have it decide we can enable
6647 * it. But first check if device does support 2G operation.
6648 */
6649 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6650 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6651 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6652 }
6653 err = wiphy_register(wiphy);
6654 if (err < 0) {
6655 brcmf_err("Could not register wiphy device (%d)\n", err);
6656 goto priv_out;
ccfd1e81
AS
6657 }
6658
6659 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6660 * setup 40MHz in 2GHz band and enable OBSS scanning.
6661 */
b48d8916
AS
6662 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6663 err = brcmf_enable_bw40_2g(cfg);
ccfd1e81
AS
6664 if (!err)
6665 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6666 BRCMF_OBSS_COEX_AUTO);
b48d8916
AS
6667 else
6668 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ccfd1e81 6669 }
2b76acdb
HM
6670 /* p2p might require that "if-events" get processed by fweh. So
6671 * activate the already registered event handlers now and activate
6672 * the rest when initialization has completed. drvr->config needs to
6673 * be assigned before activating events.
6674 */
6675 drvr->config = cfg;
6676 err = brcmf_fweh_activate_events(ifp);
6677 if (err) {
6678 brcmf_err("FWEH activation failed (%d)\n", err);
6679 goto wiphy_unreg_out;
6680 }
ccfd1e81 6681
ae7c03f6 6682 err = brcmf_p2p_attach(cfg, p2pdev_forced);
ccfd1e81 6683 if (err) {
b48d8916
AS
6684 brcmf_err("P2P initilisation failed (%d)\n", err);
6685 goto wiphy_unreg_out;
6686 }
6687 err = brcmf_btcoex_attach(cfg);
6688 if (err) {
6689 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6690 brcmf_p2p_detach(&cfg->p2p);
6691 goto wiphy_unreg_out;
ccfd1e81
AS
6692 }
6693
a7b82d47
HM
6694 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6695 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6696 if (err) {
6697 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6698 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6699 } else {
6700 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6701 brcmf_notify_tdls_peer_event);
6702 }
ccfd1e81 6703 }
ccfd1e81 6704
2b76acdb
HM
6705 /* (re-) activate FWEH event handling */
6706 err = brcmf_fweh_activate_events(ifp);
6707 if (err) {
6708 brcmf_err("FWEH activation failed (%d)\n", err);
6709 goto wiphy_unreg_out;
6710 }
6711
48ed16e8
HM
6712 /* Fill in some of the advertised nl80211 supported features */
6713 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6714 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6715#ifdef CONFIG_PM
6ea09153
FL
6716 if (wiphy->wowlan &&
6717 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
48ed16e8
HM
6718 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6719#endif
6720 }
6721
ccfd1e81
AS
6722 return cfg;
6723
b48d8916
AS
6724wiphy_unreg_out:
6725 wiphy_unregister(cfg->wiphy);
6726priv_out:
ccfd1e81 6727 wl_deinit_priv(cfg);
ccfd1e81 6728 brcmf_free_vif(vif);
2b5d348e 6729 ifp->vif = NULL;
b48d8916
AS
6730wiphy_out:
6731 brcmf_free_wiphy(wiphy);
5c22fb85 6732 kfree(ops);
ccfd1e81
AS
6733 return NULL;
6734}
6735
6736void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6737{
6738 if (!cfg)
6739 return;
6740
ccfd1e81 6741 brcmf_btcoex_detach(cfg);
f7a40873 6742 wiphy_unregister(cfg->wiphy);
5c22fb85 6743 kfree(cfg->ops);
ccfd1e81 6744 wl_deinit_priv(cfg);
b48d8916 6745 brcmf_free_wiphy(cfg->wiphy);
ccfd1e81 6746}