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