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