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