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