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