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