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