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