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