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