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