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