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