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