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