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