net: rfkill: move poll work to power efficient workqueue
[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 */
4b5800fe
JB
354const struct brcmf_tlv *
355brcmf_parse_tlvs(const void *buf, int buflen, uint key)
89286dc9 356{
4b5800fe
JB
357 const struct brcmf_tlv *elt = buf;
358 int totlen = buflen;
89286dc9
HM
359
360 /* find tagged parameter */
361 while (totlen >= TLV_HDR_LEN) {
362 int len = elt->len;
363
364 /* validate remaining totlen */
365 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
366 return elt;
367
368 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
369 totlen -= (len + TLV_HDR_LEN);
370 }
371
372 return NULL;
373}
374
375/* Is any of the tlvs the expected entry? If
376 * not update the tlvs buffer pointer/length.
377 */
378static bool
4b5800fe
JB
379brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
380 const u8 *oui, u32 oui_len, u8 type)
89286dc9
HM
381{
382 /* If the contents match the OUI and the type */
383 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
384 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
385 type == ie[TLV_BODY_OFF + oui_len]) {
386 return true;
387 }
388
389 if (tlvs == NULL)
390 return false;
391 /* point to the next ie */
392 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
393 /* calculate the length of the rest of the buffer */
394 *tlvs_len -= (int)(ie - *tlvs);
395 /* update the pointer to the start of the buffer */
396 *tlvs = ie;
397
398 return false;
399}
400
401static struct brcmf_vs_tlv *
4b5800fe 402brcmf_find_wpaie(const u8 *parse, u32 len)
89286dc9 403{
4b5800fe 404 const struct brcmf_tlv *ie;
89286dc9
HM
405
406 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
4b5800fe 407 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
89286dc9
HM
408 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
409 return (struct brcmf_vs_tlv *)ie;
410 }
411 return NULL;
412}
413
414static struct brcmf_vs_tlv *
4b5800fe 415brcmf_find_wpsie(const u8 *parse, u32 len)
89286dc9 416{
4b5800fe 417 const struct brcmf_tlv *ie;
89286dc9
HM
418
419 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
420 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
421 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
422 return (struct brcmf_vs_tlv *)ie;
423 }
424 return NULL;
425}
426
427
5b435de0
AS
428static void convert_key_from_CPU(struct brcmf_wsec_key *key,
429 struct brcmf_wsec_key_le *key_le)
430{
431 key_le->index = cpu_to_le32(key->index);
432 key_le->len = cpu_to_le32(key->len);
433 key_le->algo = cpu_to_le32(key->algo);
434 key_le->flags = cpu_to_le32(key->flags);
435 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
436 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
437 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
438 memcpy(key_le->data, key->data, sizeof(key->data));
439 memcpy(key_le->ea, key->ea, sizeof(key->ea));
440}
441
f09d0c02 442static int
2eaba7e8 443send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
5b435de0
AS
444{
445 int err;
446 struct brcmf_wsec_key_le key_le;
447
448 convert_key_from_CPU(key, &key_le);
f09d0c02 449
81f5dcb8
HM
450 brcmf_netdev_wait_pend8021x(ndev);
451
ac24be6f 452 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
81f5dcb8 453 sizeof(key_le));
f09d0c02 454
5b435de0 455 if (err)
57d6e91a 456 brcmf_err("wsec_key error (%d)\n", err);
5b435de0
AS
457 return err;
458}
459
b3657453
HM
460static s32
461brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
462{
463 s32 err;
464 u32 mode;
465
466 if (enable)
467 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
468 else
469 mode = 0;
470
471 /* Try to set and enable ARP offload feature, this may fail, then it */
472 /* is simply not supported and err 0 will be returned */
473 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
474 if (err) {
475 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
476 mode, err);
477 err = 0;
478 } else {
479 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
480 if (err) {
481 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
482 enable, err);
483 err = 0;
484 } else
485 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
486 enable, mode);
487 }
488
489 return err;
490}
491
9f440b7b
AS
492static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
493 const char *name,
494 enum nl80211_iftype type,
495 u32 *flags,
496 struct vif_params *params)
497{
498 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
499 switch (type) {
500 case NL80211_IFTYPE_ADHOC:
501 case NL80211_IFTYPE_STATION:
502 case NL80211_IFTYPE_AP:
503 case NL80211_IFTYPE_AP_VLAN:
504 case NL80211_IFTYPE_WDS:
505 case NL80211_IFTYPE_MONITOR:
506 case NL80211_IFTYPE_MESH_POINT:
507 return ERR_PTR(-EOPNOTSUPP);
508 case NL80211_IFTYPE_P2P_CLIENT:
509 case NL80211_IFTYPE_P2P_GO:
27f10e38 510 case NL80211_IFTYPE_P2P_DEVICE:
9f440b7b
AS
511 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
512 case NL80211_IFTYPE_UNSPECIFIED:
9f440b7b
AS
513 default:
514 return ERR_PTR(-EINVAL);
515 }
516}
517
f96aa07e 518void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
5f4f9f11 519{
5f4f9f11
AS
520 s32 err = 0;
521
522 if (check_vif_up(ifp->vif)) {
523 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
524 if (err) {
525 brcmf_err("fail to set mpc\n");
526 return;
527 }
528 brcmf_dbg(INFO, "MPC : %d\n", mpc);
529 }
530}
531
a0f472ac
AS
532s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
533 struct brcmf_if *ifp, bool aborted,
534 bool fw_abort)
5f4f9f11
AS
535{
536 struct brcmf_scan_params_le params_le;
537 struct cfg80211_scan_request *scan_request;
538 s32 err = 0;
539
540 brcmf_dbg(SCAN, "Enter\n");
541
542 /* clear scan request, because the FW abort can cause a second call */
543 /* to this functon and might cause a double cfg80211_scan_done */
544 scan_request = cfg->scan_request;
545 cfg->scan_request = NULL;
546
547 if (timer_pending(&cfg->escan_timeout))
548 del_timer_sync(&cfg->escan_timeout);
549
550 if (fw_abort) {
551 /* Do a scan abort to stop the driver's scan engine */
552 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
553 memset(&params_le, 0, sizeof(params_le));
554 memset(params_le.bssid, 0xFF, ETH_ALEN);
555 params_le.bss_type = DOT11_BSSTYPE_ANY;
556 params_le.scan_type = 0;
557 params_le.channel_num = cpu_to_le32(1);
558 params_le.nprobes = cpu_to_le32(1);
559 params_le.active_time = cpu_to_le32(-1);
560 params_le.passive_time = cpu_to_le32(-1);
561 params_le.home_time = cpu_to_le32(-1);
562 /* Scan is aborted by setting channel_list[0] to -1 */
563 params_le.channel_list[0] = cpu_to_le16(-1);
564 /* E-Scan (or anyother type) can be aborted by SCAN */
f96aa07e 565 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
5f4f9f11
AS
566 &params_le, sizeof(params_le));
567 if (err)
568 brcmf_err("Scan abort failed\n");
569 }
570 /*
571 * e-scan can be initiated by scheduled scan
572 * which takes precedence.
573 */
574 if (cfg->sched_escan) {
575 brcmf_dbg(SCAN, "scheduled scan completed\n");
576 cfg->sched_escan = false;
577 if (!aborted)
578 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
f96aa07e 579 brcmf_set_mpc(ifp, 1);
5f4f9f11
AS
580 } else if (scan_request) {
581 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
582 aborted ? "Aborted" : "Done");
583 cfg80211_scan_done(scan_request, aborted);
f96aa07e 584 brcmf_set_mpc(ifp, 1);
5f4f9f11 585 }
6eda4e2c
HM
586 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
587 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
5f4f9f11
AS
588
589 return err;
590}
591
9f440b7b
AS
592static
593int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
594{
5f4f9f11
AS
595 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
596 struct net_device *ndev = wdev->netdev;
597
598 /* vif event pending in firmware */
599 if (brcmf_cfg80211_vif_event_armed(cfg))
600 return -EBUSY;
601
602 if (ndev) {
603 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
a0f472ac
AS
604 cfg->escan_info.ifp == netdev_priv(ndev))
605 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
606 true, true);
5f4f9f11
AS
607
608 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
609 }
610
9f440b7b
AS
611 switch (wdev->iftype) {
612 case NL80211_IFTYPE_ADHOC:
613 case NL80211_IFTYPE_STATION:
614 case NL80211_IFTYPE_AP:
615 case NL80211_IFTYPE_AP_VLAN:
616 case NL80211_IFTYPE_WDS:
617 case NL80211_IFTYPE_MONITOR:
618 case NL80211_IFTYPE_MESH_POINT:
619 return -EOPNOTSUPP;
620 case NL80211_IFTYPE_P2P_CLIENT:
621 case NL80211_IFTYPE_P2P_GO:
27f10e38 622 case NL80211_IFTYPE_P2P_DEVICE:
9f440b7b
AS
623 return brcmf_p2p_del_vif(wiphy, wdev);
624 case NL80211_IFTYPE_UNSPECIFIED:
9f440b7b
AS
625 default:
626 return -EINVAL;
627 }
628 return -EOPNOTSUPP;
629}
630
5b435de0
AS
631static s32
632brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
633 enum nl80211_iftype type, u32 *flags,
634 struct vif_params *params)
635{
7a5c1f64 636 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
c1179033 637 struct brcmf_if *ifp = netdev_priv(ndev);
128ce3b6 638 struct brcmf_cfg80211_vif *vif = ifp->vif;
5b435de0 639 s32 infra = 0;
1a873342 640 s32 ap = 0;
5b435de0
AS
641 s32 err = 0;
642
d96b801f 643 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
5b435de0
AS
644
645 switch (type) {
646 case NL80211_IFTYPE_MONITOR:
647 case NL80211_IFTYPE_WDS:
57d6e91a
AS
648 brcmf_err("type (%d) : currently we do not support this type\n",
649 type);
5b435de0
AS
650 return -EOPNOTSUPP;
651 case NL80211_IFTYPE_ADHOC:
128ce3b6 652 vif->mode = WL_MODE_IBSS;
5b435de0
AS
653 infra = 0;
654 break;
655 case NL80211_IFTYPE_STATION:
1bc7c654
HM
656 /* Ignore change for p2p IF. Unclear why supplicant does this */
657 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
658 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
659 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
660 /* WAR: It is unexpected to get a change of VIF for P2P
661 * IF, but it happens. The request can not be handled
662 * but returning EPERM causes a crash. Returning 0
663 * without setting ieee80211_ptr->iftype causes trace
664 * (WARN_ON) but it works with wpa_supplicant
665 */
666 return 0;
667 }
128ce3b6 668 vif->mode = WL_MODE_BSS;
5b435de0
AS
669 infra = 1;
670 break;
1a873342 671 case NL80211_IFTYPE_AP:
7a5c1f64 672 case NL80211_IFTYPE_P2P_GO:
128ce3b6 673 vif->mode = WL_MODE_AP;
1a873342
HM
674 ap = 1;
675 break;
5b435de0
AS
676 default:
677 err = -EINVAL;
678 goto done;
679 }
680
1a873342 681 if (ap) {
7a5c1f64
HM
682 if (type == NL80211_IFTYPE_P2P_GO) {
683 brcmf_dbg(INFO, "IF Type = P2P GO\n");
684 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
685 }
686 if (!err) {
687 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
688 brcmf_dbg(INFO, "IF Type = AP\n");
689 }
5b435de0 690 } else {
128ce3b6 691 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
1a873342 692 if (err) {
57d6e91a 693 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
1a873342
HM
694 err = -EAGAIN;
695 goto done;
696 }
647c9ae0
AS
697 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
698 "Adhoc" : "Infra");
5b435de0 699 }
1a873342 700 ndev->ieee80211_ptr->iftype = type;
5b435de0
AS
701
702done:
d96b801f 703 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
704
705 return err;
706}
707
83cf17aa
FL
708static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
709 struct brcmf_scan_params_le *params_le,
e756af5b
HM
710 struct cfg80211_scan_request *request)
711{
712 u32 n_ssids;
713 u32 n_channels;
714 s32 i;
715 s32 offset;
029591f3 716 u16 chanspec;
e756af5b 717 char *ptr;
029591f3 718 struct brcmf_ssid_le ssid_le;
e756af5b 719
ba40d166 720 memset(params_le->bssid, 0xFF, ETH_ALEN);
e756af5b
HM
721 params_le->bss_type = DOT11_BSSTYPE_ANY;
722 params_le->scan_type = 0;
723 params_le->channel_num = 0;
724 params_le->nprobes = cpu_to_le32(-1);
725 params_le->active_time = cpu_to_le32(-1);
726 params_le->passive_time = cpu_to_le32(-1);
727 params_le->home_time = cpu_to_le32(-1);
728 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
729
730 /* if request is null exit so it will be all channel broadcast scan */
731 if (!request)
732 return;
733
734 n_ssids = request->n_ssids;
735 n_channels = request->n_channels;
736 /* Copy channel array if applicable */
4e8a008e
AS
737 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
738 n_channels);
e756af5b
HM
739 if (n_channels > 0) {
740 for (i = 0; i < n_channels; i++) {
83cf17aa
FL
741 chanspec = channel_to_chanspec(&cfg->d11inf,
742 request->channels[i]);
4e8a008e
AS
743 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
744 request->channels[i]->hw_value, chanspec);
029591f3 745 params_le->channel_list[i] = cpu_to_le16(chanspec);
e756af5b
HM
746 }
747 } else {
4e8a008e 748 brcmf_dbg(SCAN, "Scanning all channels\n");
e756af5b
HM
749 }
750 /* Copy ssid array if applicable */
4e8a008e 751 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
e756af5b
HM
752 if (n_ssids > 0) {
753 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
754 n_channels * sizeof(u16);
755 offset = roundup(offset, sizeof(u32));
756 ptr = (char *)params_le + offset;
757 for (i = 0; i < n_ssids; i++) {
029591f3
AS
758 memset(&ssid_le, 0, sizeof(ssid_le));
759 ssid_le.SSID_len =
760 cpu_to_le32(request->ssids[i].ssid_len);
761 memcpy(ssid_le.SSID, request->ssids[i].ssid,
762 request->ssids[i].ssid_len);
763 if (!ssid_le.SSID_len)
4e8a008e 764 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
e756af5b 765 else
4e8a008e
AS
766 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
767 i, ssid_le.SSID, ssid_le.SSID_len);
029591f3
AS
768 memcpy(ptr, &ssid_le, sizeof(ssid_le));
769 ptr += sizeof(ssid_le);
e756af5b
HM
770 }
771 } else {
4e8a008e 772 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
e756af5b 773 if ((request->ssids) && request->ssids->ssid_len) {
4e8a008e
AS
774 brcmf_dbg(SCAN, "SSID %s len=%d\n",
775 params_le->ssid_le.SSID,
776 request->ssids->ssid_len);
e756af5b
HM
777 params_le->ssid_le.SSID_len =
778 cpu_to_le32(request->ssids->ssid_len);
779 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
780 request->ssids->ssid_len);
781 }
782 }
783 /* Adding mask to channel numbers */
784 params_le->channel_num =
785 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
786 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
787}
788
e756af5b 789static s32
a0f472ac 790brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
e756af5b
HM
791 struct cfg80211_scan_request *request, u16 action)
792{
793 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
794 offsetof(struct brcmf_escan_params_le, params_le);
795 struct brcmf_escan_params_le *params;
796 s32 err = 0;
797
4e8a008e 798 brcmf_dbg(SCAN, "E-SCAN START\n");
e756af5b
HM
799
800 if (request != NULL) {
801 /* Allocate space for populating ssids in struct */
802 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
803
804 /* Allocate space for populating ssids in struct */
805 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
806 }
807
808 params = kzalloc(params_size, GFP_KERNEL);
809 if (!params) {
810 err = -ENOMEM;
811 goto exit;
812 }
813 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
83cf17aa 814 brcmf_escan_prep(cfg, &params->params_le, request);
e756af5b
HM
815 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
816 params->action = cpu_to_le16(action);
817 params->sync_id = cpu_to_le16(0x1234);
818
a0f472ac 819 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
e756af5b
HM
820 if (err) {
821 if (err == -EBUSY)
647c9ae0 822 brcmf_dbg(INFO, "system busy : escan canceled\n");
e756af5b 823 else
57d6e91a 824 brcmf_err("error (%d)\n", err);
e756af5b
HM
825 }
826
827 kfree(params);
828exit:
829 return err;
830}
831
832static s32
27a68fe3 833brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
a0f472ac 834 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
e756af5b
HM
835{
836 s32 err;
81f5dcb8 837 u32 passive_scan;
e756af5b 838 struct brcmf_scan_results *results;
9f440b7b 839 struct escan_info *escan = &cfg->escan_info;
e756af5b 840
4e8a008e 841 brcmf_dbg(SCAN, "Enter\n");
a0f472ac 842 escan->ifp = ifp;
9f440b7b
AS
843 escan->wiphy = wiphy;
844 escan->escan_state = WL_ESCAN_STATE_SCANNING;
81f5dcb8 845 passive_scan = cfg->active_scan ? 0 : 1;
f96aa07e 846 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 847 passive_scan);
e756af5b 848 if (err) {
57d6e91a 849 brcmf_err("error (%d)\n", err);
e756af5b
HM
850 return err;
851 }
f96aa07e 852 brcmf_set_mpc(ifp, 0);
27a68fe3 853 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
e756af5b
HM
854 results->version = 0;
855 results->count = 0;
856 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
857
a0f472ac 858 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
e756af5b 859 if (err)
f96aa07e 860 brcmf_set_mpc(ifp, 1);
e756af5b
HM
861 return err;
862}
863
864static s32
a0f472ac 865brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
e756af5b
HM
866 struct cfg80211_scan_request *request,
867 struct cfg80211_ssid *this_ssid)
868{
a0f472ac
AS
869 struct brcmf_if *ifp = vif->ifp;
870 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e756af5b 871 struct cfg80211_ssid *ssids;
f0799895 872 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
81f5dcb8 873 u32 passive_scan;
e756af5b
HM
874 bool escan_req;
875 bool spec_scan;
876 s32 err;
877 u32 SSID_len;
878
4e8a008e 879 brcmf_dbg(SCAN, "START ESCAN\n");
e756af5b 880
c1179033 881 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 882 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e756af5b
HM
883 return -EAGAIN;
884 }
c1179033 885 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
57d6e91a
AS
886 brcmf_err("Scanning being aborted: status (%lu)\n",
887 cfg->scan_status);
e756af5b
HM
888 return -EAGAIN;
889 }
1687eee2
AS
890 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
891 brcmf_err("Scanning suppressed: status (%lu)\n",
892 cfg->scan_status);
893 return -EAGAIN;
894 }
c1179033 895 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
57d6e91a 896 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
e756af5b
HM
897 return -EAGAIN;
898 }
899
0f8ffe17 900 /* If scan req comes for p2p0, send it over primary I/F */
a0f472ac
AS
901 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
902 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
0f8ffe17 903
e756af5b 904 /* Arm scan timeout timer */
27a68fe3 905 mod_timer(&cfg->escan_timeout, jiffies +
e756af5b
HM
906 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
907
908 escan_req = false;
909 if (request) {
910 /* scan bss */
911 ssids = request->ssids;
912 escan_req = true;
913 } else {
914 /* scan in ibss */
915 /* we don't do escan in ibss */
916 ssids = this_ssid;
917 }
918
27a68fe3 919 cfg->scan_request = request;
c1179033 920 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e756af5b 921 if (escan_req) {
9f440b7b 922 cfg->escan_info.run = brcmf_run_escan;
a0f472ac 923 err = brcmf_p2p_scan_prep(wiphy, request, vif);
9f440b7b
AS
924 if (err)
925 goto scan_out;
926
a0f472ac 927 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
2cb941c0 928 if (err)
e756af5b
HM
929 goto scan_out;
930 } else {
4e8a008e
AS
931 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
932 ssids->ssid, ssids->ssid_len);
e756af5b
HM
933 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
934 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
935 sr->ssid_le.SSID_len = cpu_to_le32(0);
936 spec_scan = false;
937 if (SSID_len) {
938 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
939 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
940 spec_scan = true;
941 } else
4e8a008e 942 brcmf_dbg(SCAN, "Broadcast scan\n");
e756af5b 943
81f5dcb8 944 passive_scan = cfg->active_scan ? 0 : 1;
c1179033 945 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 946 passive_scan);
e756af5b 947 if (err) {
57d6e91a 948 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
e756af5b
HM
949 goto scan_out;
950 }
f96aa07e 951 brcmf_set_mpc(ifp, 0);
c1179033 952 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
ac24be6f 953 &sr->ssid_le, sizeof(sr->ssid_le));
e756af5b
HM
954 if (err) {
955 if (err == -EBUSY)
647c9ae0
AS
956 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
957 sr->ssid_le.SSID);
e756af5b 958 else
57d6e91a 959 brcmf_err("WLC_SCAN error (%d)\n", err);
e756af5b 960
f96aa07e 961 brcmf_set_mpc(ifp, 1);
e756af5b
HM
962 goto scan_out;
963 }
964 }
965
966 return 0;
967
968scan_out:
c1179033 969 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3
AS
970 if (timer_pending(&cfg->escan_timeout))
971 del_timer_sync(&cfg->escan_timeout);
972 cfg->scan_request = NULL;
e756af5b
HM
973 return err;
974}
975
5b435de0 976static s32
0abb5f21 977brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
5b435de0 978{
a0f472ac 979 struct brcmf_cfg80211_vif *vif;
5b435de0
AS
980 s32 err = 0;
981
d96b801f 982 brcmf_dbg(TRACE, "Enter\n");
a0f472ac
AS
983 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
984 if (!check_vif_up(vif))
5b435de0
AS
985 return -EIO;
986
a0f472ac 987 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
e756af5b 988
5b435de0 989 if (err)
57d6e91a 990 brcmf_err("scan error (%d)\n", err);
5b435de0 991
d96b801f 992 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
993 return err;
994}
995
996static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
997{
998 s32 err = 0;
999
ac24be6f
AS
1000 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1001 rts_threshold);
5b435de0 1002 if (err)
57d6e91a 1003 brcmf_err("Error (%d)\n", err);
5b435de0
AS
1004
1005 return err;
1006}
1007
1008static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1009{
1010 s32 err = 0;
1011
ac24be6f
AS
1012 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1013 frag_threshold);
5b435de0 1014 if (err)
57d6e91a 1015 brcmf_err("Error (%d)\n", err);
5b435de0
AS
1016
1017 return err;
1018}
1019
1020static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1021{
1022 s32 err = 0;
b87e2c48 1023 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
5b435de0 1024
ac24be6f 1025 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
5b435de0 1026 if (err) {
57d6e91a 1027 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
5b435de0
AS
1028 return err;
1029 }
1030 return err;
1031}
1032
1033static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1034{
27a68fe3
AS
1035 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1036 struct net_device *ndev = cfg_to_ndev(cfg);
0abb5f21 1037 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1038 s32 err = 0;
1039
d96b801f 1040 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1041 if (!check_vif_up(ifp->vif))
5b435de0
AS
1042 return -EIO;
1043
1044 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
27a68fe3
AS
1045 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1046 cfg->conf->rts_threshold = wiphy->rts_threshold;
1047 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
5b435de0
AS
1048 if (!err)
1049 goto done;
1050 }
1051 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
27a68fe3
AS
1052 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1053 cfg->conf->frag_threshold = wiphy->frag_threshold;
1054 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
5b435de0
AS
1055 if (!err)
1056 goto done;
1057 }
1058 if (changed & WIPHY_PARAM_RETRY_LONG
27a68fe3
AS
1059 && (cfg->conf->retry_long != wiphy->retry_long)) {
1060 cfg->conf->retry_long = wiphy->retry_long;
1061 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
5b435de0
AS
1062 if (!err)
1063 goto done;
1064 }
1065 if (changed & WIPHY_PARAM_RETRY_SHORT
27a68fe3
AS
1066 && (cfg->conf->retry_short != wiphy->retry_short)) {
1067 cfg->conf->retry_short = wiphy->retry_short;
1068 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
5b435de0
AS
1069 if (!err)
1070 goto done;
1071 }
1072
1073done:
d96b801f 1074 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1075 return err;
1076}
1077
5b435de0
AS
1078static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1079{
1080 memset(prof, 0, sizeof(*prof));
1081}
1082
903e0eee 1083static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
5b435de0 1084{
61730d4d 1085 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
5b435de0
AS
1086 s32 err = 0;
1087
d96b801f 1088 brcmf_dbg(TRACE, "Enter\n");
5b435de0 1089
903e0eee 1090 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
647c9ae0 1091 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
903e0eee 1092 err = brcmf_fil_cmd_data_set(vif->ifp,
ac24be6f 1093 BRCMF_C_DISASSOC, NULL, 0);
a538ae31 1094 if (err) {
57d6e91a 1095 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
a538ae31 1096 }
903e0eee 1097 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
43dffbc6
AS
1098 cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
1099
5b435de0 1100 }
903e0eee 1101 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
61730d4d
PH
1102 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1103 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
d96b801f 1104 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1105}
1106
1107static s32
1108brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1109 struct cfg80211_ibss_params *params)
1110{
27a68fe3 1111 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1112 struct brcmf_if *ifp = netdev_priv(ndev);
1113 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1114 struct brcmf_join_params join_params;
1115 size_t join_params_size = 0;
1116 s32 err = 0;
1117 s32 wsec = 0;
1118 s32 bcnprd;
1701261d 1119 u16 chanspec;
5b435de0 1120
d96b801f 1121 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1122 if (!check_vif_up(ifp->vif))
5b435de0
AS
1123 return -EIO;
1124
1125 if (params->ssid)
16886735 1126 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
5b435de0 1127 else {
16886735 1128 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
5b435de0
AS
1129 return -EOPNOTSUPP;
1130 }
1131
c1179033 1132 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1133
1134 if (params->bssid)
16886735 1135 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
5b435de0 1136 else
16886735 1137 brcmf_dbg(CONN, "No BSSID specified\n");
5b435de0 1138
683b6d3b 1139 if (params->chandef.chan)
16886735
AS
1140 brcmf_dbg(CONN, "channel: %d\n",
1141 params->chandef.chan->center_freq);
5b435de0 1142 else
16886735 1143 brcmf_dbg(CONN, "no channel specified\n");
5b435de0
AS
1144
1145 if (params->channel_fixed)
16886735 1146 brcmf_dbg(CONN, "fixed channel required\n");
5b435de0 1147 else
16886735 1148 brcmf_dbg(CONN, "no fixed channel required\n");
5b435de0
AS
1149
1150 if (params->ie && params->ie_len)
16886735 1151 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
5b435de0 1152 else
16886735 1153 brcmf_dbg(CONN, "no ie specified\n");
5b435de0
AS
1154
1155 if (params->beacon_interval)
16886735
AS
1156 brcmf_dbg(CONN, "beacon interval: %d\n",
1157 params->beacon_interval);
5b435de0 1158 else
16886735 1159 brcmf_dbg(CONN, "no beacon interval specified\n");
5b435de0
AS
1160
1161 if (params->basic_rates)
16886735 1162 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
5b435de0 1163 else
16886735 1164 brcmf_dbg(CONN, "no basic rates specified\n");
5b435de0
AS
1165
1166 if (params->privacy)
16886735 1167 brcmf_dbg(CONN, "privacy required\n");
5b435de0 1168 else
16886735 1169 brcmf_dbg(CONN, "no privacy required\n");
5b435de0
AS
1170
1171 /* Configure Privacy for starter */
1172 if (params->privacy)
1173 wsec |= WEP_ENABLED;
1174
c1179033 1175 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
5b435de0 1176 if (err) {
57d6e91a 1177 brcmf_err("wsec failed (%d)\n", err);
5b435de0
AS
1178 goto done;
1179 }
1180
1181 /* Configure Beacon Interval for starter */
1182 if (params->beacon_interval)
1183 bcnprd = params->beacon_interval;
1184 else
1185 bcnprd = 100;
1186
b87e2c48 1187 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
5b435de0 1188 if (err) {
57d6e91a 1189 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
5b435de0
AS
1190 goto done;
1191 }
1192
1193 /* Configure required join parameter */
1194 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1195
1196 /* SSID */
6c8c4f72
AS
1197 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1198 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1199 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1200 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
5b435de0 1201 join_params_size = sizeof(join_params.ssid_le);
5b435de0
AS
1202
1203 /* BSSID */
1204 if (params->bssid) {
1205 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1206 join_params_size = sizeof(join_params.ssid_le) +
1207 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
6c8c4f72 1208 memcpy(profile->bssid, params->bssid, ETH_ALEN);
5b435de0 1209 } else {
ba40d166 1210 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
6c8c4f72 1211 memset(profile->bssid, 0, ETH_ALEN);
5b435de0
AS
1212 }
1213
5b435de0 1214 /* Channel */
683b6d3b 1215 if (params->chandef.chan) {
5b435de0
AS
1216 u32 target_channel;
1217
27a68fe3 1218 cfg->channel =
5b435de0 1219 ieee80211_frequency_to_channel(
683b6d3b 1220 params->chandef.chan->center_freq);
5b435de0
AS
1221 if (params->channel_fixed) {
1222 /* adding chanspec */
83cf17aa
FL
1223 chanspec = channel_to_chanspec(&cfg->d11inf,
1224 params->chandef.chan);
1701261d
HM
1225 join_params.params_le.chanspec_list[0] =
1226 cpu_to_le16(chanspec);
1227 join_params.params_le.chanspec_num = cpu_to_le32(1);
1228 join_params_size += sizeof(join_params.params_le);
5b435de0
AS
1229 }
1230
1231 /* set channel for starter */
27a68fe3 1232 target_channel = cfg->channel;
b87e2c48 1233 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
81f5dcb8 1234 target_channel);
5b435de0 1235 if (err) {
57d6e91a 1236 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
5b435de0
AS
1237 goto done;
1238 }
1239 } else
27a68fe3 1240 cfg->channel = 0;
5b435de0 1241
27a68fe3 1242 cfg->ibss_starter = false;
5b435de0
AS
1243
1244
c1179033 1245 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1246 &join_params, join_params_size);
5b435de0 1247 if (err) {
57d6e91a 1248 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
5b435de0
AS
1249 goto done;
1250 }
1251
1252done:
1253 if (err)
c1179033 1254 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
d96b801f 1255 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1256 return err;
1257}
1258
1259static s32
1260brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1261{
0abb5f21 1262 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1263 s32 err = 0;
1264
d96b801f 1265 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1266 if (!check_vif_up(ifp->vif))
5b435de0
AS
1267 return -EIO;
1268
903e0eee 1269 brcmf_link_down(ifp->vif);
5b435de0 1270
d96b801f 1271 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1272
1273 return err;
1274}
1275
1276static s32 brcmf_set_wpa_version(struct net_device *ndev,
1277 struct cfg80211_connect_params *sme)
1278{
6ac4f4ed 1279 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1280 struct brcmf_cfg80211_security *sec;
1281 s32 val = 0;
1282 s32 err = 0;
1283
1284 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1285 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1286 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1287 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1288 else
1289 val = WPA_AUTH_DISABLED;
16886735 1290 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
89286dc9 1291 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
5b435de0 1292 if (err) {
57d6e91a 1293 brcmf_err("set wpa_auth failed (%d)\n", err);
5b435de0
AS
1294 return err;
1295 }
06bb123e 1296 sec = &profile->sec;
5b435de0
AS
1297 sec->wpa_versions = sme->crypto.wpa_versions;
1298 return err;
1299}
1300
1301static s32 brcmf_set_auth_type(struct net_device *ndev,
1302 struct cfg80211_connect_params *sme)
1303{
6ac4f4ed 1304 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1305 struct brcmf_cfg80211_security *sec;
1306 s32 val = 0;
1307 s32 err = 0;
1308
1309 switch (sme->auth_type) {
1310 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1311 val = 0;
16886735 1312 brcmf_dbg(CONN, "open system\n");
5b435de0
AS
1313 break;
1314 case NL80211_AUTHTYPE_SHARED_KEY:
1315 val = 1;
16886735 1316 brcmf_dbg(CONN, "shared key\n");
5b435de0
AS
1317 break;
1318 case NL80211_AUTHTYPE_AUTOMATIC:
1319 val = 2;
16886735 1320 brcmf_dbg(CONN, "automatic\n");
5b435de0
AS
1321 break;
1322 case NL80211_AUTHTYPE_NETWORK_EAP:
16886735 1323 brcmf_dbg(CONN, "network eap\n");
5b435de0
AS
1324 default:
1325 val = 2;
57d6e91a 1326 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
5b435de0
AS
1327 break;
1328 }
1329
89286dc9 1330 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
5b435de0 1331 if (err) {
57d6e91a 1332 brcmf_err("set auth failed (%d)\n", err);
5b435de0
AS
1333 return err;
1334 }
06bb123e 1335 sec = &profile->sec;
5b435de0
AS
1336 sec->auth_type = sme->auth_type;
1337 return err;
1338}
1339
1340static s32
1341brcmf_set_set_cipher(struct net_device *ndev,
1342 struct cfg80211_connect_params *sme)
1343{
6ac4f4ed 1344 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1345 struct brcmf_cfg80211_security *sec;
1346 s32 pval = 0;
1347 s32 gval = 0;
1348 s32 err = 0;
1349
1350 if (sme->crypto.n_ciphers_pairwise) {
1351 switch (sme->crypto.ciphers_pairwise[0]) {
1352 case WLAN_CIPHER_SUITE_WEP40:
1353 case WLAN_CIPHER_SUITE_WEP104:
1354 pval = WEP_ENABLED;
1355 break;
1356 case WLAN_CIPHER_SUITE_TKIP:
1357 pval = TKIP_ENABLED;
1358 break;
1359 case WLAN_CIPHER_SUITE_CCMP:
1360 pval = AES_ENABLED;
1361 break;
1362 case WLAN_CIPHER_SUITE_AES_CMAC:
1363 pval = AES_ENABLED;
1364 break;
1365 default:
57d6e91a
AS
1366 brcmf_err("invalid cipher pairwise (%d)\n",
1367 sme->crypto.ciphers_pairwise[0]);
5b435de0
AS
1368 return -EINVAL;
1369 }
1370 }
1371 if (sme->crypto.cipher_group) {
1372 switch (sme->crypto.cipher_group) {
1373 case WLAN_CIPHER_SUITE_WEP40:
1374 case WLAN_CIPHER_SUITE_WEP104:
1375 gval = WEP_ENABLED;
1376 break;
1377 case WLAN_CIPHER_SUITE_TKIP:
1378 gval = TKIP_ENABLED;
1379 break;
1380 case WLAN_CIPHER_SUITE_CCMP:
1381 gval = AES_ENABLED;
1382 break;
1383 case WLAN_CIPHER_SUITE_AES_CMAC:
1384 gval = AES_ENABLED;
1385 break;
1386 default:
57d6e91a
AS
1387 brcmf_err("invalid cipher group (%d)\n",
1388 sme->crypto.cipher_group);
5b435de0
AS
1389 return -EINVAL;
1390 }
1391 }
1392
16886735 1393 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
89286dc9
HM
1394 /* In case of privacy, but no security and WPS then simulate */
1395 /* setting AES. WPS-2.0 allows no security */
1396 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1397 sme->privacy)
1398 pval = AES_ENABLED;
1399 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
5b435de0 1400 if (err) {
57d6e91a 1401 brcmf_err("error (%d)\n", err);
5b435de0
AS
1402 return err;
1403 }
1404
06bb123e 1405 sec = &profile->sec;
5b435de0
AS
1406 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1407 sec->cipher_group = sme->crypto.cipher_group;
1408
1409 return err;
1410}
1411
1412static s32
1413brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1414{
6ac4f4ed 1415 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1416 struct brcmf_cfg80211_security *sec;
1417 s32 val = 0;
1418 s32 err = 0;
1419
1420 if (sme->crypto.n_akm_suites) {
89286dc9
HM
1421 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1422 "wpa_auth", &val);
5b435de0 1423 if (err) {
57d6e91a 1424 brcmf_err("could not get wpa_auth (%d)\n", err);
5b435de0
AS
1425 return err;
1426 }
1427 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1428 switch (sme->crypto.akm_suites[0]) {
1429 case WLAN_AKM_SUITE_8021X:
1430 val = WPA_AUTH_UNSPECIFIED;
1431 break;
1432 case WLAN_AKM_SUITE_PSK:
1433 val = WPA_AUTH_PSK;
1434 break;
1435 default:
57d6e91a
AS
1436 brcmf_err("invalid cipher group (%d)\n",
1437 sme->crypto.cipher_group);
5b435de0
AS
1438 return -EINVAL;
1439 }
1440 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1441 switch (sme->crypto.akm_suites[0]) {
1442 case WLAN_AKM_SUITE_8021X:
1443 val = WPA2_AUTH_UNSPECIFIED;
1444 break;
1445 case WLAN_AKM_SUITE_PSK:
1446 val = WPA2_AUTH_PSK;
1447 break;
1448 default:
57d6e91a
AS
1449 brcmf_err("invalid cipher group (%d)\n",
1450 sme->crypto.cipher_group);
5b435de0
AS
1451 return -EINVAL;
1452 }
1453 }
1454
16886735 1455 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
89286dc9
HM
1456 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1457 "wpa_auth", val);
5b435de0 1458 if (err) {
57d6e91a 1459 brcmf_err("could not set wpa_auth (%d)\n", err);
5b435de0
AS
1460 return err;
1461 }
1462 }
06bb123e 1463 sec = &profile->sec;
5b435de0
AS
1464 sec->wpa_auth = sme->crypto.akm_suites[0];
1465
1466 return err;
1467}
1468
1469static s32
f09d0c02
HM
1470brcmf_set_sharedkey(struct net_device *ndev,
1471 struct cfg80211_connect_params *sme)
5b435de0 1472{
6ac4f4ed 1473 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1474 struct brcmf_cfg80211_security *sec;
1475 struct brcmf_wsec_key key;
1476 s32 val;
1477 s32 err = 0;
1478
16886735 1479 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
5b435de0 1480
a718e2fe
RV
1481 if (sme->key_len == 0)
1482 return 0;
1483
06bb123e 1484 sec = &profile->sec;
16886735
AS
1485 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1486 sec->wpa_versions, sec->cipher_pairwise);
a718e2fe
RV
1487
1488 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1489 return 0;
1490
f09d0c02
HM
1491 if (!(sec->cipher_pairwise &
1492 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1493 return 0;
a718e2fe 1494
f09d0c02
HM
1495 memset(&key, 0, sizeof(key));
1496 key.len = (u32) sme->key_len;
1497 key.index = (u32) sme->key_idx;
1498 if (key.len > sizeof(key.data)) {
57d6e91a 1499 brcmf_err("Too long key length (%u)\n", key.len);
f09d0c02
HM
1500 return -EINVAL;
1501 }
1502 memcpy(key.data, sme->key, key.len);
1503 key.flags = BRCMF_PRIMARY_KEY;
1504 switch (sec->cipher_pairwise) {
1505 case WLAN_CIPHER_SUITE_WEP40:
1506 key.algo = CRYPTO_ALGO_WEP1;
1507 break;
1508 case WLAN_CIPHER_SUITE_WEP104:
1509 key.algo = CRYPTO_ALGO_WEP128;
1510 break;
1511 default:
57d6e91a
AS
1512 brcmf_err("Invalid algorithm (%d)\n",
1513 sme->crypto.ciphers_pairwise[0]);
f09d0c02
HM
1514 return -EINVAL;
1515 }
1516 /* Set the new key/index */
16886735
AS
1517 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1518 key.len, key.index, key.algo);
1519 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
2eaba7e8 1520 err = send_key_to_dongle(ndev, &key);
f09d0c02
HM
1521 if (err)
1522 return err;
1523
1524 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
16886735 1525 brcmf_dbg(CONN, "set auth_type to shared key\n");
f09d0c02 1526 val = WL_AUTH_SHARED_KEY; /* shared key */
ac24be6f 1527 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
f09d0c02 1528 if (err)
57d6e91a 1529 brcmf_err("set auth failed (%d)\n", err);
5b435de0
AS
1530 }
1531 return err;
1532}
1533
cbb1ec94
AS
1534static
1535enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1536 enum nl80211_auth_type type)
1537{
1538 u32 ci;
1539 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1540 /* shift to ignore chip revision */
1541 ci = brcmf_get_chip_info(ifp) >> 4;
1542 switch (ci) {
1543 case 43236:
1544 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1545 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1546 default:
1547 break;
1548 }
1549 }
1550 return type;
1551}
1552
5b435de0
AS
1553static s32
1554brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
cbb1ec94 1555 struct cfg80211_connect_params *sme)
5b435de0 1556{
27a68fe3 1557 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1558 struct brcmf_if *ifp = netdev_priv(ndev);
1559 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1560 struct ieee80211_channel *chan = sme->channel;
1561 struct brcmf_join_params join_params;
1562 size_t join_params_size;
4b5800fe
JB
1563 const struct brcmf_tlv *rsn_ie;
1564 const struct brcmf_vs_tlv *wpa_ie;
1565 const void *ie;
89286dc9
HM
1566 u32 ie_len;
1567 struct brcmf_ext_join_params_le *ext_join_params;
1701261d 1568 u16 chanspec;
5b435de0
AS
1569
1570 s32 err = 0;
1571
d96b801f 1572 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1573 if (!check_vif_up(ifp->vif))
5b435de0
AS
1574 return -EIO;
1575
1576 if (!sme->ssid) {
57d6e91a 1577 brcmf_err("Invalid ssid\n");
5b435de0
AS
1578 return -EOPNOTSUPP;
1579 }
1580
89286dc9
HM
1581 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1582 /* A normal (non P2P) connection request setup. */
1583 ie = NULL;
1584 ie_len = 0;
1585 /* find the WPA_IE */
1586 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1587 if (wpa_ie) {
1588 ie = wpa_ie;
1589 ie_len = wpa_ie->len + TLV_HDR_LEN;
1590 } else {
1591 /* find the RSN_IE */
4b5800fe
JB
1592 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1593 sme->ie_len,
89286dc9
HM
1594 WLAN_EID_RSN);
1595 if (rsn_ie) {
1596 ie = rsn_ie;
1597 ie_len = rsn_ie->len + TLV_HDR_LEN;
1598 }
1599 }
1600 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1601 }
1602
1603 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1604 sme->ie, sme->ie_len);
1605 if (err)
1606 brcmf_err("Set Assoc REQ IE Failed\n");
1607 else
1608 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1609
c1179033 1610 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1611
1612 if (chan) {
27a68fe3 1613 cfg->channel =
5b435de0 1614 ieee80211_frequency_to_channel(chan->center_freq);
83cf17aa 1615 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
1701261d
HM
1616 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1617 cfg->channel, chan->center_freq, chanspec);
1618 } else {
27a68fe3 1619 cfg->channel = 0;
1701261d
HM
1620 chanspec = 0;
1621 }
5b435de0 1622
647c9ae0 1623 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
5b435de0
AS
1624
1625 err = brcmf_set_wpa_version(ndev, sme);
1626 if (err) {
57d6e91a 1627 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
5b435de0
AS
1628 goto done;
1629 }
1630
cbb1ec94 1631 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
5b435de0
AS
1632 err = brcmf_set_auth_type(ndev, sme);
1633 if (err) {
57d6e91a 1634 brcmf_err("wl_set_auth_type failed (%d)\n", err);
5b435de0
AS
1635 goto done;
1636 }
1637
1638 err = brcmf_set_set_cipher(ndev, sme);
1639 if (err) {
57d6e91a 1640 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
5b435de0
AS
1641 goto done;
1642 }
1643
1644 err = brcmf_set_key_mgmt(ndev, sme);
1645 if (err) {
57d6e91a 1646 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
5b435de0
AS
1647 goto done;
1648 }
1649
f09d0c02 1650 err = brcmf_set_sharedkey(ndev, sme);
5b435de0 1651 if (err) {
57d6e91a 1652 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
5b435de0
AS
1653 goto done;
1654 }
1655
89286dc9
HM
1656 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1657 (u32)sme->ssid_len);
1658 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1659 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1660 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1661 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1662 profile->ssid.SSID_len);
1663 }
1664
1665 /* Join with specific BSSID and cached SSID
1666 * If SSID is zero join based on BSSID only
1667 */
1668 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1669 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1670 if (cfg->channel)
1671 join_params_size += sizeof(u16);
1672 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1673 if (ext_join_params == NULL) {
1674 err = -ENOMEM;
1675 goto done;
1676 }
1677 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1678 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1679 profile->ssid.SSID_len);
1680 /*increase dwell time to receive probe response or detect Beacon
1681 * from target AP at a noisy air only during connect command
1682 */
1683 ext_join_params->scan_le.active_time =
1684 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1685 ext_join_params->scan_le.passive_time =
1686 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1687 /* Set up join scan parameters */
1688 ext_join_params->scan_le.scan_type = -1;
1689 /* to sync with presence period of VSDB GO.
1690 * Send probe request more frequently. Probe request will be stopped
1691 * when it gets probe response from target AP/GO.
1692 */
1693 ext_join_params->scan_le.nprobes =
1694 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1695 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1696 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1697
1698 if (sme->bssid)
1699 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1700 else
1701 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1702
1703 if (cfg->channel) {
1704 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1705
1706 ext_join_params->assoc_le.chanspec_list[0] =
1707 cpu_to_le16(chanspec);
1708 }
1709
1710 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1711 join_params_size);
1712 kfree(ext_join_params);
1713 if (!err)
1714 /* This is it. join command worked, we are done */
1715 goto done;
1716
1717 /* join command failed, fallback to set ssid */
5b435de0
AS
1718 memset(&join_params, 0, sizeof(join_params));
1719 join_params_size = sizeof(join_params.ssid_le);
1720
6c8c4f72 1721 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
6c8c4f72 1722 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
5b435de0 1723
89286dc9
HM
1724 if (sme->bssid)
1725 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1726 else
1727 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
5b435de0 1728
1701261d
HM
1729 if (cfg->channel) {
1730 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1731 join_params.params_le.chanspec_num = cpu_to_le32(1);
1732 join_params_size += sizeof(join_params.params_le);
1733 }
c1179033 1734 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1735 &join_params, join_params_size);
5b435de0 1736 if (err)
89286dc9 1737 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
5b435de0
AS
1738
1739done:
1740 if (err)
c1179033 1741 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
d96b801f 1742 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1743 return err;
1744}
1745
1746static s32
1747brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1748 u16 reason_code)
1749{
0abb5f21
AS
1750 struct brcmf_if *ifp = netdev_priv(ndev);
1751 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1752 struct brcmf_scb_val_le scbval;
1753 s32 err = 0;
1754
d96b801f 1755 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
ce81e317 1756 if (!check_vif_up(ifp->vif))
5b435de0
AS
1757 return -EIO;
1758
c1179033 1759 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
43dffbc6 1760 cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
5b435de0 1761
06bb123e 1762 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
5b435de0 1763 scbval.val = cpu_to_le32(reason_code);
c1179033 1764 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
ac24be6f 1765 &scbval, sizeof(scbval));
5b435de0 1766 if (err)
57d6e91a 1767 brcmf_err("error (%d)\n", err);
5b435de0 1768
d96b801f 1769 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1770 return err;
1771}
1772
1773static s32
c8442118 1774brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
d3f31134 1775 enum nl80211_tx_power_setting type, s32 mbm)
5b435de0
AS
1776{
1777
27a68fe3 1778 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1779 struct net_device *ndev = cfg_to_ndev(cfg);
1780 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1781 u16 txpwrmw;
1782 s32 err = 0;
1783 s32 disable = 0;
d3f31134 1784 s32 dbm = MBM_TO_DBM(mbm);
5b435de0 1785
d96b801f 1786 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1787 if (!check_vif_up(ifp->vif))
5b435de0
AS
1788 return -EIO;
1789
1790 switch (type) {
1791 case NL80211_TX_POWER_AUTOMATIC:
1792 break;
1793 case NL80211_TX_POWER_LIMITED:
5b435de0
AS
1794 case NL80211_TX_POWER_FIXED:
1795 if (dbm < 0) {
57d6e91a 1796 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
5b435de0
AS
1797 err = -EINVAL;
1798 goto done;
1799 }
1800 break;
1801 }
1802 /* Make sure radio is off or on as far as software is concerned */
1803 disable = WL_RADIO_SW_DISABLE << 16;
ac24be6f 1804 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
5b435de0 1805 if (err)
57d6e91a 1806 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
5b435de0
AS
1807
1808 if (dbm > 0xffff)
1809 txpwrmw = 0xffff;
1810 else
1811 txpwrmw = (u16) dbm;
ac24be6f
AS
1812 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1813 (s32)brcmf_mw_to_qdbm(txpwrmw));
5b435de0 1814 if (err)
57d6e91a 1815 brcmf_err("qtxpower error (%d)\n", err);
27a68fe3 1816 cfg->conf->tx_power = dbm;
5b435de0
AS
1817
1818done:
d96b801f 1819 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1820 return err;
1821}
1822
c8442118
JB
1823static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1824 struct wireless_dev *wdev,
1825 s32 *dbm)
5b435de0 1826{
27a68fe3 1827 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 1828 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
1829 s32 txpwrdbm;
1830 u8 result;
1831 s32 err = 0;
1832
d96b801f 1833 brcmf_dbg(TRACE, "Enter\n");
ce81e317 1834 if (!check_vif_up(ifp->vif))
5b435de0
AS
1835 return -EIO;
1836
0abb5f21 1837 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
5b435de0 1838 if (err) {
57d6e91a 1839 brcmf_err("error (%d)\n", err);
5b435de0
AS
1840 goto done;
1841 }
1842
1843 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
ef6ac17a 1844 *dbm = (s32) brcmf_qdbm_to_mw(result);
5b435de0
AS
1845
1846done:
d96b801f 1847 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1848 return err;
1849}
1850
1851static s32
1852brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1853 u8 key_idx, bool unicast, bool multicast)
1854{
0abb5f21 1855 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1856 u32 index;
1857 u32 wsec;
1858 s32 err = 0;
1859
d96b801f 1860 brcmf_dbg(TRACE, "Enter\n");
16886735 1861 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 1862 if (!check_vif_up(ifp->vif))
5b435de0
AS
1863 return -EIO;
1864
0abb5f21 1865 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 1866 if (err) {
57d6e91a 1867 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
5b435de0
AS
1868 goto done;
1869 }
1870
1871 if (wsec & WEP_ENABLED) {
1872 /* Just select a new current key */
1873 index = key_idx;
0abb5f21 1874 err = brcmf_fil_cmd_int_set(ifp,
ac24be6f 1875 BRCMF_C_SET_KEY_PRIMARY, index);
5b435de0 1876 if (err)
57d6e91a 1877 brcmf_err("error (%d)\n", err);
5b435de0
AS
1878 }
1879done:
d96b801f 1880 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
1881 return err;
1882}
1883
1884static s32
1885brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1886 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1887{
992f6068 1888 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 1889 struct brcmf_wsec_key key;
5b435de0 1890 s32 err = 0;
992f6068 1891 u8 keybuf[8];
5b435de0
AS
1892
1893 memset(&key, 0, sizeof(key));
1894 key.index = (u32) key_idx;
1895 /* Instead of bcast for ea address for default wep keys,
1896 driver needs it to be Null */
1897 if (!is_multicast_ether_addr(mac_addr))
1898 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1899 key.len = (u32) params->key_len;
1900 /* check for key index change */
1901 if (key.len == 0) {
1902 /* key delete */
2eaba7e8 1903 err = send_key_to_dongle(ndev, &key);
5b435de0 1904 if (err)
57d6e91a 1905 brcmf_err("key delete error (%d)\n", err);
5b435de0
AS
1906 } else {
1907 if (key.len > sizeof(key.data)) {
57d6e91a 1908 brcmf_err("Invalid key length (%d)\n", key.len);
5b435de0
AS
1909 return -EINVAL;
1910 }
1911
16886735 1912 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
5b435de0
AS
1913 memcpy(key.data, params->key, key.len);
1914
992f6068
HM
1915 if ((ifp->vif->mode != WL_MODE_AP) &&
1916 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1917 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
5b435de0
AS
1918 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1919 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1920 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1921 }
1922
1923 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1924 if (params->seq && params->seq_len == 6) {
1925 /* rx iv */
1926 u8 *ivptr;
1927 ivptr = (u8 *) params->seq;
1928 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1929 (ivptr[3] << 8) | ivptr[2];
1930 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1931 key.iv_initialized = true;
1932 }
1933
1934 switch (params->cipher) {
1935 case WLAN_CIPHER_SUITE_WEP40:
1936 key.algo = CRYPTO_ALGO_WEP1;
16886735 1937 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
1938 break;
1939 case WLAN_CIPHER_SUITE_WEP104:
1940 key.algo = CRYPTO_ALGO_WEP128;
16886735 1941 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
1942 break;
1943 case WLAN_CIPHER_SUITE_TKIP:
1944 key.algo = CRYPTO_ALGO_TKIP;
16886735 1945 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
1946 break;
1947 case WLAN_CIPHER_SUITE_AES_CMAC:
1948 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 1949 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
1950 break;
1951 case WLAN_CIPHER_SUITE_CCMP:
1952 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 1953 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
1954 break;
1955 default:
57d6e91a 1956 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
1957 return -EINVAL;
1958 }
2eaba7e8 1959 err = send_key_to_dongle(ndev, &key);
f09d0c02 1960 if (err)
57d6e91a 1961 brcmf_err("wsec_key error (%d)\n", err);
5b435de0
AS
1962 }
1963 return err;
1964}
1965
1966static s32
1967brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1968 u8 key_idx, bool pairwise, const u8 *mac_addr,
1969 struct key_params *params)
1970{
0abb5f21 1971 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1972 struct brcmf_wsec_key key;
1973 s32 val;
1974 s32 wsec;
1975 s32 err = 0;
1976 u8 keybuf[8];
1977
d96b801f 1978 brcmf_dbg(TRACE, "Enter\n");
16886735 1979 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 1980 if (!check_vif_up(ifp->vif))
5b435de0
AS
1981 return -EIO;
1982
1983 if (mac_addr) {
d96b801f 1984 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
1985 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1986 }
1987 memset(&key, 0, sizeof(key));
1988
1989 key.len = (u32) params->key_len;
1990 key.index = (u32) key_idx;
1991
1992 if (key.len > sizeof(key.data)) {
57d6e91a 1993 brcmf_err("Too long key length (%u)\n", key.len);
5b435de0
AS
1994 err = -EINVAL;
1995 goto done;
1996 }
1997 memcpy(key.data, params->key, key.len);
1998
1999 key.flags = BRCMF_PRIMARY_KEY;
2000 switch (params->cipher) {
2001 case WLAN_CIPHER_SUITE_WEP40:
2002 key.algo = CRYPTO_ALGO_WEP1;
f09d0c02 2003 val = WEP_ENABLED;
16886735 2004 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2005 break;
2006 case WLAN_CIPHER_SUITE_WEP104:
2007 key.algo = CRYPTO_ALGO_WEP128;
f09d0c02 2008 val = WEP_ENABLED;
16886735 2009 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
2010 break;
2011 case WLAN_CIPHER_SUITE_TKIP:
128ce3b6 2012 if (ifp->vif->mode != WL_MODE_AP) {
992f6068 2013 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
1a873342
HM
2014 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2015 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2016 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2017 }
5b435de0 2018 key.algo = CRYPTO_ALGO_TKIP;
f09d0c02 2019 val = TKIP_ENABLED;
16886735 2020 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
2021 break;
2022 case WLAN_CIPHER_SUITE_AES_CMAC:
2023 key.algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 2024 val = AES_ENABLED;
16886735 2025 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
2026 break;
2027 case WLAN_CIPHER_SUITE_CCMP:
2028 key.algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 2029 val = AES_ENABLED;
16886735 2030 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
2031 break;
2032 default:
57d6e91a 2033 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
2034 err = -EINVAL;
2035 goto done;
2036 }
2037
2eaba7e8 2038 err = send_key_to_dongle(ndev, &key);
5b435de0
AS
2039 if (err)
2040 goto done;
2041
0abb5f21 2042 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2043 if (err) {
57d6e91a 2044 brcmf_err("get wsec error (%d)\n", err);
5b435de0
AS
2045 goto done;
2046 }
5b435de0 2047 wsec |= val;
0abb5f21 2048 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
5b435de0 2049 if (err) {
57d6e91a 2050 brcmf_err("set wsec error (%d)\n", err);
5b435de0
AS
2051 goto done;
2052 }
2053
5b435de0 2054done:
d96b801f 2055 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2056 return err;
2057}
2058
2059static s32
2060brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2061 u8 key_idx, bool pairwise, const u8 *mac_addr)
2062{
0abb5f21 2063 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2064 struct brcmf_wsec_key key;
2065 s32 err = 0;
5b435de0 2066
d96b801f 2067 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2068 if (!check_vif_up(ifp->vif))
5b435de0
AS
2069 return -EIO;
2070
256c374f
HM
2071 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2072 /* we ignore this key index in this case */
57d6e91a 2073 brcmf_err("invalid key index (%d)\n", key_idx);
256c374f
HM
2074 return -EINVAL;
2075 }
2076
5b435de0
AS
2077 memset(&key, 0, sizeof(key));
2078
2079 key.index = (u32) key_idx;
2080 key.flags = BRCMF_PRIMARY_KEY;
2081 key.algo = CRYPTO_ALGO_OFF;
2082
16886735 2083 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
5b435de0
AS
2084
2085 /* Set the new key/index */
2eaba7e8 2086 err = send_key_to_dongle(ndev, &key);
5b435de0 2087
d96b801f 2088 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2089 return err;
2090}
2091
2092static s32
2093brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2094 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2095 void (*callback) (void *cookie, struct key_params * params))
2096{
2097 struct key_params params;
0abb5f21
AS
2098 struct brcmf_if *ifp = netdev_priv(ndev);
2099 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2100 struct brcmf_cfg80211_security *sec;
2101 s32 wsec;
2102 s32 err = 0;
2103
d96b801f 2104 brcmf_dbg(TRACE, "Enter\n");
16886735 2105 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 2106 if (!check_vif_up(ifp->vif))
5b435de0
AS
2107 return -EIO;
2108
2109 memset(&params, 0, sizeof(params));
2110
0abb5f21 2111 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2112 if (err) {
57d6e91a 2113 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
5b435de0
AS
2114 /* Ignore this error, may happen during DISASSOC */
2115 err = -EAGAIN;
2116 goto done;
2117 }
c5bf53a8 2118 if (wsec & WEP_ENABLED) {
06bb123e 2119 sec = &profile->sec;
5b435de0
AS
2120 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2121 params.cipher = WLAN_CIPHER_SUITE_WEP40;
16886735 2122 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2123 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2124 params.cipher = WLAN_CIPHER_SUITE_WEP104;
16886735 2125 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0 2126 }
c5bf53a8 2127 } else if (wsec & TKIP_ENABLED) {
5b435de0 2128 params.cipher = WLAN_CIPHER_SUITE_TKIP;
16886735 2129 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
c5bf53a8 2130 } else if (wsec & AES_ENABLED) {
5b435de0 2131 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
16886735 2132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
c5bf53a8 2133 } else {
57d6e91a 2134 brcmf_err("Invalid algo (0x%x)\n", wsec);
5b435de0
AS
2135 err = -EINVAL;
2136 goto done;
2137 }
2138 callback(cookie, &params);
2139
2140done:
d96b801f 2141 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2142 return err;
2143}
2144
2145static s32
2146brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2147 struct net_device *ndev, u8 key_idx)
2148{
647c9ae0 2149 brcmf_dbg(INFO, "Not supported\n");
5b435de0
AS
2150
2151 return -EOPNOTSUPP;
2152}
2153
2154static s32
2155brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
1a873342 2156 u8 *mac, struct station_info *sinfo)
5b435de0 2157{
0abb5f21
AS
2158 struct brcmf_if *ifp = netdev_priv(ndev);
2159 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2160 struct brcmf_scb_val_le scb_val;
2161 int rssi;
2162 s32 rate;
2163 s32 err = 0;
06bb123e 2164 u8 *bssid = profile->bssid;
81f5dcb8 2165 struct brcmf_sta_info_le sta_info_le;
5b435de0 2166
d96b801f 2167 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
ce81e317 2168 if (!check_vif_up(ifp->vif))
5b435de0
AS
2169 return -EIO;
2170
128ce3b6 2171 if (ifp->vif->mode == WL_MODE_AP) {
81f5dcb8 2172 memcpy(&sta_info_le, mac, ETH_ALEN);
0abb5f21 2173 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
ac24be6f 2174 &sta_info_le,
81f5dcb8 2175 sizeof(sta_info_le));
1a873342 2176 if (err < 0) {
57d6e91a 2177 brcmf_err("GET STA INFO failed, %d\n", err);
1a873342
HM
2178 goto done;
2179 }
1a873342 2180 sinfo->filled = STATION_INFO_INACTIVE_TIME;
81f5dcb8
HM
2181 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2182 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
1a873342 2183 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
81f5dcb8 2184 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
1a873342 2185 }
d96b801f
AS
2186 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2187 sinfo->inactive_time, sinfo->connected_time);
128ce3b6 2188 } else if (ifp->vif->mode == WL_MODE_BSS) {
1a873342 2189 if (memcmp(mac, bssid, ETH_ALEN)) {
57d6e91a
AS
2190 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2191 mac, bssid);
1a873342
HM
2192 err = -ENOENT;
2193 goto done;
2194 }
2195 /* Report the current tx rate */
89286dc9 2196 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
7f6c562d 2197 if (err) {
57d6e91a 2198 brcmf_err("Could not get rate (%d)\n", err);
1a873342 2199 goto done;
7f6c562d 2200 } else {
1a873342
HM
2201 sinfo->filled |= STATION_INFO_TX_BITRATE;
2202 sinfo->txrate.legacy = rate * 5;
16886735 2203 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
7f6c562d 2204 }
5b435de0 2205
c1179033
AS
2206 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2207 &ifp->vif->sme_state)) {
1a873342 2208 memset(&scb_val, 0, sizeof(scb_val));
c1179033
AS
2209 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2210 &scb_val, sizeof(scb_val));
1a873342 2211 if (err) {
57d6e91a 2212 brcmf_err("Could not get rssi (%d)\n", err);
1a873342
HM
2213 goto done;
2214 } else {
2215 rssi = le32_to_cpu(scb_val.val);
2216 sinfo->filled |= STATION_INFO_SIGNAL;
2217 sinfo->signal = rssi;
16886735 2218 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
1a873342
HM
2219 }
2220 }
2221 } else
2222 err = -EPERM;
5b435de0 2223done:
d96b801f 2224 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2225 return err;
2226}
2227
2228static s32
2229brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2230 bool enabled, s32 timeout)
2231{
2232 s32 pm;
2233 s32 err = 0;
27a68fe3 2234 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2235 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2236
d96b801f 2237 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2238
2239 /*
2240 * Powersave enable/disable request is coming from the
2241 * cfg80211 even before the interface is up. In that
2242 * scenario, driver will be storing the power save
27a68fe3 2243 * preference in cfg struct to apply this to
5b435de0
AS
2244 * FW later while initializing the dongle
2245 */
27a68fe3 2246 cfg->pwr_save = enabled;
ce81e317 2247 if (!check_vif_up(ifp->vif)) {
5b435de0 2248
647c9ae0 2249 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
5b435de0
AS
2250 goto done;
2251 }
2252
2253 pm = enabled ? PM_FAST : PM_OFF;
102fd0d6
HM
2254 /* Do not enable the power save after assoc if it is a p2p interface */
2255 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2256 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2257 pm = PM_OFF;
2258 }
647c9ae0 2259 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2260
c1179033 2261 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2262 if (err) {
2263 if (err == -ENODEV)
57d6e91a 2264 brcmf_err("net_device is not ready yet\n");
5b435de0 2265 else
57d6e91a 2266 brcmf_err("error (%d)\n", err);
5b435de0
AS
2267 }
2268done:
d96b801f 2269 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2270 return err;
2271}
2272
27a68fe3 2273static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2274 struct brcmf_bss_info_le *bi)
5b435de0 2275{
27a68fe3 2276 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2277 struct ieee80211_channel *notify_channel;
2278 struct cfg80211_bss *bss;
2279 struct ieee80211_supported_band *band;
83cf17aa 2280 struct brcmu_chan ch;
5b435de0
AS
2281 s32 err = 0;
2282 u16 channel;
2283 u32 freq;
5b435de0
AS
2284 u16 notify_capability;
2285 u16 notify_interval;
2286 u8 *notify_ie;
2287 size_t notify_ielen;
2288 s32 notify_signal;
2289
2290 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2291 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2292 return 0;
2293 }
2294
83cf17aa
FL
2295 if (!bi->ctl_ch) {
2296 ch.chspec = le16_to_cpu(bi->chanspec);
2297 cfg->d11inf.decchspec(&ch);
2298 bi->ctl_ch = ch.chnum;
2299 }
2300 channel = bi->ctl_ch;
5b435de0
AS
2301
2302 if (channel <= CH_MAX_2G_CHANNEL)
2303 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2304 else
2305 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2306
2307 freq = ieee80211_channel_to_frequency(channel, band->band);
2308 notify_channel = ieee80211_get_channel(wiphy, freq);
2309
5b435de0
AS
2310 notify_capability = le16_to_cpu(bi->capability);
2311 notify_interval = le16_to_cpu(bi->beacon_period);
2312 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2313 notify_ielen = le32_to_cpu(bi->ie_length);
2314 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2315
16886735
AS
2316 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2317 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2318 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2319 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2320 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0
AS
2321
2322 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
8e6cffb3 2323 0, notify_capability, notify_interval, notify_ie,
5b435de0
AS
2324 notify_ielen, notify_signal, GFP_KERNEL);
2325
e78946e1
FL
2326 if (!bss)
2327 return -ENOMEM;
2328
5b112d3d 2329 cfg80211_put_bss(wiphy, bss);
5b435de0
AS
2330
2331 return err;
2332}
2333
6f09be0a
RV
2334static struct brcmf_bss_info_le *
2335next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2336{
2337 if (bss == NULL)
2338 return list->bss_info_le;
2339 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2340 le32_to_cpu(bss->length));
2341}
2342
27a68fe3 2343static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2344{
2345 struct brcmf_scan_results *bss_list;
d34bf64f 2346 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2347 s32 err = 0;
2348 int i;
2349
27a68fe3 2350 bss_list = cfg->bss_list;
0ecd8164
AS
2351 if (bss_list->count != 0 &&
2352 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2353 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2354 bss_list->version);
5b435de0
AS
2355 return -EOPNOTSUPP;
2356 }
4e8a008e 2357 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2358 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2359 bi = next_bss_le(bss_list, bi);
27a68fe3 2360 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2361 if (err)
2362 break;
2363 }
2364 return err;
2365}
2366
27a68fe3 2367static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2368 struct net_device *ndev, const u8 *bssid)
2369{
27a68fe3 2370 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2371 struct ieee80211_channel *notify_channel;
d34bf64f 2372 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2373 struct ieee80211_supported_band *band;
e78946e1 2374 struct cfg80211_bss *bss;
83cf17aa 2375 struct brcmu_chan ch;
5b435de0
AS
2376 u8 *buf = NULL;
2377 s32 err = 0;
5b435de0 2378 u32 freq;
5b435de0
AS
2379 u16 notify_capability;
2380 u16 notify_interval;
2381 u8 *notify_ie;
2382 size_t notify_ielen;
2383 s32 notify_signal;
2384
d96b801f 2385 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2386
2387 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2388 if (buf == NULL) {
2389 err = -ENOMEM;
2390 goto CleanUp;
2391 }
2392
2393 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2394
ac24be6f
AS
2395 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2396 buf, WL_BSS_INFO_MAX);
5b435de0 2397 if (err) {
57d6e91a 2398 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2399 goto CleanUp;
2400 }
2401
d34bf64f 2402 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0 2403
83cf17aa
FL
2404 ch.chspec = le16_to_cpu(bi->chanspec);
2405 cfg->d11inf.decchspec(&ch);
5b435de0 2406
83cf17aa 2407 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
2408 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2409 else
2410 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2411
83cf17aa 2412 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
2413 notify_channel = ieee80211_get_channel(wiphy, freq);
2414
5b435de0
AS
2415 notify_capability = le16_to_cpu(bi->capability);
2416 notify_interval = le16_to_cpu(bi->beacon_period);
2417 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2418 notify_ielen = le32_to_cpu(bi->ie_length);
2419 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2420
83cf17aa 2421 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
16886735
AS
2422 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2423 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2424 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2425
e78946e1 2426 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
8e6cffb3 2427 0, notify_capability, notify_interval,
5b435de0
AS
2428 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2429
e78946e1
FL
2430 if (!bss) {
2431 err = -ENOMEM;
2432 goto CleanUp;
2433 }
2434
5b112d3d 2435 cfg80211_put_bss(wiphy, bss);
e78946e1 2436
5b435de0
AS
2437CleanUp:
2438
2439 kfree(buf);
2440
d96b801f 2441 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2442
2443 return err;
2444}
2445
128ce3b6 2446static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
5b435de0 2447{
128ce3b6 2448 return vif->mode == WL_MODE_IBSS;
5b435de0
AS
2449}
2450
89286dc9
HM
2451static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2452 struct brcmf_if *ifp)
1a873342 2453{
89286dc9 2454 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
d34bf64f 2455 struct brcmf_bss_info_le *bi;
5b435de0 2456 struct brcmf_ssid *ssid;
4b5800fe 2457 const struct brcmf_tlv *tim;
5b435de0
AS
2458 u16 beacon_interval;
2459 u8 dtim_period;
2460 size_t ie_len;
2461 u8 *ie;
2462 s32 err = 0;
2463
d96b801f 2464 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2465 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2466 return err;
2467
06bb123e 2468 ssid = &profile->ssid;
5b435de0 2469
27a68fe3 2470 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2471 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2472 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2473 if (err) {
57d6e91a 2474 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2475 goto update_bss_info_out;
2476 }
2477
27a68fe3
AS
2478 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2479 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2480 if (err)
2481 goto update_bss_info_out;
2482
2483 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2484 ie_len = le32_to_cpu(bi->ie_length);
2485 beacon_interval = le16_to_cpu(bi->beacon_period);
2486
f8e4b412 2487 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2488 if (tim)
2489 dtim_period = tim->data[1];
2490 else {
2491 /*
2492 * active scan was done so we could not get dtim
2493 * information out of probe response.
2494 * so we speficially query dtim information to dongle.
2495 */
2496 u32 var;
ac24be6f 2497 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2498 if (err) {
57d6e91a 2499 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2500 goto update_bss_info_out;
2501 }
2502 dtim_period = (u8)var;
2503 }
2504
5b435de0 2505update_bss_info_out:
d96b801f 2506 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2507 return err;
2508}
2509
18e2f61d 2510void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2511{
27a68fe3 2512 struct escan_info *escan = &cfg->escan_info;
5b435de0 2513
c1179033 2514 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2515 if (cfg->scan_request) {
108a4bee 2516 escan->escan_state = WL_ESCAN_STATE_IDLE;
a0f472ac 2517 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
5b435de0 2518 }
c1179033
AS
2519 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2520 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2521}
2522
e756af5b
HM
2523static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2524{
27a68fe3
AS
2525 struct brcmf_cfg80211_info *cfg =
2526 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2527 escan_timeout_work);
2528
a0f472ac 2529 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
e756af5b
HM
2530}
2531
2532static void brcmf_escan_timeout(unsigned long data)
2533{
27a68fe3
AS
2534 struct brcmf_cfg80211_info *cfg =
2535 (struct brcmf_cfg80211_info *)data;
e756af5b 2536
27a68fe3 2537 if (cfg->scan_request) {
57d6e91a 2538 brcmf_err("timer expired\n");
f0799895 2539 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2540 }
2541}
2542
2543static s32
83cf17aa
FL
2544brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2545 struct brcmf_bss_info_le *bss,
e756af5b
HM
2546 struct brcmf_bss_info_le *bss_info_le)
2547{
83cf17aa
FL
2548 struct brcmu_chan ch_bss, ch_bss_info_le;
2549
2550 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2551 cfg->d11inf.decchspec(&ch_bss);
2552 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2553 cfg->d11inf.decchspec(&ch_bss_info_le);
2554
e756af5b 2555 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
83cf17aa 2556 ch_bss.band == ch_bss_info_le.band &&
e756af5b
HM
2557 bss_info_le->SSID_len == bss->SSID_len &&
2558 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
6f5838a4
AS
2559 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2560 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2561 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2562 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2563
e756af5b
HM
2564 /* preserve max RSSI if the measurements are
2565 * both on-channel or both off-channel
2566 */
029591f3 2567 if (bss_info_rssi > bss_rssi)
e756af5b 2568 bss->RSSI = bss_info_le->RSSI;
6f5838a4
AS
2569 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2570 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
e756af5b
HM
2571 /* preserve the on-channel rssi measurement
2572 * if the new measurement is off channel
2573 */
2574 bss->RSSI = bss_info_le->RSSI;
6f5838a4 2575 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
e756af5b
HM
2576 }
2577 return 1;
2578 }
2579 return 0;
2580}
2581
2582static s32
1993732e 2583brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2584 const struct brcmf_event_msg *e, void *data)
2585{
1993732e 2586 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e756af5b
HM
2587 s32 status;
2588 s32 err = 0;
2589 struct brcmf_escan_result_le *escan_result_le;
2590 struct brcmf_bss_info_le *bss_info_le;
2591 struct brcmf_bss_info_le *bss = NULL;
2592 u32 bi_length;
2593 struct brcmf_scan_results *list;
2594 u32 i;
97ed15c7 2595 bool aborted;
e756af5b 2596
5c36b99a 2597 status = e->status;
e756af5b 2598
a0f472ac
AS
2599 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2600 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
e756af5b
HM
2601 return -EPERM;
2602 }
2603
2604 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2605 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2606 escan_result_le = (struct brcmf_escan_result_le *) data;
2607 if (!escan_result_le) {
57d6e91a 2608 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2609 goto exit;
2610 }
e756af5b 2611 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2612 brcmf_err("Invalid bss_count %d: ignoring\n",
2613 escan_result_le->bss_count);
e756af5b
HM
2614 goto exit;
2615 }
2616 bss_info_le = &escan_result_le->bss_info_le;
2617
6eda4e2c
HM
2618 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2619 goto exit;
2620
2621 if (!cfg->scan_request) {
2622 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2623 goto exit;
2624 }
2625
e756af5b
HM
2626 bi_length = le32_to_cpu(bss_info_le->length);
2627 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2628 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
2629 brcmf_err("Invalid bss_info length %d: ignoring\n",
2630 bi_length);
e756af5b
HM
2631 goto exit;
2632 }
2633
27a68fe3 2634 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2635 BIT(NL80211_IFTYPE_ADHOC))) {
2636 if (le16_to_cpu(bss_info_le->capability) &
2637 WLAN_CAPABILITY_IBSS) {
57d6e91a 2638 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
2639 goto exit;
2640 }
2641 }
2642
2643 list = (struct brcmf_scan_results *)
27a68fe3 2644 cfg->escan_info.escan_buf;
e756af5b 2645 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 2646 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
2647 goto exit;
2648 }
2649
2650 for (i = 0; i < list->count; i++) {
2651 bss = bss ? (struct brcmf_bss_info_le *)
2652 ((unsigned char *)bss +
2653 le32_to_cpu(bss->length)) : list->bss_info_le;
83cf17aa
FL
2654 if (brcmf_compare_update_same_bss(cfg, bss,
2655 bss_info_le))
e756af5b
HM
2656 goto exit;
2657 }
27a68fe3 2658 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2659 bss_info_le, bi_length);
2660 list->version = le32_to_cpu(bss_info_le->version);
2661 list->buflen += bi_length;
2662 list->count++;
2663 } else {
27a68fe3 2664 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
2665 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2666 goto exit;
27a68fe3
AS
2667 if (cfg->scan_request) {
2668 cfg->bss_list = (struct brcmf_scan_results *)
2669 cfg->escan_info.escan_buf;
2670 brcmf_inform_bss(cfg);
97ed15c7 2671 aborted = status != BRCMF_E_STATUS_SUCCESS;
a0f472ac 2672 brcmf_notify_escan_complete(cfg, ifp, aborted,
97ed15c7 2673 false);
e756af5b 2674 } else
6eda4e2c
HM
2675 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2676 status);
e756af5b
HM
2677 }
2678exit:
2679 return err;
2680}
2681
27a68fe3 2682static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 2683{
5c36b99a
AS
2684 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2685 brcmf_cfg80211_escan_handler);
f0799895
HM
2686 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2687 /* Init scan_timeout timer */
2688 init_timer(&cfg->escan_timeout);
2689 cfg->escan_timeout.data = (unsigned long) cfg;
2690 cfg->escan_timeout.function = brcmf_escan_timeout;
2691 INIT_WORK(&cfg->escan_timeout_work,
2692 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2693}
2694
5addc0de 2695static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2696{
2697 if (ms < 1000 / HZ) {
2698 cond_resched();
2699 mdelay(ms);
2700 } else {
2701 msleep(ms);
2702 }
2703}
2704
2705static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2706{
d96b801f 2707 brcmf_dbg(TRACE, "Enter\n");
5b435de0 2708
5b435de0
AS
2709 return 0;
2710}
2711
2712static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2713 struct cfg80211_wowlan *wow)
2714{
27a68fe3
AS
2715 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2716 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 2717 struct brcmf_cfg80211_vif *vif;
5b435de0 2718
d96b801f 2719 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2720
2721 /*
7d641072
AS
2722 * if the primary net_device is not READY there is nothing
2723 * we can do but pray resume goes smoothly.
5b435de0 2724 */
7d641072
AS
2725 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2726 if (!check_vif_up(vif))
2727 goto exit;
5b435de0 2728
7d641072
AS
2729 list_for_each_entry(vif, &cfg->vif_list, list) {
2730 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2731 continue;
5b435de0 2732 /*
7d641072
AS
2733 * While going to suspend if associated with AP disassociate
2734 * from AP to save power while system is in suspended state
5b435de0 2735 */
903e0eee
AS
2736 brcmf_link_down(vif);
2737
2738 /* Make sure WPA_Supplicant receives all the event
2739 * generated due to DISASSOC call to the fw to keep
2740 * the state fw and WPA_Supplicant state consistent
2741 */
2742 brcmf_delay(500);
5b435de0
AS
2743 }
2744
7d641072
AS
2745 /* end any scanning */
2746 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 2747 brcmf_abort_scanning(cfg);
5b435de0
AS
2748
2749 /* Turn off watchdog timer */
f96aa07e 2750 brcmf_set_mpc(netdev_priv(ndev), 1);
5b435de0 2751
7d641072 2752exit:
d96b801f 2753 brcmf_dbg(TRACE, "Exit\n");
7d641072
AS
2754 /* clear any scanning activity */
2755 cfg->scan_status = 0;
5b435de0
AS
2756 return 0;
2757}
2758
5b435de0
AS
2759static __used s32
2760brcmf_update_pmklist(struct net_device *ndev,
2761 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2762{
2763 int i, j;
40c8e95a 2764 int pmkid_len;
5b435de0 2765
40c8e95a
AS
2766 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2767
16886735 2768 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
40c8e95a 2769 for (i = 0; i < pmkid_len; i++) {
16886735
AS
2770 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2771 &pmk_list->pmkids.pmkid[i].BSSID);
5b435de0 2772 for (j = 0; j < WLAN_PMKID_LEN; j++)
16886735
AS
2773 brcmf_dbg(CONN, "%02x\n",
2774 pmk_list->pmkids.pmkid[i].PMKID[j]);
5b435de0
AS
2775 }
2776
2777 if (!err)
ac24be6f
AS
2778 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2779 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
2780
2781 return err;
2782}
2783
2784static s32
2785brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2786 struct cfg80211_pmksa *pmksa)
2787{
27a68fe3 2788 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2789 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2790 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
2791 s32 err = 0;
2792 int i;
40c8e95a 2793 int pmkid_len;
5b435de0 2794
d96b801f 2795 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2796 if (!check_vif_up(ifp->vif))
5b435de0
AS
2797 return -EIO;
2798
40c8e95a
AS
2799 pmkid_len = le32_to_cpu(pmkids->npmkid);
2800 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
2801 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2802 break;
2803 if (i < WL_NUM_PMKIDS_MAX) {
2804 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2805 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
2806 if (i == pmkid_len) {
2807 pmkid_len++;
2808 pmkids->npmkid = cpu_to_le32(pmkid_len);
2809 }
5b435de0
AS
2810 } else
2811 err = -EINVAL;
2812
16886735
AS
2813 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2814 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 2815 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2816 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 2817
27a68fe3 2818 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2819
d96b801f 2820 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2821 return err;
2822}
2823
2824static s32
2825brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2826 struct cfg80211_pmksa *pmksa)
2827{
27a68fe3 2828 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2829 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2830 struct pmkid_list pmkid;
2831 s32 err = 0;
40c8e95a 2832 int i, pmkid_len;
5b435de0 2833
d96b801f 2834 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2835 if (!check_vif_up(ifp->vif))
5b435de0
AS
2836 return -EIO;
2837
2838 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2839 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2840
16886735
AS
2841 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2842 &pmkid.pmkid[0].BSSID);
5b435de0 2843 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2844 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
5b435de0 2845
27a68fe3 2846 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 2847 for (i = 0; i < pmkid_len; i++)
5b435de0 2848 if (!memcmp
27a68fe3 2849 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
2850 ETH_ALEN))
2851 break;
2852
40c8e95a
AS
2853 if ((pmkid_len > 0)
2854 && (i < pmkid_len)) {
27a68fe3 2855 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 2856 sizeof(struct pmkid));
40c8e95a 2857 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
2858 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2859 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 2860 ETH_ALEN);
27a68fe3
AS
2861 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2862 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
2863 WLAN_PMKID_LEN);
2864 }
27a68fe3 2865 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
2866 } else
2867 err = -EINVAL;
2868
27a68fe3 2869 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2870
d96b801f 2871 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2872 return err;
2873
2874}
2875
2876static s32
2877brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2878{
27a68fe3 2879 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2880 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2881 s32 err = 0;
2882
d96b801f 2883 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2884 if (!check_vif_up(ifp->vif))
5b435de0
AS
2885 return -EIO;
2886
27a68fe3
AS
2887 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2888 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2889
d96b801f 2890 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2891 return err;
2892
2893}
2894
e5806072
AS
2895/*
2896 * PFN result doesn't have all the info which are
2897 * required by the supplicant
2898 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2899 * via wl_inform_single_bss in the required format. Escan does require the
2900 * scan request in the form of cfg80211_scan_request. For timebeing, create
2901 * cfg80211_scan_request one out of the received PNO event.
2902 */
2903static s32
1993732e 2904brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
2905 const struct brcmf_event_msg *e, void *data)
2906{
1993732e 2907 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e5806072
AS
2908 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2909 struct cfg80211_scan_request *request = NULL;
2910 struct cfg80211_ssid *ssid = NULL;
2911 struct ieee80211_channel *channel = NULL;
27a68fe3 2912 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
2913 int err = 0;
2914 int channel_req = 0;
2915 int band = 0;
2916 struct brcmf_pno_scanresults_le *pfn_result;
2917 u32 result_count;
2918 u32 status;
2919
4e8a008e 2920 brcmf_dbg(SCAN, "Enter\n");
e5806072 2921
5c36b99a 2922 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
4e8a008e 2923 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
e5806072
AS
2924 return 0;
2925 }
2926
2927 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2928 result_count = le32_to_cpu(pfn_result->count);
2929 status = le32_to_cpu(pfn_result->status);
2930
2931 /*
2932 * PFN event is limited to fit 512 bytes so we may get
2933 * multiple NET_FOUND events. For now place a warning here.
2934 */
2935 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
4e8a008e 2936 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
e5806072
AS
2937 if (result_count > 0) {
2938 int i;
2939
2940 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
2941 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2942 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
2943 if (!request || !ssid || !channel) {
2944 err = -ENOMEM;
2945 goto out_err;
2946 }
2947
2948 request->wiphy = wiphy;
2949 data += sizeof(struct brcmf_pno_scanresults_le);
2950 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2951
2952 for (i = 0; i < result_count; i++) {
2953 netinfo = &netinfo_start[i];
2954 if (!netinfo) {
57d6e91a
AS
2955 brcmf_err("Invalid netinfo ptr. index: %d\n",
2956 i);
e5806072
AS
2957 err = -EINVAL;
2958 goto out_err;
2959 }
2960
4e8a008e
AS
2961 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2962 netinfo->SSID, netinfo->channel);
e5806072
AS
2963 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2964 ssid[i].ssid_len = netinfo->SSID_len;
2965 request->n_ssids++;
2966
2967 channel_req = netinfo->channel;
2968 if (channel_req <= CH_MAX_2G_CHANNEL)
2969 band = NL80211_BAND_2GHZ;
2970 else
2971 band = NL80211_BAND_5GHZ;
2972 channel[i].center_freq =
2973 ieee80211_channel_to_frequency(channel_req,
2974 band);
2975 channel[i].band = band;
2976 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2977 request->channels[i] = &channel[i];
2978 request->n_channels++;
2979 }
2980
2981 /* assign parsed ssid array */
2982 if (request->n_ssids)
2983 request->ssids = &ssid[0];
2984
c1179033 2985 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 2986 /* Abort any on-going scan */
27a68fe3 2987 brcmf_abort_scanning(cfg);
e5806072
AS
2988 }
2989
c1179033 2990 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2668b0b1 2991 cfg->escan_info.run = brcmf_run_escan;
a0f472ac 2992 err = brcmf_do_escan(cfg, wiphy, ifp, request);
e5806072 2993 if (err) {
c1179033 2994 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
2995 goto out_err;
2996 }
27a68fe3
AS
2997 cfg->sched_escan = true;
2998 cfg->scan_request = request;
e5806072 2999 } else {
57d6e91a 3000 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
e5806072
AS
3001 goto out_err;
3002 }
3003
3004 kfree(ssid);
3005 kfree(channel);
3006 kfree(request);
3007 return 0;
3008
3009out_err:
3010 kfree(ssid);
3011 kfree(channel);
3012 kfree(request);
3013 cfg80211_sched_scan_stopped(wiphy);
3014 return err;
3015}
3016
e5806072
AS
3017static int brcmf_dev_pno_clean(struct net_device *ndev)
3018{
e5806072
AS
3019 int ret;
3020
3021 /* Disable pfn */
ac24be6f 3022 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3023 if (ret == 0) {
3024 /* clear pfn */
ac24be6f
AS
3025 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3026 NULL, 0);
e5806072
AS
3027 }
3028 if (ret < 0)
57d6e91a 3029 brcmf_err("failed code %d\n", ret);
e5806072
AS
3030
3031 return ret;
3032}
3033
3034static int brcmf_dev_pno_config(struct net_device *ndev)
3035{
3036 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3037
3038 memset(&pfn_param, 0, sizeof(pfn_param));
3039 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3040
3041 /* set extra pno params */
3042 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3043 pfn_param.repeat = BRCMF_PNO_REPEAT;
3044 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3045
3046 /* set up pno scan fr */
3047 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3048
ac24be6f
AS
3049 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3050 &pfn_param, sizeof(pfn_param));
e5806072
AS
3051}
3052
3053static int
3054brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3055 struct net_device *ndev,
3056 struct cfg80211_sched_scan_request *request)
3057{
c1179033 3058 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3059 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3060 struct brcmf_pno_net_param_le pfn;
3061 int i;
3062 int ret = 0;
3063
dc7bdbf1 3064 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
4e8a008e 3065 request->n_match_sets, request->n_ssids);
c1179033 3066 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 3067 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3068 return -EAGAIN;
3069 }
1687eee2
AS
3070 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3071 brcmf_err("Scanning suppressed: status (%lu)\n",
3072 cfg->scan_status);
3073 return -EAGAIN;
3074 }
e5806072 3075
dc7bdbf1 3076 if (!request->n_ssids || !request->n_match_sets) {
57d6e91a 3077 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
dc7bdbf1 3078 request->n_ssids);
e5806072
AS
3079 return -EINVAL;
3080 }
3081
3082 if (request->n_ssids > 0) {
3083 for (i = 0; i < request->n_ssids; i++) {
3084 /* Active scan req for ssids */
4e8a008e
AS
3085 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3086 request->ssids[i].ssid);
e5806072
AS
3087
3088 /*
3089 * match_set ssids is a supert set of n_ssid list,
3090 * so we need not add these set seperately.
3091 */
3092 }
3093 }
3094
3095 if (request->n_match_sets > 0) {
3096 /* clean up everything */
3097 ret = brcmf_dev_pno_clean(ndev);
3098 if (ret < 0) {
57d6e91a 3099 brcmf_err("failed error=%d\n", ret);
e5806072
AS
3100 return ret;
3101 }
3102
3103 /* configure pno */
3104 ret = brcmf_dev_pno_config(ndev);
3105 if (ret < 0) {
57d6e91a 3106 brcmf_err("PNO setup failed!! ret=%d\n", ret);
e5806072
AS
3107 return -EINVAL;
3108 }
3109
3110 /* configure each match set */
3111 for (i = 0; i < request->n_match_sets; i++) {
3112 struct cfg80211_ssid *ssid;
3113 u32 ssid_len;
3114
3115 ssid = &request->match_sets[i].ssid;
3116 ssid_len = ssid->ssid_len;
3117
3118 if (!ssid_len) {
57d6e91a 3119 brcmf_err("skip broadcast ssid\n");
e5806072
AS
3120 continue;
3121 }
3122 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3123 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3124 pfn.wsec = cpu_to_le32(0);
3125 pfn.infra = cpu_to_le32(1);
3126 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3127 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3128 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3129 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3130 sizeof(pfn));
4e8a008e
AS
3131 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3132 ret == 0 ? "set" : "failed", ssid->ssid);
e5806072
AS
3133 }
3134 /* Enable the PNO */
c1179033 3135 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
57d6e91a 3136 brcmf_err("PNO enable failed!! ret=%d\n", ret);
e5806072
AS
3137 return -EINVAL;
3138 }
3139 } else {
3140 return -EINVAL;
3141 }
3142
3143 return 0;
3144}
3145
3146static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3147 struct net_device *ndev)
3148{
27a68fe3 3149 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072 3150
4e8a008e 3151 brcmf_dbg(SCAN, "enter\n");
e5806072 3152 brcmf_dev_pno_clean(ndev);
27a68fe3 3153 if (cfg->sched_escan)
a0f472ac 3154 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
e5806072
AS
3155 return 0;
3156}
e5806072 3157
cbaa177d 3158#ifdef CONFIG_NL80211_TESTMODE
fc73f11f
DS
3159static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3160 struct wireless_dev *wdev,
3161 void *data, int len)
cbaa177d 3162{
27a68fe3 3163 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3164 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3165 struct brcmf_dcmd *dcmd = data;
3166 struct sk_buff *reply;
3167 int ret;
3168
d96b801f
AS
3169 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3170 dcmd->buf, dcmd->len);
f368a5b6
HM
3171
3172 if (dcmd->set)
ac24be6f
AS
3173 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3174 dcmd->buf, dcmd->len);
f368a5b6 3175 else
ac24be6f
AS
3176 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3177 dcmd->buf, dcmd->len);
cbaa177d
AS
3178 if (ret == 0) {
3179 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3180 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3181 ret = cfg80211_testmode_reply(reply);
3182 }
3183 return ret;
3184}
3185#endif
3186
1f170110 3187static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3188{
3189 s32 err;
3190
3191 /* set auth */
ac24be6f 3192 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3193 if (err < 0) {
57d6e91a 3194 brcmf_err("auth error %d\n", err);
1a873342
HM
3195 return err;
3196 }
3197 /* set wsec */
ac24be6f 3198 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3199 if (err < 0) {
57d6e91a 3200 brcmf_err("wsec error %d\n", err);
1a873342
HM
3201 return err;
3202 }
3203 /* set upper-layer auth */
ac24be6f 3204 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3205 if (err < 0) {
57d6e91a 3206 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3207 return err;
3208 }
3209
3210 return 0;
3211}
3212
3213static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3214{
3215 if (is_rsn_ie)
3216 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3217
3218 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3219}
3220
3221static s32
4b5800fe
JB
3222brcmf_configure_wpaie(struct net_device *ndev,
3223 const struct brcmf_vs_tlv *wpa_ie,
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);
4b5800fe 3710 const struct brcmf_tlv *ssid_ie;
1a873342 3711 struct brcmf_ssid_le ssid_le;
1a873342 3712 s32 err = -EPERM;
4b5800fe
JB
3713 const struct brcmf_tlv *rsn_ie;
3714 const struct brcmf_vs_tlv *wpa_ie;
1a873342 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.573156 seconds and 5 git commands to generate.