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