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