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