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