brcmfmac: Build wiphy mode and interface combinations dynamically
[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
5b435de0
AS
2399static s32
2400brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
3b3a0162 2401 const u8 *mac, struct station_info *sinfo)
5b435de0 2402{
0abb5f21
AS
2403 struct brcmf_if *ifp = netdev_priv(ndev);
2404 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2405 struct brcmf_scb_val_le scb_val;
2406 int rssi;
2407 s32 rate;
2408 s32 err = 0;
06bb123e 2409 u8 *bssid = profile->bssid;
81f5dcb8 2410 struct brcmf_sta_info_le sta_info_le;
9ee66d1b
HM
2411 u32 beacon_period;
2412 u32 dtim_period;
5b435de0 2413
d96b801f 2414 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
ce81e317 2415 if (!check_vif_up(ifp->vif))
5b435de0
AS
2416 return -EIO;
2417
967fe2c8 2418 if (brcmf_is_apmode(ifp->vif)) {
81f5dcb8 2419 memcpy(&sta_info_le, mac, ETH_ALEN);
0abb5f21 2420 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
ac24be6f 2421 &sta_info_le,
81f5dcb8 2422 sizeof(sta_info_le));
1a873342 2423 if (err < 0) {
57d6e91a 2424 brcmf_err("GET STA INFO failed, %d\n", err);
1a873342
HM
2425 goto done;
2426 }
319090bf 2427 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
81f5dcb8
HM
2428 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2429 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
319090bf 2430 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
81f5dcb8 2431 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
1a873342 2432 }
d96b801f
AS
2433 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2434 sinfo->inactive_time, sinfo->connected_time);
967fe2c8 2435 } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
1a873342 2436 if (memcmp(mac, bssid, ETH_ALEN)) {
57d6e91a
AS
2437 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2438 mac, bssid);
1a873342
HM
2439 err = -ENOENT;
2440 goto done;
2441 }
2442 /* Report the current tx rate */
89286dc9 2443 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
7f6c562d 2444 if (err) {
57d6e91a 2445 brcmf_err("Could not get rate (%d)\n", err);
1a873342 2446 goto done;
7f6c562d 2447 } else {
319090bf 2448 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
1a873342 2449 sinfo->txrate.legacy = rate * 5;
16886735 2450 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
7f6c562d 2451 }
5b435de0 2452
c1179033
AS
2453 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2454 &ifp->vif->sme_state)) {
1a873342 2455 memset(&scb_val, 0, sizeof(scb_val));
c1179033
AS
2456 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2457 &scb_val, sizeof(scb_val));
1a873342 2458 if (err) {
57d6e91a 2459 brcmf_err("Could not get rssi (%d)\n", err);
1a873342
HM
2460 goto done;
2461 } else {
2462 rssi = le32_to_cpu(scb_val.val);
319090bf 2463 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
1a873342 2464 sinfo->signal = rssi;
16886735 2465 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
1a873342 2466 }
9ee66d1b
HM
2467 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
2468 &beacon_period);
2469 if (err) {
2470 brcmf_err("Could not get beacon period (%d)\n",
2471 err);
2472 goto done;
2473 } else {
2474 sinfo->bss_param.beacon_interval =
2475 beacon_period;
2476 brcmf_dbg(CONN, "Beacon peroid %d\n",
2477 beacon_period);
2478 }
2479 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
2480 &dtim_period);
2481 if (err) {
2482 brcmf_err("Could not get DTIM period (%d)\n",
2483 err);
2484 goto done;
2485 } else {
2486 sinfo->bss_param.dtim_period = dtim_period;
2487 brcmf_dbg(CONN, "DTIM peroid %d\n",
2488 dtim_period);
2489 }
319090bf 2490 sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
1a873342
HM
2491 }
2492 } else
2493 err = -EPERM;
5b435de0 2494done:
d96b801f 2495 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2496 return err;
2497}
2498
2499static s32
2500brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2501 bool enabled, s32 timeout)
2502{
2503 s32 pm;
2504 s32 err = 0;
27a68fe3 2505 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2506 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2507
d96b801f 2508 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2509
2510 /*
2511 * Powersave enable/disable request is coming from the
2512 * cfg80211 even before the interface is up. In that
2513 * scenario, driver will be storing the power save
27a68fe3 2514 * preference in cfg struct to apply this to
5b435de0
AS
2515 * FW later while initializing the dongle
2516 */
27a68fe3 2517 cfg->pwr_save = enabled;
ce81e317 2518 if (!check_vif_up(ifp->vif)) {
5b435de0 2519
647c9ae0 2520 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
5b435de0
AS
2521 goto done;
2522 }
2523
2524 pm = enabled ? PM_FAST : PM_OFF;
102fd0d6
HM
2525 /* Do not enable the power save after assoc if it is a p2p interface */
2526 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2527 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2528 pm = PM_OFF;
2529 }
647c9ae0 2530 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2531
c1179033 2532 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2533 if (err) {
2534 if (err == -ENODEV)
57d6e91a 2535 brcmf_err("net_device is not ready yet\n");
5b435de0 2536 else
57d6e91a 2537 brcmf_err("error (%d)\n", err);
5b435de0
AS
2538 }
2539done:
d96b801f 2540 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2541 return err;
2542}
2543
27a68fe3 2544static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2545 struct brcmf_bss_info_le *bi)
5b435de0 2546{
27a68fe3 2547 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2548 struct ieee80211_channel *notify_channel;
2549 struct cfg80211_bss *bss;
2550 struct ieee80211_supported_band *band;
83cf17aa 2551 struct brcmu_chan ch;
5b435de0
AS
2552 u16 channel;
2553 u32 freq;
5b435de0
AS
2554 u16 notify_capability;
2555 u16 notify_interval;
2556 u8 *notify_ie;
2557 size_t notify_ielen;
2558 s32 notify_signal;
2559
2560 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2561 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2562 return 0;
2563 }
2564
83cf17aa
FL
2565 if (!bi->ctl_ch) {
2566 ch.chspec = le16_to_cpu(bi->chanspec);
2567 cfg->d11inf.decchspec(&ch);
2568 bi->ctl_ch = ch.chnum;
2569 }
2570 channel = bi->ctl_ch;
5b435de0
AS
2571
2572 if (channel <= CH_MAX_2G_CHANNEL)
2573 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2574 else
2575 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2576
2577 freq = ieee80211_channel_to_frequency(channel, band->band);
2578 notify_channel = ieee80211_get_channel(wiphy, freq);
2579
5b435de0
AS
2580 notify_capability = le16_to_cpu(bi->capability);
2581 notify_interval = le16_to_cpu(bi->beacon_period);
2582 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2583 notify_ielen = le32_to_cpu(bi->ie_length);
2584 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2585
16886735
AS
2586 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2587 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2588 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2589 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2590 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0 2591
5bc8c1f2
JB
2592 bss = cfg80211_inform_bss(wiphy, notify_channel,
2593 CFG80211_BSS_FTYPE_UNKNOWN,
2594 (const u8 *)bi->BSSID,
2595 0, notify_capability,
2596 notify_interval, notify_ie,
2597 notify_ielen, notify_signal,
2598 GFP_KERNEL);
5b435de0 2599
e78946e1
FL
2600 if (!bss)
2601 return -ENOMEM;
2602
5b112d3d 2603 cfg80211_put_bss(wiphy, bss);
5b435de0 2604
12f32370 2605 return 0;
5b435de0
AS
2606}
2607
6f09be0a
RV
2608static struct brcmf_bss_info_le *
2609next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2610{
2611 if (bss == NULL)
2612 return list->bss_info_le;
2613 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2614 le32_to_cpu(bss->length));
2615}
2616
27a68fe3 2617static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2618{
2619 struct brcmf_scan_results *bss_list;
d34bf64f 2620 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2621 s32 err = 0;
2622 int i;
2623
ef8596e1 2624 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
0ecd8164
AS
2625 if (bss_list->count != 0 &&
2626 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2627 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2628 bss_list->version);
5b435de0
AS
2629 return -EOPNOTSUPP;
2630 }
4e8a008e 2631 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2632 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2633 bi = next_bss_le(bss_list, bi);
27a68fe3 2634 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2635 if (err)
2636 break;
2637 }
2638 return err;
2639}
2640
27a68fe3 2641static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2642 struct net_device *ndev, const u8 *bssid)
2643{
27a68fe3 2644 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2645 struct ieee80211_channel *notify_channel;
d34bf64f 2646 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2647 struct ieee80211_supported_band *band;
e78946e1 2648 struct cfg80211_bss *bss;
83cf17aa 2649 struct brcmu_chan ch;
5b435de0
AS
2650 u8 *buf = NULL;
2651 s32 err = 0;
5b435de0 2652 u32 freq;
5b435de0
AS
2653 u16 notify_capability;
2654 u16 notify_interval;
2655 u8 *notify_ie;
2656 size_t notify_ielen;
2657 s32 notify_signal;
2658
d96b801f 2659 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2660
2661 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2662 if (buf == NULL) {
2663 err = -ENOMEM;
2664 goto CleanUp;
2665 }
2666
2667 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2668
ac24be6f
AS
2669 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2670 buf, WL_BSS_INFO_MAX);
5b435de0 2671 if (err) {
57d6e91a 2672 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2673 goto CleanUp;
2674 }
2675
d34bf64f 2676 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0 2677
83cf17aa
FL
2678 ch.chspec = le16_to_cpu(bi->chanspec);
2679 cfg->d11inf.decchspec(&ch);
5b435de0 2680
83cf17aa 2681 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
2682 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2683 else
2684 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2685
83cf17aa 2686 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
2687 notify_channel = ieee80211_get_channel(wiphy, freq);
2688
5b435de0
AS
2689 notify_capability = le16_to_cpu(bi->capability);
2690 notify_interval = le16_to_cpu(bi->beacon_period);
2691 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2692 notify_ielen = le32_to_cpu(bi->ie_length);
2693 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2694
83cf17aa 2695 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
16886735
AS
2696 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2697 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2698 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2699
5bc8c1f2
JB
2700 bss = cfg80211_inform_bss(wiphy, notify_channel,
2701 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2702 notify_capability, notify_interval,
2703 notify_ie, notify_ielen, notify_signal,
2704 GFP_KERNEL);
5b435de0 2705
e78946e1
FL
2706 if (!bss) {
2707 err = -ENOMEM;
2708 goto CleanUp;
2709 }
2710
5b112d3d 2711 cfg80211_put_bss(wiphy, bss);
e78946e1 2712
5b435de0
AS
2713CleanUp:
2714
2715 kfree(buf);
2716
d96b801f 2717 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2718
2719 return err;
2720}
2721
89286dc9
HM
2722static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2723 struct brcmf_if *ifp)
1a873342 2724{
89286dc9 2725 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
d34bf64f 2726 struct brcmf_bss_info_le *bi;
5b435de0 2727 struct brcmf_ssid *ssid;
4b5800fe 2728 const struct brcmf_tlv *tim;
5b435de0
AS
2729 u16 beacon_interval;
2730 u8 dtim_period;
2731 size_t ie_len;
2732 u8 *ie;
2733 s32 err = 0;
2734
d96b801f 2735 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2736 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2737 return err;
2738
06bb123e 2739 ssid = &profile->ssid;
5b435de0 2740
27a68fe3 2741 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2742 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2743 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2744 if (err) {
57d6e91a 2745 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2746 goto update_bss_info_out;
2747 }
2748
27a68fe3
AS
2749 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2750 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2751 if (err)
2752 goto update_bss_info_out;
2753
2754 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2755 ie_len = le32_to_cpu(bi->ie_length);
2756 beacon_interval = le16_to_cpu(bi->beacon_period);
2757
f8e4b412 2758 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2759 if (tim)
2760 dtim_period = tim->data[1];
2761 else {
2762 /*
2763 * active scan was done so we could not get dtim
2764 * information out of probe response.
2765 * so we speficially query dtim information to dongle.
2766 */
2767 u32 var;
ac24be6f 2768 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2769 if (err) {
57d6e91a 2770 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2771 goto update_bss_info_out;
2772 }
2773 dtim_period = (u8)var;
2774 }
2775
5b435de0 2776update_bss_info_out:
d96b801f 2777 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2778 return err;
2779}
2780
18e2f61d 2781void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2782{
27a68fe3 2783 struct escan_info *escan = &cfg->escan_info;
5b435de0 2784
c1179033 2785 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2786 if (cfg->scan_request) {
108a4bee 2787 escan->escan_state = WL_ESCAN_STATE_IDLE;
a0f472ac 2788 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
5b435de0 2789 }
c1179033
AS
2790 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2791 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2792}
2793
e756af5b
HM
2794static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2795{
27a68fe3
AS
2796 struct brcmf_cfg80211_info *cfg =
2797 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2798 escan_timeout_work);
2799
ef8596e1 2800 brcmf_inform_bss(cfg);
a0f472ac 2801 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
e756af5b
HM
2802}
2803
2804static void brcmf_escan_timeout(unsigned long data)
2805{
27a68fe3
AS
2806 struct brcmf_cfg80211_info *cfg =
2807 (struct brcmf_cfg80211_info *)data;
e756af5b 2808
27a68fe3 2809 if (cfg->scan_request) {
57d6e91a 2810 brcmf_err("timer expired\n");
f0799895 2811 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2812 }
2813}
2814
2815static s32
83cf17aa
FL
2816brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2817 struct brcmf_bss_info_le *bss,
e756af5b
HM
2818 struct brcmf_bss_info_le *bss_info_le)
2819{
83cf17aa
FL
2820 struct brcmu_chan ch_bss, ch_bss_info_le;
2821
2822 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2823 cfg->d11inf.decchspec(&ch_bss);
2824 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2825 cfg->d11inf.decchspec(&ch_bss_info_le);
2826
e756af5b 2827 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
83cf17aa 2828 ch_bss.band == ch_bss_info_le.band &&
e756af5b
HM
2829 bss_info_le->SSID_len == bss->SSID_len &&
2830 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
6f5838a4
AS
2831 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2832 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2833 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2834 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2835
e756af5b
HM
2836 /* preserve max RSSI if the measurements are
2837 * both on-channel or both off-channel
2838 */
029591f3 2839 if (bss_info_rssi > bss_rssi)
e756af5b 2840 bss->RSSI = bss_info_le->RSSI;
6f5838a4
AS
2841 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2842 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
e756af5b
HM
2843 /* preserve the on-channel rssi measurement
2844 * if the new measurement is off channel
2845 */
2846 bss->RSSI = bss_info_le->RSSI;
6f5838a4 2847 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
e756af5b
HM
2848 }
2849 return 1;
2850 }
2851 return 0;
2852}
2853
2854static s32
1993732e 2855brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2856 const struct brcmf_event_msg *e, void *data)
2857{
1993732e 2858 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e756af5b 2859 s32 status;
e756af5b
HM
2860 struct brcmf_escan_result_le *escan_result_le;
2861 struct brcmf_bss_info_le *bss_info_le;
2862 struct brcmf_bss_info_le *bss = NULL;
2863 u32 bi_length;
2864 struct brcmf_scan_results *list;
2865 u32 i;
97ed15c7 2866 bool aborted;
e756af5b 2867
5c36b99a 2868 status = e->status;
e756af5b 2869
a0f472ac
AS
2870 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2871 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
e756af5b
HM
2872 return -EPERM;
2873 }
2874
2875 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2876 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2877 escan_result_le = (struct brcmf_escan_result_le *) data;
2878 if (!escan_result_le) {
57d6e91a 2879 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2880 goto exit;
2881 }
e756af5b 2882 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2883 brcmf_err("Invalid bss_count %d: ignoring\n",
2884 escan_result_le->bss_count);
e756af5b
HM
2885 goto exit;
2886 }
2887 bss_info_le = &escan_result_le->bss_info_le;
2888
6eda4e2c
HM
2889 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2890 goto exit;
2891
2892 if (!cfg->scan_request) {
2893 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2894 goto exit;
2895 }
2896
e756af5b
HM
2897 bi_length = le32_to_cpu(bss_info_le->length);
2898 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2899 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
2900 brcmf_err("Invalid bss_info length %d: ignoring\n",
2901 bi_length);
e756af5b
HM
2902 goto exit;
2903 }
2904
27a68fe3 2905 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2906 BIT(NL80211_IFTYPE_ADHOC))) {
2907 if (le16_to_cpu(bss_info_le->capability) &
2908 WLAN_CAPABILITY_IBSS) {
57d6e91a 2909 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
2910 goto exit;
2911 }
2912 }
2913
2914 list = (struct brcmf_scan_results *)
27a68fe3 2915 cfg->escan_info.escan_buf;
e756af5b 2916 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 2917 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
2918 goto exit;
2919 }
2920
2921 for (i = 0; i < list->count; i++) {
2922 bss = bss ? (struct brcmf_bss_info_le *)
2923 ((unsigned char *)bss +
2924 le32_to_cpu(bss->length)) : list->bss_info_le;
83cf17aa
FL
2925 if (brcmf_compare_update_same_bss(cfg, bss,
2926 bss_info_le))
e756af5b
HM
2927 goto exit;
2928 }
27a68fe3 2929 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2930 bss_info_le, bi_length);
2931 list->version = le32_to_cpu(bss_info_le->version);
2932 list->buflen += bi_length;
2933 list->count++;
2934 } else {
27a68fe3 2935 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
2936 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2937 goto exit;
27a68fe3 2938 if (cfg->scan_request) {
27a68fe3 2939 brcmf_inform_bss(cfg);
97ed15c7 2940 aborted = status != BRCMF_E_STATUS_SUCCESS;
ef8596e1 2941 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
e756af5b 2942 } else
6eda4e2c
HM
2943 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2944 status);
e756af5b
HM
2945 }
2946exit:
12f32370 2947 return 0;
e756af5b
HM
2948}
2949
27a68fe3 2950static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 2951{
5c36b99a
AS
2952 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2953 brcmf_cfg80211_escan_handler);
f0799895
HM
2954 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2955 /* Init scan_timeout timer */
2956 init_timer(&cfg->escan_timeout);
2957 cfg->escan_timeout.data = (unsigned long) cfg;
2958 cfg->escan_timeout.function = brcmf_escan_timeout;
2959 INIT_WORK(&cfg->escan_timeout_work,
2960 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2961}
2962
5addc0de 2963static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2964{
2965 if (ms < 1000 / HZ) {
2966 cond_resched();
2967 mdelay(ms);
2968 } else {
2969 msleep(ms);
2970 }
2971}
2972
b9a82f89
HM
2973static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
2974 u8 *pattern, u32 patternsize, u8 *mask,
2975 u32 packet_offset)
2976{
2977 struct brcmf_fil_wowl_pattern_le *filter;
2978 u32 masksize;
2979 u32 patternoffset;
2980 u8 *buf;
2981 u32 bufsize;
2982 s32 ret;
2983
2984 masksize = (patternsize + 7) / 8;
2985 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
2986
2987 bufsize = sizeof(*filter) + patternsize + masksize;
2988 buf = kzalloc(bufsize, GFP_KERNEL);
2989 if (!buf)
2990 return -ENOMEM;
2991 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
2992
2993 memcpy(filter->cmd, cmd, 4);
2994 filter->masksize = cpu_to_le32(masksize);
2995 filter->offset = cpu_to_le32(packet_offset);
2996 filter->patternoffset = cpu_to_le32(patternoffset);
2997 filter->patternsize = cpu_to_le32(patternsize);
2998 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
2999
3000 if ((mask) && (masksize))
3001 memcpy(buf + sizeof(*filter), mask, masksize);
3002 if ((pattern) && (patternsize))
3003 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3004
3005 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3006
3007 kfree(buf);
3008 return ret;
3009}
3010
5b435de0
AS
3011static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3012{
4eb3af7c
HM
3013 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3014 struct net_device *ndev = cfg_to_ndev(cfg);
3015 struct brcmf_if *ifp = netdev_priv(ndev);
3016
d96b801f 3017 brcmf_dbg(TRACE, "Enter\n");
5b435de0 3018
4eb3af7c 3019 if (cfg->wowl_enabled) {
b9a82f89 3020 brcmf_configure_arp_offload(ifp, true);
4eb3af7c
HM
3021 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
3022 cfg->pre_wowl_pmmode);
4eb3af7c 3023 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
b9a82f89 3024 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
4eb3af7c
HM
3025 cfg->wowl_enabled = false;
3026 }
5b435de0
AS
3027 return 0;
3028}
3029
4eb3af7c
HM
3030static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3031 struct brcmf_if *ifp,
3032 struct cfg80211_wowlan *wowl)
3033{
3034 u32 wowl_config;
b9a82f89 3035 u32 i;
4eb3af7c
HM
3036
3037 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3038
b9a82f89 3039 brcmf_configure_arp_offload(ifp, false);
4eb3af7c
HM
3040 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
3041 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3042
3043 wowl_config = 0;
3044 if (wowl->disconnect)
b9a82f89 3045 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
4eb3af7c 3046 if (wowl->magic_pkt)
b9a82f89
HM
3047 wowl_config |= BRCMF_WOWL_MAGIC;
3048 if ((wowl->patterns) && (wowl->n_patterns)) {
3049 wowl_config |= BRCMF_WOWL_NET;
3050 for (i = 0; i < wowl->n_patterns; i++) {
3051 brcmf_config_wowl_pattern(ifp, "add",
3052 (u8 *)wowl->patterns[i].pattern,
3053 wowl->patterns[i].pattern_len,
3054 (u8 *)wowl->patterns[i].mask,
3055 wowl->patterns[i].pkt_offset);
3056 }
3057 }
4eb3af7c
HM
3058 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3059 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3060 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
3061 cfg->wowl_enabled = true;
3062}
3063
5b435de0 3064static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
4eb3af7c 3065 struct cfg80211_wowlan *wowl)
5b435de0 3066{
27a68fe3
AS
3067 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3068 struct net_device *ndev = cfg_to_ndev(cfg);
4eb3af7c 3069 struct brcmf_if *ifp = netdev_priv(ndev);
7d641072 3070 struct brcmf_cfg80211_vif *vif;
5b435de0 3071
d96b801f 3072 brcmf_dbg(TRACE, "Enter\n");
5b435de0 3073
4eb3af7c 3074 /* if the primary net_device is not READY there is nothing
7d641072 3075 * we can do but pray resume goes smoothly.
5b435de0 3076 */
4eb3af7c 3077 if (!check_vif_up(ifp->vif))
7d641072 3078 goto exit;
5b435de0 3079
7d641072
AS
3080 /* end any scanning */
3081 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 3082 brcmf_abort_scanning(cfg);
5b435de0 3083
4eb3af7c
HM
3084 if (wowl == NULL) {
3085 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3086 list_for_each_entry(vif, &cfg->vif_list, list) {
3087 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3088 continue;
3089 /* While going to suspend if associated with AP
3090 * disassociate from AP to save power while system is
3091 * in suspended state
3092 */
9b7a0ddc 3093 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
4eb3af7c
HM
3094 /* Make sure WPA_Supplicant receives all the event
3095 * generated due to DISASSOC call to the fw to keep
3096 * the state fw and WPA_Supplicant state consistent
3097 */
3098 brcmf_delay(500);
3099 }
3100 /* Configure MPC */
3101 brcmf_set_mpc(ifp, 1);
3102
3103 } else {
3104 /* Configure WOWL paramaters */
3105 brcmf_configure_wowl(cfg, ifp, wowl);
3106 }
5b435de0 3107
7d641072 3108exit:
d96b801f 3109 brcmf_dbg(TRACE, "Exit\n");
7d641072
AS
3110 /* clear any scanning activity */
3111 cfg->scan_status = 0;
5b435de0
AS
3112 return 0;
3113}
3114
5b435de0
AS
3115static __used s32
3116brcmf_update_pmklist(struct net_device *ndev,
3117 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
3118{
3119 int i, j;
c15d789e 3120 u32 pmkid_len;
5b435de0 3121
40c8e95a
AS
3122 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
3123
16886735 3124 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
40c8e95a 3125 for (i = 0; i < pmkid_len; i++) {
16886735
AS
3126 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
3127 &pmk_list->pmkids.pmkid[i].BSSID);
5b435de0 3128 for (j = 0; j < WLAN_PMKID_LEN; j++)
16886735
AS
3129 brcmf_dbg(CONN, "%02x\n",
3130 pmk_list->pmkids.pmkid[i].PMKID[j]);
5b435de0
AS
3131 }
3132
3133 if (!err)
ac24be6f
AS
3134 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
3135 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
3136
3137 return err;
3138}
3139
3140static s32
3141brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3142 struct cfg80211_pmksa *pmksa)
3143{
27a68fe3 3144 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3145 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3146 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0 3147 s32 err = 0;
c15d789e 3148 u32 pmkid_len, i;
5b435de0 3149
d96b801f 3150 brcmf_dbg(TRACE, "Enter\n");
ce81e317 3151 if (!check_vif_up(ifp->vif))
5b435de0
AS
3152 return -EIO;
3153
40c8e95a
AS
3154 pmkid_len = le32_to_cpu(pmkids->npmkid);
3155 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
3156 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
3157 break;
3158 if (i < WL_NUM_PMKIDS_MAX) {
3159 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
3160 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
3161 if (i == pmkid_len) {
3162 pmkid_len++;
3163 pmkids->npmkid = cpu_to_le32(pmkid_len);
3164 }
5b435de0
AS
3165 } else
3166 err = -EINVAL;
3167
16886735
AS
3168 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
3169 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 3170 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 3171 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 3172
27a68fe3 3173 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 3174
d96b801f 3175 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
3176 return err;
3177}
3178
3179static s32
3180brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3181 struct cfg80211_pmksa *pmksa)
3182{
27a68fe3 3183 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3184 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3185 struct pmkid_list pmkid;
3186 s32 err = 0;
c15d789e 3187 u32 pmkid_len, i;
5b435de0 3188
d96b801f 3189 brcmf_dbg(TRACE, "Enter\n");
ce81e317 3190 if (!check_vif_up(ifp->vif))
5b435de0
AS
3191 return -EIO;
3192
3193 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
3194 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
3195
16886735
AS
3196 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3197 &pmkid.pmkid[0].BSSID);
5b435de0 3198 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 3199 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
5b435de0 3200
27a68fe3 3201 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 3202 for (i = 0; i < pmkid_len; i++)
5b435de0 3203 if (!memcmp
27a68fe3 3204 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
3205 ETH_ALEN))
3206 break;
3207
40c8e95a
AS
3208 if ((pmkid_len > 0)
3209 && (i < pmkid_len)) {
27a68fe3 3210 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 3211 sizeof(struct pmkid));
40c8e95a 3212 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
3213 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
3214 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 3215 ETH_ALEN);
27a68fe3
AS
3216 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
3217 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
3218 WLAN_PMKID_LEN);
3219 }
27a68fe3 3220 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
3221 } else
3222 err = -EINVAL;
3223
27a68fe3 3224 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 3225
d96b801f 3226 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
3227 return err;
3228
3229}
3230
3231static s32
3232brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3233{
27a68fe3 3234 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3235 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3236 s32 err = 0;
3237
d96b801f 3238 brcmf_dbg(TRACE, "Enter\n");
ce81e317 3239 if (!check_vif_up(ifp->vif))
5b435de0
AS
3240 return -EIO;
3241
27a68fe3
AS
3242 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
3243 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 3244
d96b801f 3245 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
3246 return err;
3247
3248}
3249
e5806072
AS
3250/*
3251 * PFN result doesn't have all the info which are
3252 * required by the supplicant
3253 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3254 * via wl_inform_single_bss in the required format. Escan does require the
3255 * scan request in the form of cfg80211_scan_request. For timebeing, create
3256 * cfg80211_scan_request one out of the received PNO event.
3257 */
3258static s32
1993732e 3259brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
3260 const struct brcmf_event_msg *e, void *data)
3261{
1993732e 3262 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e5806072
AS
3263 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3264 struct cfg80211_scan_request *request = NULL;
3265 struct cfg80211_ssid *ssid = NULL;
3266 struct ieee80211_channel *channel = NULL;
27a68fe3 3267 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
3268 int err = 0;
3269 int channel_req = 0;
3270 int band = 0;
3271 struct brcmf_pno_scanresults_le *pfn_result;
3272 u32 result_count;
3273 u32 status;
3274
4e8a008e 3275 brcmf_dbg(SCAN, "Enter\n");
e5806072 3276
5c36b99a 3277 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
4e8a008e 3278 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
e5806072
AS
3279 return 0;
3280 }
3281
3282 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3283 result_count = le32_to_cpu(pfn_result->count);
3284 status = le32_to_cpu(pfn_result->status);
3285
3286 /*
3287 * PFN event is limited to fit 512 bytes so we may get
3288 * multiple NET_FOUND events. For now place a warning here.
3289 */
3290 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
4e8a008e 3291 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
e5806072
AS
3292 if (result_count > 0) {
3293 int i;
3294
3295 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
3296 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3297 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
3298 if (!request || !ssid || !channel) {
3299 err = -ENOMEM;
3300 goto out_err;
3301 }
3302
3303 request->wiphy = wiphy;
3304 data += sizeof(struct brcmf_pno_scanresults_le);
3305 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3306
3307 for (i = 0; i < result_count; i++) {
3308 netinfo = &netinfo_start[i];
3309 if (!netinfo) {
57d6e91a
AS
3310 brcmf_err("Invalid netinfo ptr. index: %d\n",
3311 i);
e5806072
AS
3312 err = -EINVAL;
3313 goto out_err;
3314 }
3315
4e8a008e
AS
3316 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3317 netinfo->SSID, netinfo->channel);
e5806072
AS
3318 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3319 ssid[i].ssid_len = netinfo->SSID_len;
3320 request->n_ssids++;
3321
3322 channel_req = netinfo->channel;
3323 if (channel_req <= CH_MAX_2G_CHANNEL)
3324 band = NL80211_BAND_2GHZ;
3325 else
3326 band = NL80211_BAND_5GHZ;
3327 channel[i].center_freq =
3328 ieee80211_channel_to_frequency(channel_req,
3329 band);
3330 channel[i].band = band;
3331 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3332 request->channels[i] = &channel[i];
3333 request->n_channels++;
3334 }
3335
3336 /* assign parsed ssid array */
3337 if (request->n_ssids)
3338 request->ssids = &ssid[0];
3339
c1179033 3340 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 3341 /* Abort any on-going scan */
27a68fe3 3342 brcmf_abort_scanning(cfg);
e5806072
AS
3343 }
3344
c1179033 3345 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2668b0b1 3346 cfg->escan_info.run = brcmf_run_escan;
a0f472ac 3347 err = brcmf_do_escan(cfg, wiphy, ifp, request);
e5806072 3348 if (err) {
c1179033 3349 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
3350 goto out_err;
3351 }
27a68fe3
AS
3352 cfg->sched_escan = true;
3353 cfg->scan_request = request;
e5806072 3354 } else {
57d6e91a 3355 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
e5806072
AS
3356 goto out_err;
3357 }
3358
3359 kfree(ssid);
3360 kfree(channel);
3361 kfree(request);
3362 return 0;
3363
3364out_err:
3365 kfree(ssid);
3366 kfree(channel);
3367 kfree(request);
3368 cfg80211_sched_scan_stopped(wiphy);
3369 return err;
3370}
3371
e5806072
AS
3372static int brcmf_dev_pno_clean(struct net_device *ndev)
3373{
e5806072
AS
3374 int ret;
3375
3376 /* Disable pfn */
ac24be6f 3377 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3378 if (ret == 0) {
3379 /* clear pfn */
ac24be6f
AS
3380 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3381 NULL, 0);
e5806072
AS
3382 }
3383 if (ret < 0)
57d6e91a 3384 brcmf_err("failed code %d\n", ret);
e5806072
AS
3385
3386 return ret;
3387}
3388
3389static int brcmf_dev_pno_config(struct net_device *ndev)
3390{
3391 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3392
3393 memset(&pfn_param, 0, sizeof(pfn_param));
3394 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3395
3396 /* set extra pno params */
3397 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3398 pfn_param.repeat = BRCMF_PNO_REPEAT;
3399 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3400
3401 /* set up pno scan fr */
3402 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3403
ac24be6f
AS
3404 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3405 &pfn_param, sizeof(pfn_param));
e5806072
AS
3406}
3407
3408static int
3409brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3410 struct net_device *ndev,
3411 struct cfg80211_sched_scan_request *request)
3412{
c1179033 3413 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3414 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3415 struct brcmf_pno_net_param_le pfn;
3416 int i;
3417 int ret = 0;
3418
dc7bdbf1 3419 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
4e8a008e 3420 request->n_match_sets, request->n_ssids);
c1179033 3421 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 3422 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3423 return -EAGAIN;
3424 }
1687eee2
AS
3425 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3426 brcmf_err("Scanning suppressed: status (%lu)\n",
3427 cfg->scan_status);
3428 return -EAGAIN;
3429 }
e5806072 3430
dc7bdbf1 3431 if (!request->n_ssids || !request->n_match_sets) {
181f2d17 3432 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
dc7bdbf1 3433 request->n_ssids);
e5806072
AS
3434 return -EINVAL;
3435 }
3436
3437 if (request->n_ssids > 0) {
3438 for (i = 0; i < request->n_ssids; i++) {
3439 /* Active scan req for ssids */
4e8a008e
AS
3440 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3441 request->ssids[i].ssid);
e5806072
AS
3442
3443 /*
3444 * match_set ssids is a supert set of n_ssid list,
3445 * so we need not add these set seperately.
3446 */
3447 }
3448 }
3449
3450 if (request->n_match_sets > 0) {
3451 /* clean up everything */
3452 ret = brcmf_dev_pno_clean(ndev);
3453 if (ret < 0) {
57d6e91a 3454 brcmf_err("failed error=%d\n", ret);
e5806072
AS
3455 return ret;
3456 }
3457
3458 /* configure pno */
3459 ret = brcmf_dev_pno_config(ndev);
3460 if (ret < 0) {
57d6e91a 3461 brcmf_err("PNO setup failed!! ret=%d\n", ret);
e5806072
AS
3462 return -EINVAL;
3463 }
3464
3465 /* configure each match set */
3466 for (i = 0; i < request->n_match_sets; i++) {
3467 struct cfg80211_ssid *ssid;
3468 u32 ssid_len;
3469
3470 ssid = &request->match_sets[i].ssid;
3471 ssid_len = ssid->ssid_len;
3472
3473 if (!ssid_len) {
57d6e91a 3474 brcmf_err("skip broadcast ssid\n");
e5806072
AS
3475 continue;
3476 }
3477 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3478 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3479 pfn.wsec = cpu_to_le32(0);
3480 pfn.infra = cpu_to_le32(1);
3481 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3482 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3483 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3484 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3485 sizeof(pfn));
4e8a008e
AS
3486 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3487 ret == 0 ? "set" : "failed", ssid->ssid);
e5806072
AS
3488 }
3489 /* Enable the PNO */
c1179033 3490 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
57d6e91a 3491 brcmf_err("PNO enable failed!! ret=%d\n", ret);
e5806072
AS
3492 return -EINVAL;
3493 }
3494 } else {
3495 return -EINVAL;
3496 }
3497
3498 return 0;
3499}
3500
3501static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3502 struct net_device *ndev)
3503{
27a68fe3 3504 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072 3505
4e8a008e 3506 brcmf_dbg(SCAN, "enter\n");
e5806072 3507 brcmf_dev_pno_clean(ndev);
27a68fe3 3508 if (cfg->sched_escan)
a0f472ac 3509 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
e5806072
AS
3510 return 0;
3511}
e5806072 3512
1f170110 3513static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3514{
3515 s32 err;
3516
3517 /* set auth */
ac24be6f 3518 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3519 if (err < 0) {
57d6e91a 3520 brcmf_err("auth error %d\n", err);
1a873342
HM
3521 return err;
3522 }
3523 /* set wsec */
ac24be6f 3524 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3525 if (err < 0) {
57d6e91a 3526 brcmf_err("wsec error %d\n", err);
1a873342
HM
3527 return err;
3528 }
3529 /* set upper-layer auth */
ac24be6f 3530 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3531 if (err < 0) {
57d6e91a 3532 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3533 return err;
3534 }
3535
3536 return 0;
3537}
3538
3539static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3540{
3541 if (is_rsn_ie)
3542 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3543
3544 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3545}
3546
3547static s32
a44aa400 3548brcmf_configure_wpaie(struct brcmf_if *ifp,
4b5800fe
JB
3549 const struct brcmf_vs_tlv *wpa_ie,
3550 bool is_rsn_ie)
1a873342
HM
3551{
3552 u32 auth = 0; /* d11 open authentication */
3553 u16 count;
3554 s32 err = 0;
3555 s32 len = 0;
3556 u32 i;
3557 u32 wsec;
3558 u32 pval = 0;
3559 u32 gval = 0;
3560 u32 wpa_auth = 0;
3561 u32 offset;
3562 u8 *data;
3563 u16 rsn_cap;
3564 u32 wme_bss_disable;
3565
d96b801f 3566 brcmf_dbg(TRACE, "Enter\n");
1a873342
HM
3567 if (wpa_ie == NULL)
3568 goto exit;
3569
3570 len = wpa_ie->len + TLV_HDR_LEN;
3571 data = (u8 *)wpa_ie;
619c5a9a 3572 offset = TLV_HDR_LEN;
1a873342
HM
3573 if (!is_rsn_ie)
3574 offset += VS_IE_FIXED_HDR_LEN;
619c5a9a
HM
3575 else
3576 offset += WPA_IE_VERSION_LEN;
1a873342
HM
3577
3578 /* check for multicast cipher suite */
3579 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3580 err = -EINVAL;
57d6e91a 3581 brcmf_err("no multicast cipher suite\n");
1a873342
HM
3582 goto exit;
3583 }
3584
3585 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3586 err = -EINVAL;
57d6e91a 3587 brcmf_err("ivalid OUI\n");
1a873342
HM
3588 goto exit;
3589 }
3590 offset += TLV_OUI_LEN;
3591
3592 /* pick up multicast cipher */
3593 switch (data[offset]) {
3594 case WPA_CIPHER_NONE:
3595 gval = 0;
3596 break;
3597 case WPA_CIPHER_WEP_40:
3598 case WPA_CIPHER_WEP_104:
3599 gval = WEP_ENABLED;
3600 break;
3601 case WPA_CIPHER_TKIP:
3602 gval = TKIP_ENABLED;
3603 break;
3604 case WPA_CIPHER_AES_CCM:
3605 gval = AES_ENABLED;
3606 break;
3607 default:
3608 err = -EINVAL;
57d6e91a 3609 brcmf_err("Invalid multi cast cipher info\n");
1a873342
HM
3610 goto exit;
3611 }
3612
3613 offset++;
3614 /* walk thru unicast cipher list and pick up what we recognize */
3615 count = data[offset] + (data[offset + 1] << 8);
3616 offset += WPA_IE_SUITE_COUNT_LEN;
3617 /* Check for unicast suite(s) */
3618 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3619 err = -EINVAL;
57d6e91a 3620 brcmf_err("no unicast cipher suite\n");
1a873342
HM
3621 goto exit;
3622 }
3623 for (i = 0; i < count; i++) {
3624 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3625 err = -EINVAL;
57d6e91a 3626 brcmf_err("ivalid OUI\n");
1a873342
HM
3627 goto exit;
3628 }
3629 offset += TLV_OUI_LEN;
3630 switch (data[offset]) {
3631 case WPA_CIPHER_NONE:
3632 break;
3633 case WPA_CIPHER_WEP_40:
3634 case WPA_CIPHER_WEP_104:
3635 pval |= WEP_ENABLED;
3636 break;
3637 case WPA_CIPHER_TKIP:
3638 pval |= TKIP_ENABLED;
3639 break;
3640 case WPA_CIPHER_AES_CCM:
3641 pval |= AES_ENABLED;
3642 break;
3643 default:
57d6e91a 3644 brcmf_err("Ivalid unicast security info\n");
1a873342
HM
3645 }
3646 offset++;
3647 }
3648 /* walk thru auth management suite list and pick up what we recognize */
3649 count = data[offset] + (data[offset + 1] << 8);
3650 offset += WPA_IE_SUITE_COUNT_LEN;
3651 /* Check for auth key management suite(s) */
3652 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3653 err = -EINVAL;
57d6e91a 3654 brcmf_err("no auth key mgmt suite\n");
1a873342
HM
3655 goto exit;
3656 }
3657 for (i = 0; i < count; i++) {
3658 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3659 err = -EINVAL;
57d6e91a 3660 brcmf_err("ivalid OUI\n");
1a873342
HM
3661 goto exit;
3662 }
3663 offset += TLV_OUI_LEN;
3664 switch (data[offset]) {
3665 case RSN_AKM_NONE:
d96b801f 3666 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
1a873342
HM
3667 wpa_auth |= WPA_AUTH_NONE;
3668 break;
3669 case RSN_AKM_UNSPECIFIED:
d96b801f 3670 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
1a873342
HM
3671 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3672 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3673 break;
3674 case RSN_AKM_PSK:
d96b801f 3675 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
1a873342
HM
3676 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3677 (wpa_auth |= WPA_AUTH_PSK);
3678 break;
3679 default:
57d6e91a 3680 brcmf_err("Ivalid key mgmt info\n");
1a873342
HM
3681 }
3682 offset++;
3683 }
3684
3685 if (is_rsn_ie) {
3686 wme_bss_disable = 1;
3687 if ((offset + RSN_CAP_LEN) <= len) {
3688 rsn_cap = data[offset] + (data[offset + 1] << 8);
3689 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3690 wme_bss_disable = 0;
3691 }
3692 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3693 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3694 wme_bss_disable);
1a873342 3695 if (err < 0) {
57d6e91a 3696 brcmf_err("wme_bss_disable error %d\n", err);
1a873342
HM
3697 goto exit;
3698 }
3699 }
3700 /* FOR WPS , set SES_OW_ENABLED */
3701 wsec = (pval | gval | SES_OW_ENABLED);
3702
3703 /* set auth */
ac24be6f 3704 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342 3705 if (err < 0) {
57d6e91a 3706 brcmf_err("auth error %d\n", err);
1a873342
HM
3707 goto exit;
3708 }
3709 /* set wsec */
ac24be6f 3710 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342 3711 if (err < 0) {
57d6e91a 3712 brcmf_err("wsec error %d\n", err);
1a873342
HM
3713 goto exit;
3714 }
3715 /* set upper-layer auth */
ac24be6f 3716 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342 3717 if (err < 0) {
57d6e91a 3718 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3719 goto exit;
3720 }
3721
3722exit:
3723 return err;
3724}
3725
3726static s32
3082b9be 3727brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
3728 struct parsed_vndr_ies *vndr_ies)
3729{
1a873342
HM
3730 struct brcmf_vs_tlv *vndrie;
3731 struct brcmf_tlv *ie;
3732 struct parsed_vndr_ie_info *parsed_info;
3733 s32 remaining_len;
3734
3735 remaining_len = (s32)vndr_ie_len;
3736 memset(vndr_ies, 0, sizeof(*vndr_ies));
3737
3738 ie = (struct brcmf_tlv *)vndr_ie_buf;
3739 while (ie) {
3740 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3741 goto next;
3742 vndrie = (struct brcmf_vs_tlv *)ie;
3743 /* len should be bigger than OUI length + one */
3744 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
57d6e91a
AS
3745 brcmf_err("invalid vndr ie. length is too small %d\n",
3746 vndrie->len);
1a873342
HM
3747 goto next;
3748 }
3749 /* if wpa or wme ie, do not add ie */
3750 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3751 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3752 (vndrie->oui_type == WME_OUI_TYPE))) {
d96b801f 3753 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
1a873342
HM
3754 goto next;
3755 }
3756
3757 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3758
3759 /* save vndr ie information */
3760 parsed_info->ie_ptr = (char *)vndrie;
3761 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3762 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3763
3764 vndr_ies->count++;
3765
d96b801f
AS
3766 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3767 parsed_info->vndrie.oui[0],
3768 parsed_info->vndrie.oui[1],
3769 parsed_info->vndrie.oui[2],
3770 parsed_info->vndrie.oui_type);
1a873342 3771
9f440b7b 3772 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
1a873342
HM
3773 break;
3774next:
b41fc3d7
HM
3775 remaining_len -= (ie->len + TLV_HDR_LEN);
3776 if (remaining_len <= TLV_HDR_LEN)
1a873342
HM
3777 ie = NULL;
3778 else
b41fc3d7
HM
3779 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3780 TLV_HDR_LEN);
1a873342 3781 }
12f32370 3782 return 0;
1a873342
HM
3783}
3784
3785static u32
3786brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3787{
3788
1a873342
HM
3789 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3790 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3791
362126cd 3792 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
1a873342 3793
362126cd 3794 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
1a873342
HM
3795
3796 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3797
3798 return ie_len + VNDR_IE_HDR_SIZE;
3799}
3800
1332e26e
AS
3801s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3802 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 3803{
1332e26e
AS
3804 struct brcmf_if *ifp;
3805 struct vif_saved_ie *saved_ie;
1a873342
HM
3806 s32 err = 0;
3807 u8 *iovar_ie_buf;
3808 u8 *curr_ie_buf;
3809 u8 *mgmt_ie_buf = NULL;
3e4f319d 3810 int mgmt_ie_buf_len;
81118d16 3811 u32 *mgmt_ie_len;
1a873342
HM
3812 u32 del_add_ie_buf_len = 0;
3813 u32 total_ie_buf_len = 0;
3814 u32 parsed_ie_buf_len = 0;
3815 struct parsed_vndr_ies old_vndr_ies;
3816 struct parsed_vndr_ies new_vndr_ies;
3817 struct parsed_vndr_ie_info *vndrie_info;
3818 s32 i;
3819 u8 *ptr;
3e4f319d 3820 int remained_buf_len;
1a873342 3821
1332e26e
AS
3822 if (!vif)
3823 return -ENODEV;
3824 ifp = vif->ifp;
3825 saved_ie = &vif->saved_ie;
3826
d96b801f 3827 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
1a873342
HM
3828 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3829 if (!iovar_ie_buf)
3830 return -ENOMEM;
3831 curr_ie_buf = iovar_ie_buf;
89286dc9
HM
3832 switch (pktflag) {
3833 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3834 mgmt_ie_buf = saved_ie->probe_req_ie;
3835 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3836 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3837 break;
3838 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3839 mgmt_ie_buf = saved_ie->probe_res_ie;
3840 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3841 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3842 break;
3843 case BRCMF_VNDR_IE_BEACON_FLAG:
3844 mgmt_ie_buf = saved_ie->beacon_ie;
3845 mgmt_ie_len = &saved_ie->beacon_ie_len;
3846 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3847 break;
3848 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3849 mgmt_ie_buf = saved_ie->assoc_req_ie;
3850 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3851 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3852 break;
3853 default:
3854 err = -EPERM;
3855 brcmf_err("not suitable type\n");
3856 goto exit;
1a873342
HM
3857 }
3858
3859 if (vndr_ie_len > mgmt_ie_buf_len) {
3860 err = -ENOMEM;
57d6e91a 3861 brcmf_err("extra IE size too big\n");
1a873342
HM
3862 goto exit;
3863 }
3864
3865 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3866 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3867 ptr = curr_ie_buf;
3868 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3869 for (i = 0; i < new_vndr_ies.count; i++) {
3870 vndrie_info = &new_vndr_ies.ie_info[i];
3871 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3872 vndrie_info->ie_len);
3873 parsed_ie_buf_len += vndrie_info->ie_len;
3874 }
3875 }
3876
b41fc3d7 3877 if (mgmt_ie_buf && *mgmt_ie_len) {
1a873342
HM
3878 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3879 (memcmp(mgmt_ie_buf, curr_ie_buf,
3880 parsed_ie_buf_len) == 0)) {
d96b801f 3881 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
1a873342
HM
3882 goto exit;
3883 }
3884
3885 /* parse old vndr_ie */
3886 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3887
3888 /* make a command to delete old ie */
3889 for (i = 0; i < old_vndr_ies.count; i++) {
3890 vndrie_info = &old_vndr_ies.ie_info[i];
3891
d96b801f
AS
3892 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3893 vndrie_info->vndrie.id,
3894 vndrie_info->vndrie.len,
3895 vndrie_info->vndrie.oui[0],
3896 vndrie_info->vndrie.oui[1],
3897 vndrie_info->vndrie.oui[2]);
1a873342
HM
3898
3899 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3900 vndrie_info->ie_ptr,
3901 vndrie_info->ie_len,
3902 "del");
3903 curr_ie_buf += del_add_ie_buf_len;
3904 total_ie_buf_len += del_add_ie_buf_len;
3905 }
3906 }
3907
3908 *mgmt_ie_len = 0;
3909 /* Add if there is any extra IE */
3910 if (mgmt_ie_buf && parsed_ie_buf_len) {
3911 ptr = mgmt_ie_buf;
3912
3913 remained_buf_len = mgmt_ie_buf_len;
3914
3915 /* make a command to add new ie */
3916 for (i = 0; i < new_vndr_ies.count; i++) {
3917 vndrie_info = &new_vndr_ies.ie_info[i];
3918
b41fc3d7
HM
3919 /* verify remained buf size before copy data */
3920 if (remained_buf_len < (vndrie_info->vndrie.len +
3921 VNDR_IE_VSIE_OFFSET)) {
57d6e91a
AS
3922 brcmf_err("no space in mgmt_ie_buf: len left %d",
3923 remained_buf_len);
b41fc3d7
HM
3924 break;
3925 }
3926 remained_buf_len -= (vndrie_info->ie_len +
3927 VNDR_IE_VSIE_OFFSET);
3928
d96b801f
AS
3929 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3930 vndrie_info->vndrie.id,
3931 vndrie_info->vndrie.len,
3932 vndrie_info->vndrie.oui[0],
3933 vndrie_info->vndrie.oui[1],
3934 vndrie_info->vndrie.oui[2]);
1a873342
HM
3935
3936 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3937 vndrie_info->ie_ptr,
3938 vndrie_info->ie_len,
3939 "add");
1a873342
HM
3940
3941 /* save the parsed IE in wl struct */
3942 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3943 vndrie_info->ie_len);
3944 *mgmt_ie_len += vndrie_info->ie_len;
3945
3946 curr_ie_buf += del_add_ie_buf_len;
3947 total_ie_buf_len += del_add_ie_buf_len;
3948 }
3949 }
3950 if (total_ie_buf_len) {
c1179033 3951 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3952 total_ie_buf_len);
1a873342 3953 if (err)
57d6e91a 3954 brcmf_err("vndr ie set error : %d\n", err);
1a873342
HM
3955 }
3956
3957exit:
3958 kfree(iovar_ie_buf);
3959 return err;
3960}
3961
5f4f9f11
AS
3962s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3963{
3964 s32 pktflags[] = {
3965 BRCMF_VNDR_IE_PRBREQ_FLAG,
3966 BRCMF_VNDR_IE_PRBRSP_FLAG,
3967 BRCMF_VNDR_IE_BEACON_FLAG
3968 };
3969 int i;
3970
3971 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3972 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3973
3974 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3975 return 0;
3976}
3977
a0f07959
HM
3978static s32
3979brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3980 struct cfg80211_beacon_data *beacon)
3981{
3982 s32 err;
3983
3984 /* Set Beacon IEs to FW */
3985 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3986 beacon->tail, beacon->tail_len);
3987 if (err) {
3988 brcmf_err("Set Beacon IE Failed\n");
3989 return err;
3990 }
3991 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3992
3993 /* Set Probe Response IEs to FW */
3994 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3995 beacon->proberesp_ies,
3996 beacon->proberesp_ies_len);
3997 if (err)
3998 brcmf_err("Set Probe Resp IE Failed\n");
3999 else
4000 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4001
4002 return err;
4003}
4004
1a873342
HM
4005static s32
4006brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4007 struct cfg80211_ap_settings *settings)
4008{
4009 s32 ie_offset;
1c9d30cf 4010 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
ac24be6f 4011 struct brcmf_if *ifp = netdev_priv(ndev);
4b5800fe 4012 const struct brcmf_tlv *ssid_ie;
98027769 4013 const struct brcmf_tlv *country_ie;
1a873342 4014 struct brcmf_ssid_le ssid_le;
1a873342 4015 s32 err = -EPERM;
4b5800fe
JB
4016 const struct brcmf_tlv *rsn_ie;
4017 const struct brcmf_vs_tlv *wpa_ie;
1a873342 4018 struct brcmf_join_params join_params;
a0f07959
HM
4019 enum nl80211_iftype dev_role;
4020 struct brcmf_fil_bss_enable_le bss_enable;
06c01585 4021 u16 chanspec;
a44aa400 4022 bool mbss;
98027769 4023 int is_11d;
1a873342 4024
06c01585
AS
4025 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4026 settings->chandef.chan->hw_value,
4027 settings->chandef.center_freq1, settings->chandef.width,
a9a56878 4028 settings->beacon_interval, settings->dtim_period);
d96b801f
AS
4029 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4030 settings->ssid, settings->ssid_len, settings->auth_type,
4031 settings->inactivity_timeout);
426d0a56 4032 dev_role = ifp->vif->wdev.iftype;
a44aa400 4033 mbss = ifp->vif->mbss;
1a873342 4034
98027769
AS
4035 /* store current 11d setting */
4036 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4037 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4038 settings->beacon.tail_len,
4039 WLAN_EID_COUNTRY);
4040 is_11d = country_ie ? 1 : 0;
4041
1a873342
HM
4042 memset(&ssid_le, 0, sizeof(ssid_le));
4043 if (settings->ssid == NULL || settings->ssid_len == 0) {
4044 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4045 ssid_ie = brcmf_parse_tlvs(
4046 (u8 *)&settings->beacon.head[ie_offset],
4047 settings->beacon.head_len - ie_offset,
4048 WLAN_EID_SSID);
4049 if (!ssid_ie)
4050 return -EINVAL;
4051
4052 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4053 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
d96b801f 4054 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
1a873342
HM
4055 } else {
4056 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4057 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4058 }
4059
a44aa400
HM
4060 if (!mbss) {
4061 brcmf_set_mpc(ifp, 0);
4062 brcmf_configure_arp_offload(ifp, false);
4063 }
1a873342
HM
4064
4065 /* find the RSN_IE */
4066 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4067 settings->beacon.tail_len, WLAN_EID_RSN);
4068
4069 /* find the WPA_IE */
4070 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4071 settings->beacon.tail_len);
4072
1a873342 4073 if ((wpa_ie != NULL || rsn_ie != NULL)) {
d96b801f 4074 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
1a873342
HM
4075 if (wpa_ie != NULL) {
4076 /* WPA IE */
a44aa400 4077 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
1a873342
HM
4078 if (err < 0)
4079 goto exit;
1a873342 4080 } else {
a44aa400
HM
4081 struct brcmf_vs_tlv *tmp_ie;
4082
4083 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4084
1a873342 4085 /* RSN IE */
a44aa400 4086 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
1a873342
HM
4087 if (err < 0)
4088 goto exit;
1a873342 4089 }
1a873342 4090 } else {
d96b801f 4091 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
1f170110 4092 brcmf_configure_opensecurity(ifp);
1a873342 4093 }
1a873342 4094
a0f07959 4095 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
1a873342 4096
a44aa400
HM
4097 if (!mbss) {
4098 chanspec = chandef_to_chanspec(&cfg->d11inf,
4099 &settings->chandef);
4100 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
1a873342 4101 if (err < 0) {
a44aa400
HM
4102 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4103 chanspec, err);
1a873342
HM
4104 goto exit;
4105 }
a44aa400 4106
98027769
AS
4107 if (is_11d != ifp->vif->is_11d) {
4108 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4109 is_11d);
4110 if (err < 0) {
4111 brcmf_err("Regulatory Set Error, %d\n", err);
4112 goto exit;
4113 }
4114 }
a44aa400
HM
4115 if (settings->beacon_interval) {
4116 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4117 settings->beacon_interval);
4118 if (err < 0) {
4119 brcmf_err("Beacon Interval Set Error, %d\n",
4120 err);
4121 goto exit;
4122 }
4123 }
4124 if (settings->dtim_period) {
4125 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4126 settings->dtim_period);
4127 if (err < 0) {
4128 brcmf_err("DTIM Interval Set Error, %d\n", err);
4129 goto exit;
4130 }
1a873342 4131 }
a0f07959 4132
a44aa400
HM
4133 if (dev_role == NL80211_IFTYPE_AP) {
4134 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4135 if (err < 0) {
4136 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4137 goto exit;
4138 }
4139 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4140 }
4141
4142 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
a0f07959 4143 if (err < 0) {
a44aa400 4144 brcmf_err("SET INFRA error %d\n", err);
a0f07959
HM
4145 goto exit;
4146 }
98027769
AS
4147 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4148 /* Multiple-BSS should use same 11d configuration */
4149 err = -EINVAL;
4150 goto exit;
1a873342 4151 }
a0f07959 4152 if (dev_role == NL80211_IFTYPE_AP) {
a44aa400
HM
4153 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4154 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4155
a0f07959
HM
4156 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4157 if (err < 0) {
4158 brcmf_err("setting AP mode failed %d\n", err);
4159 goto exit;
4160 }
4161 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4162 if (err < 0) {
4163 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4164 goto exit;
4165 }
118eb304
HM
4166 /* On DOWN the firmware removes the WEP keys, reconfigure
4167 * them if they were set.
4168 */
4169 brcmf_cfg80211_reconfigure_wep(ifp);
a0f07959
HM
4170
4171 memset(&join_params, 0, sizeof(join_params));
4172 /* join parameters starts with ssid */
4173 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4174 /* create softap */
4175 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4176 &join_params, sizeof(join_params));
4177 if (err < 0) {
4178 brcmf_err("SET SSID error (%d)\n", err);
4179 goto exit;
4180 }
4181 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4182 } else {
4183 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4184 sizeof(ssid_le));
4185 if (err < 0) {
4186 brcmf_err("setting ssid failed %d\n", err);
4187 goto exit;
4188 }
4189 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
4190 bss_enable.enable = cpu_to_le32(1);
4191 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4192 sizeof(bss_enable));
4193 if (err < 0) {
4194 brcmf_err("bss_enable config failed %d\n", err);
4195 goto exit;
4196 }
4197
4198 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4199 }
c1179033
AS
4200 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4201 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
4202
4203exit:
a44aa400 4204 if ((err) && (!mbss)) {
f96aa07e 4205 brcmf_set_mpc(ifp, 1);
b3657453
HM
4206 brcmf_configure_arp_offload(ifp, true);
4207 }
1a873342
HM
4208 return err;
4209}
4210
4211static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4212{
c1179033 4213 struct brcmf_if *ifp = netdev_priv(ndev);
5c33a942 4214 s32 err;
426d0a56 4215 struct brcmf_fil_bss_enable_le bss_enable;
5c33a942 4216 struct brcmf_join_params join_params;
1a873342 4217
d96b801f 4218 brcmf_dbg(TRACE, "Enter\n");
1a873342 4219
426d0a56 4220 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
1a873342
HM
4221 /* Due to most likely deauths outstanding we sleep */
4222 /* first to make sure they get processed by fw. */
4223 msleep(400);
5c33a942 4224
a44aa400
HM
4225 if (ifp->vif->mbss) {
4226 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4227 return err;
4228 }
4229
5c33a942
HM
4230 memset(&join_params, 0, sizeof(join_params));
4231 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4232 &join_params, sizeof(join_params));
4233 if (err < 0)
4234 brcmf_err("SET SSID error (%d)\n", err);
a44aa400 4235 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
5c33a942 4236 if (err < 0)
a44aa400 4237 brcmf_err("BRCMF_C_DOWN error %d\n", err);
5c33a942
HM
4238 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4239 if (err < 0)
4240 brcmf_err("setting AP mode failed %d\n", err);
4241 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4242 if (err < 0)
4243 brcmf_err("setting INFRA mode failed %d\n", err);
a44aa400
HM
4244 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4245 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
98027769
AS
4246 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4247 ifp->vif->is_11d);
4248 if (err < 0)
4249 brcmf_err("restoring REGULATORY setting failed %d\n",
4250 err);
a44aa400
HM
4251 /* Bring device back up so it can be used again */
4252 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4253 if (err < 0)
4254 brcmf_err("BRCMF_C_UP error %d\n", err);
426d0a56
HM
4255 } else {
4256 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
4257 bss_enable.enable = cpu_to_le32(0);
4258 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4259 sizeof(bss_enable));
4260 if (err < 0)
4261 brcmf_err("bss_enable config failed %d\n", err);
1a873342 4262 }
f96aa07e 4263 brcmf_set_mpc(ifp, 1);
b3657453 4264 brcmf_configure_arp_offload(ifp, true);
426d0a56
HM
4265 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4266 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
4267
1a873342
HM
4268 return err;
4269}
4270
a0f07959
HM
4271static s32
4272brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4273 struct cfg80211_beacon_data *info)
4274{
a0f07959
HM
4275 struct brcmf_if *ifp = netdev_priv(ndev);
4276 s32 err;
4277
4278 brcmf_dbg(TRACE, "Enter\n");
4279
a0f07959
HM
4280 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4281
4282 return err;
4283}
4284
1a873342
HM
4285static int
4286brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
89c771e5 4287 struct station_del_parameters *params)
1a873342 4288{
a0f07959 4289 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342 4290 struct brcmf_scb_val_le scbval;
0abb5f21 4291 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
4292 s32 err;
4293
89c771e5 4294 if (!params->mac)
1a873342
HM
4295 return -EFAULT;
4296
89c771e5 4297 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
1a873342 4298
a0f07959
HM
4299 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4300 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ce81e317 4301 if (!check_vif_up(ifp->vif))
1a873342
HM
4302 return -EIO;
4303
89c771e5 4304 memcpy(&scbval.ea, params->mac, ETH_ALEN);
ba8b6ae6 4305 scbval.val = cpu_to_le32(params->reason_code);
0abb5f21 4306 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 4307 &scbval, sizeof(scbval));
1a873342 4308 if (err)
57d6e91a 4309 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
7ab6acd0 4310
d96b801f 4311 brcmf_dbg(TRACE, "Exit\n");
1a873342
HM
4312 return err;
4313}
4314
6b89dcb3
HM
4315static int
4316brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4317 const u8 *mac, struct station_parameters *params)
4318{
4319 struct brcmf_if *ifp = netdev_priv(ndev);
4320 s32 err;
4321
4322 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4323 params->sta_flags_mask, params->sta_flags_set);
4324
4325 /* Ignore all 00 MAC */
4326 if (is_zero_ether_addr(mac))
4327 return 0;
4328
4329 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4330 return 0;
4331
4332 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4333 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4334 (void *)mac, ETH_ALEN);
4335 else
4336 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4337 (void *)mac, ETH_ALEN);
4338 if (err < 0)
4339 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4340
4341 return err;
4342}
0de8aace
HM
4343
4344static void
4345brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4346 struct wireless_dev *wdev,
4347 u16 frame_type, bool reg)
4348{
7fa2e352 4349 struct brcmf_cfg80211_vif *vif;
0de8aace
HM
4350 u16 mgmt_type;
4351
4352 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4353
4354 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
7fa2e352 4355 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
0de8aace
HM
4356 if (reg)
4357 vif->mgmt_rx_reg |= BIT(mgmt_type);
4358 else
318a64ce 4359 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
0de8aace
HM
4360}
4361
4362
4363static int
4364brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
b176e629 4365 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
0de8aace
HM
4366{
4367 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
b176e629
AO
4368 struct ieee80211_channel *chan = params->chan;
4369 const u8 *buf = params->buf;
4370 size_t len = params->len;
0de8aace
HM
4371 const struct ieee80211_mgmt *mgmt;
4372 struct brcmf_cfg80211_vif *vif;
4373 s32 err = 0;
4374 s32 ie_offset;
4375 s32 ie_len;
18e2f61d
HM
4376 struct brcmf_fil_action_frame_le *action_frame;
4377 struct brcmf_fil_af_params_le *af_params;
4378 bool ack;
4379 s32 chan_nr;
c2ff8cad 4380 u32 freq;
0de8aace
HM
4381
4382 brcmf_dbg(TRACE, "Enter\n");
4383
4384 *cookie = 0;
4385
4386 mgmt = (const struct ieee80211_mgmt *)buf;
4387
a0f07959
HM
4388 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4389 brcmf_err("Driver only allows MGMT packet type\n");
4390 return -EPERM;
4391 }
0de8aace 4392
c2ff8cad
AQ
4393 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4394
a0f07959
HM
4395 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4396 /* Right now the only reason to get a probe response */
4397 /* is for p2p listen response or for p2p GO from */
4398 /* wpa_supplicant. Unfortunately the probe is send */
4399 /* on primary ndev, while dongle wants it on the p2p */
4400 /* vif. Since this is only reason for a probe */
4401 /* response to be sent, the vif is taken from cfg. */
4402 /* If ever desired to send proberesp for non p2p */
4403 /* response then data should be checked for */
4404 /* "DIRECT-". Note in future supplicant will take */
4405 /* dedicated p2p wdev to do this and then this 'hack'*/
4406 /* is not needed anymore. */
4407 ie_offset = DOT11_MGMT_HDR_LEN +
4408 DOT11_BCN_PRB_FIXED_LEN;
4409 ie_len = len - ie_offset;
a0f07959 4410 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
0de8aace 4411 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
a0f07959
HM
4412 err = brcmf_vif_set_mgmt_ie(vif,
4413 BRCMF_VNDR_IE_PRBRSP_FLAG,
4414 &buf[ie_offset],
4415 ie_len);
4416 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4417 GFP_KERNEL);
18e2f61d
HM
4418 } else if (ieee80211_is_action(mgmt->frame_control)) {
4419 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4420 if (af_params == NULL) {
4421 brcmf_err("unable to allocate frame\n");
4422 err = -ENOMEM;
4423 goto exit;
4424 }
4425 action_frame = &af_params->action_frame;
4426 /* Add the packet Id */
4427 action_frame->packet_id = cpu_to_le32(*cookie);
4428 /* Add BSSID */
4429 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4430 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4431 /* Add the length exepted for 802.11 header */
4432 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
c2ff8cad
AQ
4433 /* Add the channel. Use the one specified as parameter if any or
4434 * the current one (got from the firmware) otherwise
4435 */
4436 if (chan)
4437 freq = chan->center_freq;
4438 else
4439 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4440 &freq);
4441 chan_nr = ieee80211_frequency_to_channel(freq);
18e2f61d
HM
4442 af_params->channel = cpu_to_le32(chan_nr);
4443
4444 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4445 le16_to_cpu(action_frame->len));
4446
4447 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
86a9c4a2 4448 *cookie, le16_to_cpu(action_frame->len), freq);
18e2f61d 4449
7fa2e352 4450 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
18e2f61d
HM
4451 af_params);
4452
4453 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4454 GFP_KERNEL);
4455 kfree(af_params);
a0f07959
HM
4456 } else {
4457 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4458 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
0de8aace 4459 }
a0f07959 4460
18e2f61d 4461exit:
0de8aace
HM
4462 return err;
4463}
4464
4465
4466static int
4467brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4468 struct wireless_dev *wdev,
4469 u64 cookie)
4470{
4471 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4472 struct brcmf_cfg80211_vif *vif;
4473 int err = 0;
4474
4475 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4476
4477 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4478 if (vif == NULL) {
4479 brcmf_err("No p2p device available for probe response\n");
4480 err = -ENODEV;
4481 goto exit;
4482 }
4483 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4484exit:
4485 return err;
4486}
4487
61730d4d
PH
4488static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4489 struct wireless_dev *wdev,
4490 enum nl80211_crit_proto_id proto,
4491 u16 duration)
4492{
4493 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4494 struct brcmf_cfg80211_vif *vif;
4495
4496 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4497
4498 /* only DHCP support for now */
4499 if (proto != NL80211_CRIT_PROTO_DHCP)
4500 return -EINVAL;
4501
4502 /* suppress and abort scanning */
4503 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4504 brcmf_abort_scanning(cfg);
4505
4506 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4507}
4508
4509static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4510 struct wireless_dev *wdev)
4511{
4512 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4513 struct brcmf_cfg80211_vif *vif;
4514
4515 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4516
4517 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4518 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4519}
4520
70b7d94b
HM
4521static s32
4522brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4523 const struct brcmf_event_msg *e, void *data)
4524{
4525 switch (e->reason) {
4526 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4527 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4528 break;
4529 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4530 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4531 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4532 break;
4533 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4534 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4535 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4536 break;
4537 }
4538
4539 return 0;
4540}
4541
89c2f382
AS
4542static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4543{
4544 int ret;
4545
4546 switch (oper) {
4547 case NL80211_TDLS_DISCOVERY_REQ:
4548 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4549 break;
4550 case NL80211_TDLS_SETUP:
4551 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4552 break;
4553 case NL80211_TDLS_TEARDOWN:
4554 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4555 break;
4556 default:
4557 brcmf_err("unsupported operation: %d\n", oper);
4558 ret = -EOPNOTSUPP;
4559 }
4560 return ret;
4561}
4562
4563static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
3b3a0162 4564 struct net_device *ndev, const u8 *peer,
89c2f382
AS
4565 enum nl80211_tdls_operation oper)
4566{
4567 struct brcmf_if *ifp;
4568 struct brcmf_tdls_iovar_le info;
4569 int ret = 0;
4570
4571 ret = brcmf_convert_nl80211_tdls_oper(oper);
4572 if (ret < 0)
4573 return ret;
4574
4575 ifp = netdev_priv(ndev);
4576 memset(&info, 0, sizeof(info));
4577 info.mode = (u8)ret;
4578 if (peer)
4579 memcpy(info.ea, peer, ETH_ALEN);
4580
4581 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4582 &info, sizeof(info));
4583 if (ret < 0)
4584 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4585
4586 return ret;
4587}
4588
5b435de0 4589static struct cfg80211_ops wl_cfg80211_ops = {
9f440b7b
AS
4590 .add_virtual_intf = brcmf_cfg80211_add_iface,
4591 .del_virtual_intf = brcmf_cfg80211_del_iface,
5b435de0
AS
4592 .change_virtual_intf = brcmf_cfg80211_change_iface,
4593 .scan = brcmf_cfg80211_scan,
4594 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4595 .join_ibss = brcmf_cfg80211_join_ibss,
4596 .leave_ibss = brcmf_cfg80211_leave_ibss,
4597 .get_station = brcmf_cfg80211_get_station,
4598 .set_tx_power = brcmf_cfg80211_set_tx_power,
4599 .get_tx_power = brcmf_cfg80211_get_tx_power,
4600 .add_key = brcmf_cfg80211_add_key,
4601 .del_key = brcmf_cfg80211_del_key,
4602 .get_key = brcmf_cfg80211_get_key,
4603 .set_default_key = brcmf_cfg80211_config_default_key,
4604 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4605 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
5b435de0
AS
4606 .connect = brcmf_cfg80211_connect,
4607 .disconnect = brcmf_cfg80211_disconnect,
4608 .suspend = brcmf_cfg80211_suspend,
4609 .resume = brcmf_cfg80211_resume,
4610 .set_pmksa = brcmf_cfg80211_set_pmksa,
4611 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4612 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4613 .start_ap = brcmf_cfg80211_start_ap,
4614 .stop_ap = brcmf_cfg80211_stop_ap,
a0f07959 4615 .change_beacon = brcmf_cfg80211_change_beacon,
1a873342 4616 .del_station = brcmf_cfg80211_del_station,
6b89dcb3 4617 .change_station = brcmf_cfg80211_change_station,
e5806072
AS
4618 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4619 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
0de8aace
HM
4620 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4621 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4622 .remain_on_channel = brcmf_p2p_remain_on_channel,
4623 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
27f10e38
AS
4624 .start_p2p_device = brcmf_p2p_start_device,
4625 .stop_p2p_device = brcmf_p2p_stop_device,
61730d4d
PH
4626 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4627 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
89c2f382 4628 .tdls_oper = brcmf_cfg80211_tdls_oper,
5b435de0
AS
4629};
4630
3eacf866 4631struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
9f440b7b
AS
4632 enum nl80211_iftype type,
4633 bool pm_block)
3eacf866 4634{
a44aa400 4635 struct brcmf_cfg80211_vif *vif_walk;
3eacf866 4636 struct brcmf_cfg80211_vif *vif;
a44aa400 4637 bool mbss;
5b435de0 4638
33a6b157 4639 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
9f440b7b 4640 sizeof(*vif));
3eacf866
AS
4641 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4642 if (!vif)
4643 return ERR_PTR(-ENOMEM);
4644
4645 vif->wdev.wiphy = cfg->wiphy;
9f440b7b 4646 vif->wdev.iftype = type;
5b435de0 4647
3eacf866
AS
4648 vif->pm_block = pm_block;
4649 vif->roam_off = -1;
4650
6ac4f4ed
AS
4651 brcmf_init_prof(&vif->profile);
4652
a44aa400
HM
4653 if (type == NL80211_IFTYPE_AP) {
4654 mbss = false;
4655 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
4656 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
4657 mbss = true;
4658 break;
4659 }
4660 }
4661 vif->mbss = mbss;
4662 }
4663
3eacf866 4664 list_add_tail(&vif->list, &cfg->vif_list);
3eacf866 4665 return vif;
5b435de0
AS
4666}
4667
427dec5f 4668void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4669{
3eacf866 4670 list_del(&vif->list);
3eacf866 4671 kfree(vif);
5b435de0
AS
4672}
4673
9df4d542
AS
4674void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4675{
4676 struct brcmf_cfg80211_vif *vif;
4677 struct brcmf_if *ifp;
4678
4679 ifp = netdev_priv(ndev);
4680 vif = ifp->vif;
4681
4682 brcmf_free_vif(vif);
4683 free_netdev(ndev);
4684}
4685
903e0eee 4686static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
5b435de0 4687{
5c36b99a
AS
4688 u32 event = e->event_code;
4689 u32 status = e->status;
5b435de0
AS
4690
4691 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
16886735 4692 brcmf_dbg(CONN, "Processing set ssid\n");
5b435de0
AS
4693 return true;
4694 }
4695
4696 return false;
4697}
4698
903e0eee 4699static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
5b435de0 4700{
5c36b99a
AS
4701 u32 event = e->event_code;
4702 u16 flags = e->flags;
5b435de0 4703
68ca395f
HM
4704 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
4705 (event == BRCMF_E_DISASSOC_IND) ||
4706 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
16886735 4707 brcmf_dbg(CONN, "Processing link down\n");
5b435de0
AS
4708 return true;
4709 }
4710 return false;
4711}
4712
27a68fe3 4713static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4714 const struct brcmf_event_msg *e)
4715{
5c36b99a
AS
4716 u32 event = e->event_code;
4717 u32 status = e->status;
5b435de0
AS
4718
4719 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
16886735
AS
4720 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4721 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
4722 return true;
4723 }
4724
4725 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
16886735 4726 brcmf_dbg(CONN, "Processing connecting & no network found\n");
5b435de0
AS
4727 return true;
4728 }
4729
4730 return false;
4731}
4732
27a68fe3 4733static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4734{
27a68fe3 4735 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4736
4737 kfree(conn_info->req_ie);
4738 conn_info->req_ie = NULL;
4739 conn_info->req_ie_len = 0;
4740 kfree(conn_info->resp_ie);
4741 conn_info->resp_ie = NULL;
4742 conn_info->resp_ie_len = 0;
4743}
4744
89286dc9
HM
4745static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4746 struct brcmf_if *ifp)
5b435de0 4747{
c4e382d2 4748 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4749 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4750 u32 req_len;
4751 u32 resp_len;
4752 s32 err = 0;
4753
27a68fe3 4754 brcmf_clear_assoc_ies(cfg);
5b435de0 4755
ac24be6f
AS
4756 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4757 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0 4758 if (err) {
57d6e91a 4759 brcmf_err("could not get assoc info (%d)\n", err);
5b435de0
AS
4760 return err;
4761 }
c4e382d2 4762 assoc_info =
27a68fe3 4763 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4764 req_len = le32_to_cpu(assoc_info->req_len);
4765 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4766 if (req_len) {
ac24be6f 4767 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4768 cfg->extra_buf,
4769 WL_ASSOC_INFO_MAX);
5b435de0 4770 if (err) {
57d6e91a 4771 brcmf_err("could not get assoc req (%d)\n", err);
5b435de0
AS
4772 return err;
4773 }
4774 conn_info->req_ie_len = req_len;
4775 conn_info->req_ie =
27a68fe3 4776 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4777 GFP_KERNEL);
4778 } else {
4779 conn_info->req_ie_len = 0;
4780 conn_info->req_ie = NULL;
4781 }
4782 if (resp_len) {
ac24be6f 4783 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4784 cfg->extra_buf,
4785 WL_ASSOC_INFO_MAX);
5b435de0 4786 if (err) {
57d6e91a 4787 brcmf_err("could not get assoc resp (%d)\n", err);
5b435de0
AS
4788 return err;
4789 }
4790 conn_info->resp_ie_len = resp_len;
4791 conn_info->resp_ie =
27a68fe3 4792 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4793 GFP_KERNEL);
4794 } else {
4795 conn_info->resp_ie_len = 0;
4796 conn_info->resp_ie = NULL;
4797 }
16886735
AS
4798 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4799 conn_info->req_ie_len, conn_info->resp_ie_len);
5b435de0
AS
4800
4801 return err;
4802}
4803
4804static s32
27a68fe3 4805brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4806 struct net_device *ndev,
4807 const struct brcmf_event_msg *e)
4808{
c1179033
AS
4809 struct brcmf_if *ifp = netdev_priv(ndev);
4810 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4811 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4812 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4813 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4814 struct ieee80211_supported_band *band;
a180b83b 4815 struct brcmf_bss_info_le *bi;
83cf17aa 4816 struct brcmu_chan ch;
5b435de0
AS
4817 u32 freq;
4818 s32 err = 0;
a180b83b 4819 u8 *buf;
5b435de0 4820
d96b801f 4821 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4822
89286dc9 4823 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4824 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9 4825 brcmf_update_bss_info(cfg, ifp);
5b435de0 4826
a180b83b
FL
4827 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4828 if (buf == NULL) {
4829 err = -ENOMEM;
4830 goto done;
4831 }
4832
4833 /* data sent to dongle has to be little endian */
4834 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4835 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4836 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4837
4838 if (err)
4839 goto done;
5b435de0 4840
a180b83b 4841 bi = (struct brcmf_bss_info_le *)(buf + 4);
83cf17aa
FL
4842 ch.chspec = le16_to_cpu(bi->chanspec);
4843 cfg->d11inf.decchspec(&ch);
5b435de0 4844
83cf17aa 4845 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
4846 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4847 else
4848 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4849
83cf17aa 4850 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
4851 notify_channel = ieee80211_get_channel(wiphy, freq);
4852
a180b83b
FL
4853done:
4854 kfree(buf);
06bb123e 4855 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4856 conn_info->req_ie, conn_info->req_ie_len,
4857 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16886735 4858 brcmf_dbg(CONN, "Report roaming result\n");
5b435de0 4859
c1179033 4860 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
d96b801f 4861 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4862 return err;
4863}
4864
4865static s32
27a68fe3 4866brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4867 struct net_device *ndev, const struct brcmf_event_msg *e,
4868 bool completed)
4869{
c1179033
AS
4870 struct brcmf_if *ifp = netdev_priv(ndev);
4871 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4872 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0 4873
d96b801f 4874 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4875
c1179033
AS
4876 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4877 &ifp->vif->sme_state)) {
5b435de0 4878 if (completed) {
89286dc9 4879 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4880 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9
HM
4881 brcmf_update_bss_info(cfg, ifp);
4882 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4883 &ifp->vif->sme_state);
5b435de0
AS
4884 }
4885 cfg80211_connect_result(ndev,
06bb123e 4886 (u8 *)profile->bssid,
5b435de0
AS
4887 conn_info->req_ie,
4888 conn_info->req_ie_len,
4889 conn_info->resp_ie,
4890 conn_info->resp_ie_len,
4891 completed ? WLAN_STATUS_SUCCESS :
4892 WLAN_STATUS_AUTH_TIMEOUT,
4893 GFP_KERNEL);
16886735
AS
4894 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4895 completed ? "succeeded" : "failed");
5b435de0 4896 }
d96b801f 4897 brcmf_dbg(TRACE, "Exit\n");
12f32370 4898 return 0;
5b435de0
AS
4899}
4900
4901static s32
27a68fe3 4902brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4903 struct net_device *ndev,
4904 const struct brcmf_event_msg *e, void *data)
4905{
a44aa400 4906 struct brcmf_if *ifp = netdev_priv(ndev);
7ee29602 4907 static int generation;
5c36b99a
AS
4908 u32 event = e->event_code;
4909 u32 reason = e->reason;
1a873342
HM
4910 struct station_info sinfo;
4911
16886735 4912 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
5f4f9f11
AS
4913 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4914 ndev != cfg_to_ndev(cfg)) {
4915 brcmf_dbg(CONN, "AP mode link down\n");
4916 complete(&cfg->vif_disabled);
a44aa400
HM
4917 if (ifp->vif->mbss)
4918 brcmf_remove_interface(ifp->drvr, ifp->bssidx);
5f4f9f11
AS
4919 return 0;
4920 }
1a873342 4921
1a873342 4922 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
7ee29602
HM
4923 (reason == BRCMF_E_STATUS_SUCCESS)) {
4924 memset(&sinfo, 0, sizeof(sinfo));
1a873342 4925 if (!data) {
57d6e91a 4926 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
1a873342
HM
4927 return -EINVAL;
4928 }
4929 sinfo.assoc_req_ies = data;
7ee29602 4930 sinfo.assoc_req_ies_len = e->datalen;
1a873342
HM
4931 generation++;
4932 sinfo.generation = generation;
7ee29602 4933 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
1a873342
HM
4934 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4935 (event == BRCMF_E_DEAUTH_IND) ||
4936 (event == BRCMF_E_DEAUTH)) {
7ee29602 4937 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
1a873342 4938 }
7ee29602 4939 return 0;
1a873342
HM
4940}
4941
5b435de0 4942static s32
1993732e 4943brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
4944 const struct brcmf_event_msg *e, void *data)
4945{
1993732e
AS
4946 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4947 struct net_device *ndev = ifp->ndev;
c1179033 4948 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
fe94f3a4 4949 struct ieee80211_channel *chan;
5b435de0
AS
4950 s32 err = 0;
4951
8851cce0
HM
4952 if ((e->event_code == BRCMF_E_DEAUTH) ||
4953 (e->event_code == BRCMF_E_DEAUTH_IND) ||
4954 (e->event_code == BRCMF_E_DISASSOC_IND) ||
4955 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
4956 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4957 }
4958
967fe2c8 4959 if (brcmf_is_apmode(ifp->vif)) {
27a68fe3 4960 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
903e0eee 4961 } else if (brcmf_is_linkup(e)) {
16886735 4962 brcmf_dbg(CONN, "Linkup\n");
128ce3b6 4963 if (brcmf_is_ibssmode(ifp->vif)) {
fe94f3a4 4964 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
6c8c4f72 4965 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4966 wl_inform_ibss(cfg, ndev, e->addr);
fe94f3a4 4967 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
c1179033
AS
4968 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4969 &ifp->vif->sme_state);
4970 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4971 &ifp->vif->sme_state);
5b435de0 4972 } else
27a68fe3 4973 brcmf_bss_connect_done(cfg, ndev, e, true);
903e0eee 4974 } else if (brcmf_is_linkdown(e)) {
16886735 4975 brcmf_dbg(CONN, "Linkdown\n");
128ce3b6 4976 if (!brcmf_is_ibssmode(ifp->vif)) {
27a68fe3 4977 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0 4978 }
9b7a0ddc 4979 brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e));
6ac4f4ed 4980 brcmf_init_prof(ndev_to_prof(ndev));
5f4f9f11
AS
4981 if (ndev != cfg_to_ndev(cfg))
4982 complete(&cfg->vif_disabled);
27a68fe3 4983 } else if (brcmf_is_nonetwork(cfg, e)) {
128ce3b6 4984 if (brcmf_is_ibssmode(ifp->vif))
c1179033
AS
4985 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4986 &ifp->vif->sme_state);
5b435de0 4987 else
27a68fe3 4988 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4989 }
4990
4991 return err;
4992}
4993
4994static s32
1993732e 4995brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
4996 const struct brcmf_event_msg *e, void *data)
4997{
1993732e 4998 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5c36b99a
AS
4999 u32 event = e->event_code;
5000 u32 status = e->status;
5b435de0
AS
5001
5002 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 5003 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 5004 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 5005 else
1993732e 5006 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
5007 }
5008
12f32370 5009 return 0;
5b435de0
AS
5010}
5011
5012static s32
1993732e 5013brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
5014 const struct brcmf_event_msg *e, void *data)
5015{
5c36b99a 5016 u16 flags = e->flags;
5b435de0
AS
5017 enum nl80211_key_type key_type;
5018
5019 if (flags & BRCMF_EVENT_MSG_GROUP)
5020 key_type = NL80211_KEYTYPE_GROUP;
5021 else
5022 key_type = NL80211_KEYTYPE_PAIRWISE;
5023
1993732e 5024 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
5025 NULL, GFP_KERNEL);
5026
5027 return 0;
5028}
5029
d3c0b633
AS
5030static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5031 const struct brcmf_event_msg *e, void *data)
5032{
5033 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5034 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5035 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5036 struct brcmf_cfg80211_vif *vif;
5037
5038 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
5039 ifevent->action, ifevent->flags, ifevent->ifidx,
5040 ifevent->bssidx);
5041
d3c0b633
AS
5042 mutex_lock(&event->vif_event_lock);
5043 event->action = ifevent->action;
5044 vif = event->vif;
5045
5046 switch (ifevent->action) {
5047 case BRCMF_E_IF_ADD:
5048 /* waiting process may have timed out */
dc4a787c
WY
5049 if (!cfg->vif_event.vif) {
5050 mutex_unlock(&event->vif_event_lock);
d3c0b633 5051 return -EBADF;
dc4a787c 5052 }
d3c0b633
AS
5053
5054 ifp->vif = vif;
5055 vif->ifp = ifp;
01b8e7db
AS
5056 if (ifp->ndev) {
5057 vif->wdev.netdev = ifp->ndev;
5058 ifp->ndev->ieee80211_ptr = &vif->wdev;
5059 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5060 }
d3c0b633
AS
5061 mutex_unlock(&event->vif_event_lock);
5062 wake_up(&event->vif_wq);
4b3a89de 5063 return 0;
d3c0b633
AS
5064
5065 case BRCMF_E_IF_DEL:
d3c0b633
AS
5066 mutex_unlock(&event->vif_event_lock);
5067 /* event may not be upon user request */
5068 if (brcmf_cfg80211_vif_event_armed(cfg))
5069 wake_up(&event->vif_wq);
5070 return 0;
5071
7a5c1f64
HM
5072 case BRCMF_E_IF_CHANGE:
5073 mutex_unlock(&event->vif_event_lock);
5074 wake_up(&event->vif_wq);
5075 return 0;
5076
d3c0b633
AS
5077 default:
5078 mutex_unlock(&event->vif_event_lock);
5079 break;
5080 }
5081 return -EINVAL;
5082}
5083
5b435de0
AS
5084static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5085{
5b435de0
AS
5086 conf->frag_threshold = (u32)-1;
5087 conf->rts_threshold = (u32)-1;
5088 conf->retry_short = (u32)-1;
5089 conf->retry_long = (u32)-1;
5090 conf->tx_power = -1;
5091}
5092
5c36b99a 5093static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 5094{
5c36b99a
AS
5095 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5096 brcmf_notify_connect_status);
5097 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5098 brcmf_notify_connect_status);
5099 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5100 brcmf_notify_connect_status);
5101 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5102 brcmf_notify_connect_status);
5103 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5104 brcmf_notify_connect_status);
5105 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5106 brcmf_notify_connect_status);
5107 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5108 brcmf_notify_roaming_status);
5109 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5110 brcmf_notify_mic_status);
5111 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5112 brcmf_notify_connect_status);
5113 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5114 brcmf_notify_sched_scan_results);
d3c0b633
AS
5115 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5116 brcmf_notify_vif_event);
0de8aace 5117 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
6eda4e2c 5118 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
0de8aace
HM
5119 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5120 brcmf_p2p_notify_listen_complete);
e6da3400
HM
5121 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5122 brcmf_p2p_notify_action_frame_rx);
18e2f61d
HM
5123 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5124 brcmf_p2p_notify_action_tx_complete);
6eda4e2c
HM
5125 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5126 brcmf_p2p_notify_action_tx_complete);
5b435de0
AS
5127}
5128
27a68fe3
AS
5129static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
5130{
27a68fe3
AS
5131 kfree(cfg->conf);
5132 cfg->conf = NULL;
27a68fe3
AS
5133 kfree(cfg->escan_ioctl_buf);
5134 cfg->escan_ioctl_buf = NULL;
27a68fe3
AS
5135 kfree(cfg->extra_buf);
5136 cfg->extra_buf = NULL;
27a68fe3
AS
5137 kfree(cfg->pmk_list);
5138 cfg->pmk_list = NULL;
27a68fe3
AS
5139}
5140
5141static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
5142{
27a68fe3
AS
5143 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5144 if (!cfg->conf)
5b435de0 5145 goto init_priv_mem_out;
27a68fe3
AS
5146 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5147 if (!cfg->escan_ioctl_buf)
e756af5b 5148 goto init_priv_mem_out;
27a68fe3
AS
5149 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5150 if (!cfg->extra_buf)
5b435de0 5151 goto init_priv_mem_out;
27a68fe3
AS
5152 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
5153 if (!cfg->pmk_list)
5b435de0
AS
5154 goto init_priv_mem_out;
5155
5156 return 0;
5157
5158init_priv_mem_out:
27a68fe3 5159 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
5160
5161 return -ENOMEM;
5162}
5163
27a68fe3 5164static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5165{
5166 s32 err = 0;
5167
27a68fe3
AS
5168 cfg->scan_request = NULL;
5169 cfg->pwr_save = true;
68ca395f
HM
5170 cfg->active_scan = true; /* we do active scan per default */
5171 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 5172 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
5173 if (err)
5174 return err;
5c36b99a 5175 brcmf_register_event_handlers(cfg);
27a68fe3 5176 mutex_init(&cfg->usr_sync);
27a68fe3
AS
5177 brcmf_init_escan(cfg);
5178 brcmf_init_conf(cfg->conf);
5f4f9f11 5179 init_completion(&cfg->vif_disabled);
5b435de0
AS
5180 return err;
5181}
5182
27a68fe3 5183static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 5184{
27a68fe3 5185 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
5186 brcmf_abort_scanning(cfg);
5187 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
5188}
5189
d3c0b633
AS
5190static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5191{
5192 init_waitqueue_head(&event->vif_wq);
d3c0b633
AS
5193 mutex_init(&event->vif_event_lock);
5194}
5195
5b435de0 5196static s32
68ca395f 5197brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
5b435de0 5198{
5b435de0 5199 s32 err = 0;
f588bc0c
AS
5200 __le32 roamtrigger[2];
5201 __le32 roam_delta[2];
5b435de0
AS
5202
5203 /*
5204 * Setup timeout if Beacons are lost and roam is
5205 * off to report link down
5206 */
68ca395f 5207 if (brcmf_roamoff) {
ac24be6f 5208 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0 5209 if (err) {
57d6e91a 5210 brcmf_err("bcn_timeout error (%d)\n", err);
5b435de0
AS
5211 goto dongle_rom_out;
5212 }
5213 }
5214
5215 /*
5216 * Enable/Disable built-in roaming to allow supplicant
5217 * to take care of roaming
5218 */
68ca395f
HM
5219 brcmf_dbg(INFO, "Internal Roaming = %s\n",
5220 brcmf_roamoff ? "Off" : "On");
5221 err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
5b435de0 5222 if (err) {
57d6e91a 5223 brcmf_err("roam_off error (%d)\n", err);
5b435de0
AS
5224 goto dongle_rom_out;
5225 }
5226
f588bc0c
AS
5227 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5228 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5229 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 5230 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0 5231 if (err) {
57d6e91a 5232 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5b435de0
AS
5233 goto dongle_rom_out;
5234 }
5235
f588bc0c
AS
5236 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5237 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5238 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 5239 (void *)roam_delta, sizeof(roam_delta));
5b435de0 5240 if (err) {
57d6e91a 5241 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
5b435de0
AS
5242 goto dongle_rom_out;
5243 }
5244
5245dongle_rom_out:
5246 return err;
5247}
5248
5249static s32
40a23296 5250brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
c68cdc0f 5251 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0
AS
5252{
5253 s32 err = 0;
5254
ac24be6f 5255 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 5256 scan_assoc_time);
5b435de0
AS
5257 if (err) {
5258 if (err == -EOPNOTSUPP)
647c9ae0 5259 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
5b435de0 5260 else
57d6e91a 5261 brcmf_err("Scan assoc time error (%d)\n", err);
5b435de0
AS
5262 goto dongle_scantime_out;
5263 }
ac24be6f 5264 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 5265 scan_unassoc_time);
5b435de0
AS
5266 if (err) {
5267 if (err == -EOPNOTSUPP)
647c9ae0 5268 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
5b435de0 5269 else
57d6e91a 5270 brcmf_err("Scan unassoc time error (%d)\n", err);
5b435de0
AS
5271 goto dongle_scantime_out;
5272 }
5273
ac24be6f 5274 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 5275 scan_passive_time);
5b435de0
AS
5276 if (err) {
5277 if (err == -EOPNOTSUPP)
647c9ae0 5278 brcmf_dbg(INFO, "Scan passive time is not supported\n");
5b435de0 5279 else
57d6e91a 5280 brcmf_err("Scan passive time error (%d)\n", err);
5b435de0
AS
5281 goto dongle_scantime_out;
5282 }
5283
5284dongle_scantime_out:
5285 return err;
5286}
5287
b48d8916
AS
5288static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5289 struct brcmu_chan *ch)
5290{
5291 u32 ht40_flag;
d48200ba 5292
b48d8916
AS
5293 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5294 if (ch->sb == BRCMU_CHAN_SB_U) {
5295 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5296 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5297 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5298 } else {
5299 /* It should be one of
5300 * IEEE80211_CHAN_NO_HT40 or
5301 * IEEE80211_CHAN_NO_HT40PLUS
5302 */
5303 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5304 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5305 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5306 }
5307}
5308
5309static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5310 u32 bw_cap[])
d48200ba
HM
5311{
5312 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
b48d8916
AS
5313 struct ieee80211_supported_band *band;
5314 struct ieee80211_channel *channel;
5315 struct wiphy *wiphy;
d48200ba 5316 struct brcmf_chanspec_list *list;
83cf17aa 5317 struct brcmu_chan ch;
b48d8916 5318 int err;
d48200ba
HM
5319 u8 *pbuf;
5320 u32 i, j;
5321 u32 total;
b48d8916 5322 u32 chaninfo;
d48200ba 5323 u32 index;
d48200ba
HM
5324
5325 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5326
5327 if (pbuf == NULL)
5328 return -ENOMEM;
5329
5330 list = (struct brcmf_chanspec_list *)pbuf;
5331
5332 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5333 BRCMF_DCMD_MEDLEN);
5334 if (err) {
5335 brcmf_err("get chanspecs error (%d)\n", err);
b48d8916 5336 goto fail_pbuf;
d48200ba
HM
5337 }
5338
b48d8916 5339 wiphy = cfg_to_wiphy(cfg);
58de92d2
AS
5340 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5341 if (band)
5342 for (i = 0; i < band->n_channels; i++)
5343 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5344 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5345 if (band)
5346 for (i = 0; i < band->n_channels; i++)
5347 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
d48200ba
HM
5348
5349 total = le32_to_cpu(list->count);
5350 for (i = 0; i < total; i++) {
83cf17aa
FL
5351 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5352 cfg->d11inf.decchspec(&ch);
d48200ba 5353
83cf17aa 5354 if (ch.band == BRCMU_CHAN_BAND_2G) {
b48d8916 5355 band = wiphy->bands[IEEE80211_BAND_2GHZ];
83cf17aa 5356 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
b48d8916 5357 band = wiphy->bands[IEEE80211_BAND_5GHZ];
d48200ba 5358 } else {
2375d970 5359 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
d48200ba
HM
5360 continue;
5361 }
58de92d2
AS
5362 if (!band)
5363 continue;
b48d8916 5364 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
2375d970 5365 ch.bw == BRCMU_CHAN_BW_40)
d48200ba 5366 continue;
b48d8916 5367 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
ee942ecc
AS
5368 ch.bw == BRCMU_CHAN_BW_80)
5369 continue;
b48d8916
AS
5370
5371 channel = band->channels;
5372 index = band->n_channels;
5373 for (j = 0; j < band->n_channels; j++) {
5374 if (channel[j].hw_value == ch.chnum) {
5375 index = j;
d48200ba
HM
5376 break;
5377 }
5378 }
b48d8916
AS
5379 channel[index].center_freq =
5380 ieee80211_channel_to_frequency(ch.chnum, band->band);
5381 channel[index].hw_value = ch.chnum;
5382
5383 /* assuming the chanspecs order is HT20,
5384 * HT40 upper, HT40 lower, and VHT80.
5385 */
5386 if (ch.bw == BRCMU_CHAN_BW_80) {
5387 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5388 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5389 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5390 } else {
58de92d2
AS
5391 /* enable the channel and disable other bandwidths
5392 * for now as mentioned order assure they are enabled
5393 * for subsequent chanspecs.
ee942ecc 5394 */
b48d8916
AS
5395 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5396 IEEE80211_CHAN_NO_80MHZ;
5397 ch.bw = BRCMU_CHAN_BW_20;
5398 cfg->d11inf.encchspec(&ch);
5399 chaninfo = ch.chspec;
5400 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5401 &chaninfo);
5402 if (!err) {
5403 if (chaninfo & WL_CHAN_RADAR)
5404 channel[index].flags |=
5405 (IEEE80211_CHAN_RADAR |
5406 IEEE80211_CHAN_NO_IR);
5407 if (chaninfo & WL_CHAN_PASSIVE)
5408 channel[index].flags |=
5409 IEEE80211_CHAN_NO_IR;
d48200ba 5410 }
d48200ba
HM
5411 }
5412 }
b48d8916 5413
b48d8916 5414fail_pbuf:
d48200ba
HM
5415 kfree(pbuf);
5416 return err;
5417}
5418
b48d8916 5419static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
aa70b4fa 5420{
b48d8916
AS
5421 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5422 struct ieee80211_supported_band *band;
aa70b4fa 5423 struct brcmf_fil_bwcap_le band_bwcap;
b48d8916
AS
5424 struct brcmf_chanspec_list *list;
5425 u8 *pbuf;
aa70b4fa
AS
5426 u32 val;
5427 int err;
b48d8916
AS
5428 struct brcmu_chan ch;
5429 u32 num_chan;
5430 int i, j;
aa70b4fa
AS
5431
5432 /* verify support for bw_cap command */
5433 val = WLC_BAND_5G;
5434 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5435
5436 if (!err) {
5437 /* only set 2G bandwidth using bw_cap command */
5438 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5439 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5440 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5441 sizeof(band_bwcap));
5442 } else {
5443 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5444 val = WLC_N_BW_40ALL;
5445 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5446 }
b48d8916
AS
5447
5448 if (!err) {
5449 /* update channel info in 2G band */
5450 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5451
5452 if (pbuf == NULL)
5453 return -ENOMEM;
5454
5455 ch.band = BRCMU_CHAN_BAND_2G;
5456 ch.bw = BRCMU_CHAN_BW_40;
fac7d2a3 5457 ch.sb = BRCMU_CHAN_SB_NONE;
b48d8916
AS
5458 ch.chnum = 0;
5459 cfg->d11inf.encchspec(&ch);
5460
5461 /* pass encoded chanspec in query */
5462 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5463
5464 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5465 BRCMF_DCMD_MEDLEN);
5466 if (err) {
5467 brcmf_err("get chanspecs error (%d)\n", err);
5468 kfree(pbuf);
5469 return err;
5470 }
5471
5472 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5473 list = (struct brcmf_chanspec_list *)pbuf;
5474 num_chan = le32_to_cpu(list->count);
5475 for (i = 0; i < num_chan; i++) {
5476 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5477 cfg->d11inf.decchspec(&ch);
5478 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5479 continue;
5480 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5481 continue;
5482 for (j = 0; j < band->n_channels; j++) {
5483 if (band->channels[j].hw_value == ch.chnum)
5484 break;
5485 }
5486 if (WARN_ON(j == band->n_channels))
5487 continue;
5488
5489 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5490 }
fac7d2a3 5491 kfree(pbuf);
b48d8916 5492 }
aa70b4fa
AS
5493 return err;
5494}
5495
2375d970
AS
5496static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5497{
5498 u32 band, mimo_bwcap;
5499 int err;
5500
5501 band = WLC_BAND_2G;
5502 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5503 if (!err) {
5504 bw_cap[IEEE80211_BAND_2GHZ] = band;
5505 band = WLC_BAND_5G;
5506 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5507 if (!err) {
5508 bw_cap[IEEE80211_BAND_5GHZ] = band;
5509 return;
5510 }
5511 WARN_ON(1);
5512 return;
5513 }
5514 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5515 mimo_bwcap = 0;
5516 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5517 if (err)
5518 /* assume 20MHz if firmware does not give a clue */
5519 mimo_bwcap = WLC_N_BW_20ALL;
5520
5521 switch (mimo_bwcap) {
5522 case WLC_N_BW_40ALL:
5523 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5524 /* fall-thru */
5525 case WLC_N_BW_20IN2G_40IN5G:
5526 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5527 /* fall-thru */
5528 case WLC_N_BW_20ALL:
5529 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5530 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5531 break;
5532 default:
5533 brcmf_err("invalid mimo_bw_cap value\n");
5534 }
5535}
d48200ba 5536
18d6c535
AS
5537static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5538 u32 bw_cap[2], u32 nchain)
5539{
5540 band->ht_cap.ht_supported = true;
5541 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5542 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5543 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5544 }
5545 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5546 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5547 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5548 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5549 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5550 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5551}
5552
5553static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5554{
5555 u16 mcs_map;
5556 int i;
5557
5558 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5559 mcs_map = (mcs_map << 2) | supp;
5560
5561 return cpu_to_le16(mcs_map);
5562}
5563
5564static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
5565 u32 bw_cap[2], u32 nchain)
5566{
5567 __le16 mcs_map;
5568
5569 /* not allowed in 2.4G band */
5570 if (band->band == IEEE80211_BAND_2GHZ)
5571 return;
5572
5573 band->vht_cap.vht_supported = true;
5574 /* 80MHz is mandatory */
5575 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5576 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5577 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5578 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5579 }
5580 /* all support 256-QAM */
5581 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5582 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5583 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
5584}
5585
b48d8916 5586static int brcmf_setup_wiphybands(struct wiphy *wiphy)
5b435de0 5587{
b48d8916 5588 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
ac24be6f 5589 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
18d6c535
AS
5590 u32 nmode = 0;
5591 u32 vhtmode = 0;
b48d8916 5592 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
4aca7a18
DK
5593 u32 rxchain;
5594 u32 nchain;
b48d8916 5595 int err;
d48200ba 5596 s32 i;
2375d970 5597 struct ieee80211_supported_band *band;
5b435de0 5598
18d6c535 5599 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
d48200ba
HM
5600 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5601 if (err) {
5602 brcmf_err("nmode error (%d)\n", err);
5603 } else {
2375d970 5604 brcmf_get_bwcap(ifp, bw_cap);
d48200ba 5605 }
18d6c535
AS
5606 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5607 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5608 bw_cap[IEEE80211_BAND_5GHZ]);
d48200ba 5609
4aca7a18
DK
5610 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5611 if (err) {
5612 brcmf_err("rxchain error (%d)\n", err);
5613 nchain = 1;
5614 } else {
5615 for (nchain = 0; rxchain; nchain++)
5616 rxchain = rxchain & (rxchain - 1);
5617 }
5618 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5619
b48d8916 5620 err = brcmf_construct_chaninfo(cfg, bw_cap);
d48200ba 5621 if (err) {
b48d8916 5622 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
d48200ba
HM
5623 return err;
5624 }
5625
b48d8916
AS
5626 wiphy = cfg_to_wiphy(cfg);
5627 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5628 band = wiphy->bands[i];
5629 if (band == NULL)
2375d970 5630 continue;
d48200ba 5631
18d6c535
AS
5632 if (nmode)
5633 brcmf_update_ht_cap(band, bw_cap, nchain);
5634 if (vhtmode)
5635 brcmf_update_vht_cap(band, bw_cap, nchain);
d48200ba
HM
5636 }
5637
b48d8916 5638 return 0;
5b435de0
AS
5639}
5640
aa70b4fa
AS
5641static const struct ieee80211_txrx_stypes
5642brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5643 [NL80211_IFTYPE_STATION] = {
5644 .tx = 0xffff,
5645 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5646 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5647 },
5648 [NL80211_IFTYPE_P2P_CLIENT] = {
5649 .tx = 0xffff,
5650 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5651 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5652 },
5653 [NL80211_IFTYPE_P2P_GO] = {
5654 .tx = 0xffff,
5655 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
5656 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
5657 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
5658 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
5659 BIT(IEEE80211_STYPE_AUTH >> 4) |
5660 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
5661 BIT(IEEE80211_STYPE_ACTION >> 4)
5662 },
5663 [NL80211_IFTYPE_P2P_DEVICE] = {
5664 .tx = 0xffff,
5665 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5666 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5667 }
5668};
5669
2e5f66fe
PF
5670static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
5671{
5672 struct ieee80211_iface_combination *combo = NULL;
5673 struct ieee80211_iface_limit *limits = NULL;
5674 int i = 0, max_iface_cnt;
5675
5676 combo = kzalloc(sizeof(*combo), GFP_KERNEL);
5677 if (!combo)
5678 goto err;
5679
5680 limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
5681 if (!limits)
5682 goto err;
5683
5684 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
5685 BIT(NL80211_IFTYPE_ADHOC) |
5686 BIT(NL80211_IFTYPE_AP);
5687
5688 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
5689 combo->num_different_channels = 2;
5690 else
5691 combo->num_different_channels = 1;
5692
5693 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
5694 limits[i].max = 1;
5695 limits[i++].types = BIT(NL80211_IFTYPE_STATION);
5696 limits[i].max = 4;
5697 limits[i++].types = BIT(NL80211_IFTYPE_AP);
5698 max_iface_cnt = 5;
5699 } else {
5700 limits[i].max = 2;
5701 limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
5702 BIT(NL80211_IFTYPE_AP);
5703 max_iface_cnt = 2;
5704 }
5705
5706 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
5707 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
5708 BIT(NL80211_IFTYPE_P2P_GO) |
5709 BIT(NL80211_IFTYPE_P2P_DEVICE);
5710 limits[i].max = 1;
5711 limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
5712 BIT(NL80211_IFTYPE_P2P_GO);
5713 limits[i].max = 1;
5714 limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
5715 max_iface_cnt += 2;
5716 }
5717 combo->max_interfaces = max_iface_cnt;
5718 combo->limits = limits;
5719 combo->n_limits = i;
5720
5721 wiphy->iface_combinations = combo;
5722 wiphy->n_iface_combinations = 1;
5723 return 0;
5724
5725err:
5726 kfree(limits);
5727 kfree(combo);
5728 return -ENOMEM;
5729}
5730
aa70b4fa
AS
5731static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
5732{
5733 /* scheduled scan settings */
5734 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
5735 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
5736 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5737 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
5738}
5739
4eb3af7c
HM
5740#ifdef CONFIG_PM
5741static const struct wiphy_wowlan_support brcmf_wowlan_support = {
5742 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
b9a82f89
HM
5743 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
5744 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
5745 .pattern_min_len = 1,
5746 .max_pkt_offset = 1500,
4eb3af7c
HM
5747};
5748#endif
5749
5750static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
5751{
5752#ifdef CONFIG_PM
5753 /* wowl settings */
5754 wiphy->wowlan = &brcmf_wowlan_support;
5755#endif
5756}
5757
b48d8916 5758static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
aa70b4fa 5759{
58de92d2 5760 struct ieee80211_supported_band *band;
58de92d2
AS
5761 __le32 bandlist[3];
5762 u32 n_bands;
5763 int err, i;
5764
aa70b4fa
AS
5765 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
5766 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5767 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
2e5f66fe
PF
5768
5769 err = brcmf_setup_ifmodes(wiphy, ifp);
5770 if (err)
5771 return err;
5772
aa70b4fa
AS
5773 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
5774 wiphy->cipher_suites = __wl_cipher_suites;
5775 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
5776 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
5777 WIPHY_FLAG_OFFCHAN_TX |
5778 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
5779 WIPHY_FLAG_SUPPORTS_TDLS;
5780 if (!brcmf_roamoff)
5781 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
5782 wiphy->mgmt_stypes = brcmf_txrx_stypes;
5783 wiphy->max_remain_on_channel_duration = 5000;
7a7a87dc
AS
5784 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
5785 brcmf_wiphy_pno_params(wiphy);
aa70b4fa
AS
5786
5787 /* vendor commands/events support */
5788 wiphy->vendor_commands = brcmf_vendor_cmds;
5789 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
5790
4eb3af7c
HM
5791 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
5792 brcmf_wiphy_wowl_params(wiphy);
5793
58de92d2
AS
5794 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
5795 sizeof(bandlist));
5796 if (err) {
5797 brcmf_err("could not obtain band info: err=%d\n", err);
5798 return err;
5799 }
5800 /* first entry in bandlist is number of bands */
5801 n_bands = le32_to_cpu(bandlist[0]);
5802 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
5803 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
5804 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
5805 GFP_KERNEL);
5806 if (!band)
5807 return -ENOMEM;
5808
5809 band->channels = kmemdup(&__wl_2ghz_channels,
5810 sizeof(__wl_2ghz_channels),
5811 GFP_KERNEL);
5812 if (!band->channels) {
5813 kfree(band);
5814 return -ENOMEM;
5815 }
5816
5817 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
5818 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
5819 }
5820 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
5821 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
5822 GFP_KERNEL);
5823 if (!band)
5824 return -ENOMEM;
5825
5826 band->channels = kmemdup(&__wl_5ghz_channels,
5827 sizeof(__wl_5ghz_channels),
5828 GFP_KERNEL);
5829 if (!band->channels) {
5830 kfree(band);
5831 return -ENOMEM;
5832 }
5833
5834 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
5835 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
5836 }
5837 }
5838 err = brcmf_setup_wiphybands(wiphy);
5839 return err;
5b435de0
AS
5840}
5841
27a68fe3 5842static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5843{
5844 struct net_device *ndev;
5845 struct wireless_dev *wdev;
40a23296 5846 struct brcmf_if *ifp;
5b435de0
AS
5847 s32 power_mode;
5848 s32 err = 0;
5849
27a68fe3 5850 if (cfg->dongle_up)
5b435de0
AS
5851 return err;
5852
27a68fe3 5853 ndev = cfg_to_ndev(cfg);
5b435de0 5854 wdev = ndev->ieee80211_ptr;
40a23296
HM
5855 ifp = netdev_priv(ndev);
5856
5857 /* make sure RF is ready for work */
5858 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5b435de0 5859
40a23296
HM
5860 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5861 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5b435de0 5862
27a68fe3 5863 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
40a23296 5864 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5b435de0
AS
5865 if (err)
5866 goto default_conf_out;
647c9ae0
AS
5867 brcmf_dbg(INFO, "power save set to %s\n",
5868 (power_mode ? "enabled" : "disabled"));
5b435de0 5869
68ca395f 5870 err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
5b435de0
AS
5871 if (err)
5872 goto default_conf_out;
5dd161ff
FL
5873 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5874 NULL, NULL);
40a23296 5875 if (err)
5b435de0 5876 goto default_conf_out;
5b435de0 5877
b3657453
HM
5878 brcmf_configure_arp_offload(ifp, true);
5879
27a68fe3 5880 cfg->dongle_up = true;
40a23296 5881default_conf_out:
5b435de0
AS
5882
5883 return err;
5884
5885}
5886
bdf5ff51 5887static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5b435de0 5888{
c1179033 5889 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5890
bdf5ff51 5891 return brcmf_config_dongle(ifp->drvr->config);
5b435de0
AS
5892}
5893
bdf5ff51 5894static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5b435de0 5895{
bdf5ff51 5896 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
c1179033 5897
5b435de0
AS
5898 /*
5899 * While going down, if associated with AP disassociate
5900 * from AP to save power
5901 */
903e0eee 5902 if (check_vif_up(ifp->vif)) {
9b7a0ddc 5903 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
5b435de0
AS
5904
5905 /* Make sure WPA_Supplicant receives all the event
5906 generated due to DISASSOC call to the fw to keep
5907 the state fw and WPA_Supplicant state consistent
5908 */
5909 brcmf_delay(500);
5910 }
5911
27a68fe3 5912 brcmf_abort_scanning(cfg);
c1179033 5913 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5914
5b435de0
AS
5915 return 0;
5916}
5917
bdf5ff51 5918s32 brcmf_cfg80211_up(struct net_device *ndev)
5b435de0 5919{
bdf5ff51
AS
5920 struct brcmf_if *ifp = netdev_priv(ndev);
5921 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5922 s32 err = 0;
5923
27a68fe3 5924 mutex_lock(&cfg->usr_sync);
bdf5ff51 5925 err = __brcmf_cfg80211_up(ifp);
27a68fe3 5926 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5927
5928 return err;
5929}
5930
bdf5ff51 5931s32 brcmf_cfg80211_down(struct net_device *ndev)
5b435de0 5932{
bdf5ff51
AS
5933 struct brcmf_if *ifp = netdev_priv(ndev);
5934 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5935 s32 err = 0;
5936
27a68fe3 5937 mutex_lock(&cfg->usr_sync);
bdf5ff51 5938 err = __brcmf_cfg80211_down(ifp);
27a68fe3 5939 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5940
5941 return err;
5942}
5943
a7965fbb
AS
5944enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5945{
5946 struct wireless_dev *wdev = &ifp->vif->wdev;
5947
5948 return wdev->iftype;
5949}
5950
bfe81975
HM
5951bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
5952 unsigned long state)
9f440b7b
AS
5953{
5954 struct brcmf_cfg80211_vif *vif;
9f440b7b
AS
5955
5956 list_for_each_entry(vif, &cfg->vif_list, list) {
5957 if (test_bit(state, &vif->sme_state))
e843bb19 5958 return true;
9f440b7b 5959 }
e843bb19 5960 return false;
9f440b7b 5961}
d3c0b633
AS
5962
5963static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5964 u8 action)
5965{
5966 u8 evt_action;
5967
5968 mutex_lock(&event->vif_event_lock);
5969 evt_action = event->action;
5970 mutex_unlock(&event->vif_event_lock);
5971 return evt_action == action;
5972}
5973
5974void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5975 struct brcmf_cfg80211_vif *vif)
5976{
5977 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5978
5979 mutex_lock(&event->vif_event_lock);
5980 event->vif = vif;
5981 event->action = 0;
5982 mutex_unlock(&event->vif_event_lock);
5983}
5984
5985bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5986{
5987 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5988 bool armed;
5989
5990 mutex_lock(&event->vif_event_lock);
5991 armed = event->vif != NULL;
5992 mutex_unlock(&event->vif_event_lock);
5993
5994 return armed;
5995}
5996int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5997 u8 action, ulong timeout)
5998{
5999 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6000
6001 return wait_event_timeout(event->vif_wq,
6002 vif_event_equals(event, action), timeout);
6003}
6004
63db1a49
AS
6005static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6006 struct regulatory_request *req)
6007{
6008 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6009 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6010 struct brcmf_fil_country_le ccreq;
6011 int i;
6012
6013 brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
6014 req->alpha2[0], req->alpha2[1]);
6015
6016 /* ignore non-ISO3166 country codes */
6017 for (i = 0; i < sizeof(req->alpha2); i++)
6018 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
6019 brcmf_err("not a ISO3166 code\n");
6020 return;
6021 }
6022 memset(&ccreq, 0, sizeof(ccreq));
6023 ccreq.rev = cpu_to_le32(-1);
6024 memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
8afe0ece
AS
6025 if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
6026 brcmf_err("firmware rejected country setting\n");
6027 return;
6028 }
6029 brcmf_setup_wiphybands(wiphy);
63db1a49
AS
6030}
6031
b48d8916
AS
6032static void brcmf_free_wiphy(struct wiphy *wiphy)
6033{
58de92d2
AS
6034 if (!wiphy)
6035 return;
6036
2e5f66fe
PF
6037 if (wiphy->iface_combinations)
6038 kfree(wiphy->iface_combinations->limits);
b48d8916
AS
6039 kfree(wiphy->iface_combinations);
6040 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6041 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6042 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6043 }
6044 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6045 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6046 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6047 }
6048 wiphy_free(wiphy);
6049}
6050
ccfd1e81
AS
6051struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
6052 struct device *busdev)
6053{
6054 struct net_device *ndev = drvr->iflist[0]->ndev;
6055 struct brcmf_cfg80211_info *cfg;
6056 struct wiphy *wiphy;
6057 struct brcmf_cfg80211_vif *vif;
6058 struct brcmf_if *ifp;
6059 s32 err = 0;
6060 s32 io_type;
b48d8916 6061 u16 *cap = NULL;
ccfd1e81
AS
6062
6063 if (!ndev) {
6064 brcmf_err("ndev is invalid\n");
6065 return NULL;
6066 }
6067
6068 ifp = netdev_priv(ndev);
b48d8916
AS
6069 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
6070 if (!wiphy) {
6071 brcmf_err("Could not allocate wiphy device\n");
ccfd1e81 6072 return NULL;
b48d8916 6073 }
6896f4fb 6074 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
b48d8916 6075 set_wiphy_dev(wiphy, busdev);
ccfd1e81
AS
6076
6077 cfg = wiphy_priv(wiphy);
6078 cfg->wiphy = wiphy;
6079 cfg->pub = drvr;
6080 init_vif_event(&cfg->vif_event);
6081 INIT_LIST_HEAD(&cfg->vif_list);
6082
6083 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
b48d8916
AS
6084 if (IS_ERR(vif))
6085 goto wiphy_out;
ccfd1e81
AS
6086
6087 vif->ifp = ifp;
6088 vif->wdev.netdev = ndev;
6089 ndev->ieee80211_ptr = &vif->wdev;
6090 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6091
6092 err = wl_init_priv(cfg);
6093 if (err) {
6094 brcmf_err("Failed to init iwm_priv (%d)\n", err);
b48d8916
AS
6095 brcmf_free_vif(vif);
6096 goto wiphy_out;
ccfd1e81
AS
6097 }
6098 ifp->vif = vif;
6099
b48d8916
AS
6100 /* determine d11 io type before wiphy setup */
6101 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
ccfd1e81 6102 if (err) {
b48d8916
AS
6103 brcmf_err("Failed to get D11 version (%d)\n", err);
6104 goto priv_out;
ccfd1e81 6105 }
b48d8916
AS
6106 cfg->d11inf.io_type = (u8)io_type;
6107 brcmu_d11_attach(&cfg->d11inf);
6108
6109 err = brcmf_setup_wiphy(wiphy, ifp);
6110 if (err < 0)
6111 goto priv_out;
6112
6113 brcmf_dbg(INFO, "Registering custom regulatory\n");
63db1a49 6114 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
b48d8916
AS
6115 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6116 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6117
6118 /* firmware defaults to 40MHz disabled in 2G band. We signal
6119 * cfg80211 here that we do and have it decide we can enable
6120 * it. But first check if device does support 2G operation.
6121 */
6122 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6123 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6124 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6125 }
6126 err = wiphy_register(wiphy);
6127 if (err < 0) {
6128 brcmf_err("Could not register wiphy device (%d)\n", err);
6129 goto priv_out;
ccfd1e81
AS
6130 }
6131
6132 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6133 * setup 40MHz in 2GHz band and enable OBSS scanning.
6134 */
b48d8916
AS
6135 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6136 err = brcmf_enable_bw40_2g(cfg);
ccfd1e81
AS
6137 if (!err)
6138 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6139 BRCMF_OBSS_COEX_AUTO);
b48d8916
AS
6140 else
6141 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ccfd1e81 6142 }
ccfd1e81 6143
b48d8916 6144 err = brcmf_p2p_attach(cfg);
ccfd1e81 6145 if (err) {
b48d8916
AS
6146 brcmf_err("P2P initilisation failed (%d)\n", err);
6147 goto wiphy_unreg_out;
6148 }
6149 err = brcmf_btcoex_attach(cfg);
6150 if (err) {
6151 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6152 brcmf_p2p_detach(&cfg->p2p);
6153 goto wiphy_unreg_out;
ccfd1e81
AS
6154 }
6155
b48d8916 6156 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
ccfd1e81 6157 if (err) {
b48d8916
AS
6158 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6159 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
70b7d94b
HM
6160 } else {
6161 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6162 brcmf_notify_tdls_peer_event);
ccfd1e81 6163 }
ccfd1e81
AS
6164
6165 return cfg;
6166
b48d8916
AS
6167wiphy_unreg_out:
6168 wiphy_unregister(cfg->wiphy);
6169priv_out:
ccfd1e81 6170 wl_deinit_priv(cfg);
ccfd1e81 6171 brcmf_free_vif(vif);
b48d8916
AS
6172wiphy_out:
6173 brcmf_free_wiphy(wiphy);
ccfd1e81
AS
6174 return NULL;
6175}
6176
6177void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6178{
6179 if (!cfg)
6180 return;
6181
6182 WARN_ON(!list_empty(&cfg->vif_list));
6183 wiphy_unregister(cfg->wiphy);
6184 brcmf_btcoex_detach(cfg);
c3da74bb 6185 brcmf_p2p_detach(&cfg->p2p);
ccfd1e81 6186 wl_deinit_priv(cfg);
b48d8916 6187 brcmf_free_wiphy(cfg->wiphy);
ccfd1e81 6188}
This page took 0.876411 seconds and 5 git commands to generate.