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