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