brcmfmac: use struct net_device::destructor to remove interfaces
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / wl_cfg80211.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
5b435de0 20#include <linux/etherdevice.h>
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;
647c9ae0 2251 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2252
c1179033 2253 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2254 if (err) {
2255 if (err == -ENODEV)
57d6e91a 2256 brcmf_err("net_device is not ready yet\n");
5b435de0 2257 else
57d6e91a 2258 brcmf_err("error (%d)\n", err);
5b435de0
AS
2259 }
2260done:
d96b801f 2261 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2262 return err;
2263}
2264
27a68fe3 2265static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2266 struct brcmf_bss_info_le *bi)
5b435de0 2267{
27a68fe3 2268 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2269 struct ieee80211_channel *notify_channel;
2270 struct cfg80211_bss *bss;
2271 struct ieee80211_supported_band *band;
83cf17aa 2272 struct brcmu_chan ch;
5b435de0
AS
2273 s32 err = 0;
2274 u16 channel;
2275 u32 freq;
5b435de0
AS
2276 u16 notify_capability;
2277 u16 notify_interval;
2278 u8 *notify_ie;
2279 size_t notify_ielen;
2280 s32 notify_signal;
2281
2282 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2283 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2284 return 0;
2285 }
2286
83cf17aa
FL
2287 if (!bi->ctl_ch) {
2288 ch.chspec = le16_to_cpu(bi->chanspec);
2289 cfg->d11inf.decchspec(&ch);
2290 bi->ctl_ch = ch.chnum;
2291 }
2292 channel = bi->ctl_ch;
5b435de0
AS
2293
2294 if (channel <= CH_MAX_2G_CHANNEL)
2295 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2296 else
2297 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2298
2299 freq = ieee80211_channel_to_frequency(channel, band->band);
2300 notify_channel = ieee80211_get_channel(wiphy, freq);
2301
5b435de0
AS
2302 notify_capability = le16_to_cpu(bi->capability);
2303 notify_interval = le16_to_cpu(bi->beacon_period);
2304 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2305 notify_ielen = le32_to_cpu(bi->ie_length);
2306 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2307
16886735
AS
2308 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2309 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2310 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2311 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2312 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0
AS
2313
2314 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
8e6cffb3 2315 0, notify_capability, notify_interval, notify_ie,
5b435de0
AS
2316 notify_ielen, notify_signal, GFP_KERNEL);
2317
e78946e1
FL
2318 if (!bss)
2319 return -ENOMEM;
2320
5b112d3d 2321 cfg80211_put_bss(wiphy, bss);
5b435de0
AS
2322
2323 return err;
2324}
2325
6f09be0a
RV
2326static struct brcmf_bss_info_le *
2327next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2328{
2329 if (bss == NULL)
2330 return list->bss_info_le;
2331 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2332 le32_to_cpu(bss->length));
2333}
2334
27a68fe3 2335static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2336{
2337 struct brcmf_scan_results *bss_list;
d34bf64f 2338 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2339 s32 err = 0;
2340 int i;
2341
27a68fe3 2342 bss_list = cfg->bss_list;
0ecd8164
AS
2343 if (bss_list->count != 0 &&
2344 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2345 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2346 bss_list->version);
5b435de0
AS
2347 return -EOPNOTSUPP;
2348 }
4e8a008e 2349 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2350 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2351 bi = next_bss_le(bss_list, bi);
27a68fe3 2352 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2353 if (err)
2354 break;
2355 }
2356 return err;
2357}
2358
27a68fe3 2359static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2360 struct net_device *ndev, const u8 *bssid)
2361{
27a68fe3 2362 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2363 struct ieee80211_channel *notify_channel;
d34bf64f 2364 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2365 struct ieee80211_supported_band *band;
e78946e1 2366 struct cfg80211_bss *bss;
83cf17aa 2367 struct brcmu_chan ch;
5b435de0
AS
2368 u8 *buf = NULL;
2369 s32 err = 0;
5b435de0 2370 u32 freq;
5b435de0
AS
2371 u16 notify_capability;
2372 u16 notify_interval;
2373 u8 *notify_ie;
2374 size_t notify_ielen;
2375 s32 notify_signal;
2376
d96b801f 2377 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2378
2379 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2380 if (buf == NULL) {
2381 err = -ENOMEM;
2382 goto CleanUp;
2383 }
2384
2385 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2386
ac24be6f
AS
2387 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2388 buf, WL_BSS_INFO_MAX);
5b435de0 2389 if (err) {
57d6e91a 2390 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2391 goto CleanUp;
2392 }
2393
d34bf64f 2394 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0 2395
83cf17aa
FL
2396 ch.chspec = le16_to_cpu(bi->chanspec);
2397 cfg->d11inf.decchspec(&ch);
5b435de0 2398
83cf17aa 2399 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
2400 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2401 else
2402 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2403
83cf17aa 2404 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
2405 notify_channel = ieee80211_get_channel(wiphy, freq);
2406
5b435de0
AS
2407 notify_capability = le16_to_cpu(bi->capability);
2408 notify_interval = le16_to_cpu(bi->beacon_period);
2409 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2410 notify_ielen = le32_to_cpu(bi->ie_length);
2411 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2412
83cf17aa 2413 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
16886735
AS
2414 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2415 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2416 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2417
e78946e1 2418 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
8e6cffb3 2419 0, notify_capability, notify_interval,
5b435de0
AS
2420 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2421
e78946e1
FL
2422 if (!bss) {
2423 err = -ENOMEM;
2424 goto CleanUp;
2425 }
2426
5b112d3d 2427 cfg80211_put_bss(wiphy, bss);
e78946e1 2428
5b435de0
AS
2429CleanUp:
2430
2431 kfree(buf);
2432
d96b801f 2433 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2434
2435 return err;
2436}
2437
128ce3b6 2438static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
5b435de0 2439{
128ce3b6 2440 return vif->mode == WL_MODE_IBSS;
5b435de0
AS
2441}
2442
89286dc9
HM
2443static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2444 struct brcmf_if *ifp)
1a873342 2445{
89286dc9 2446 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
d34bf64f 2447 struct brcmf_bss_info_le *bi;
5b435de0 2448 struct brcmf_ssid *ssid;
f8e4b412 2449 struct brcmf_tlv *tim;
5b435de0
AS
2450 u16 beacon_interval;
2451 u8 dtim_period;
2452 size_t ie_len;
2453 u8 *ie;
2454 s32 err = 0;
2455
d96b801f 2456 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2457 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2458 return err;
2459
06bb123e 2460 ssid = &profile->ssid;
5b435de0 2461
27a68fe3 2462 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2463 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2464 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2465 if (err) {
57d6e91a 2466 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2467 goto update_bss_info_out;
2468 }
2469
27a68fe3
AS
2470 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2471 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2472 if (err)
2473 goto update_bss_info_out;
2474
2475 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2476 ie_len = le32_to_cpu(bi->ie_length);
2477 beacon_interval = le16_to_cpu(bi->beacon_period);
2478
f8e4b412 2479 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2480 if (tim)
2481 dtim_period = tim->data[1];
2482 else {
2483 /*
2484 * active scan was done so we could not get dtim
2485 * information out of probe response.
2486 * so we speficially query dtim information to dongle.
2487 */
2488 u32 var;
ac24be6f 2489 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2490 if (err) {
57d6e91a 2491 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2492 goto update_bss_info_out;
2493 }
2494 dtim_period = (u8)var;
2495 }
2496
5b435de0 2497update_bss_info_out:
d96b801f 2498 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2499 return err;
2500}
2501
18e2f61d 2502void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2503{
27a68fe3 2504 struct escan_info *escan = &cfg->escan_info;
5b435de0 2505
c1179033 2506 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2507 if (cfg->scan_request) {
108a4bee 2508 escan->escan_state = WL_ESCAN_STATE_IDLE;
a0f472ac 2509 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
5b435de0 2510 }
c1179033
AS
2511 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2512 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2513}
2514
e756af5b
HM
2515static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2516{
27a68fe3
AS
2517 struct brcmf_cfg80211_info *cfg =
2518 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2519 escan_timeout_work);
2520
a0f472ac 2521 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
e756af5b
HM
2522}
2523
2524static void brcmf_escan_timeout(unsigned long data)
2525{
27a68fe3
AS
2526 struct brcmf_cfg80211_info *cfg =
2527 (struct brcmf_cfg80211_info *)data;
e756af5b 2528
27a68fe3 2529 if (cfg->scan_request) {
57d6e91a 2530 brcmf_err("timer expired\n");
f0799895 2531 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2532 }
2533}
2534
2535static s32
83cf17aa
FL
2536brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2537 struct brcmf_bss_info_le *bss,
e756af5b
HM
2538 struct brcmf_bss_info_le *bss_info_le)
2539{
83cf17aa
FL
2540 struct brcmu_chan ch_bss, ch_bss_info_le;
2541
2542 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2543 cfg->d11inf.decchspec(&ch_bss);
2544 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2545 cfg->d11inf.decchspec(&ch_bss_info_le);
2546
e756af5b 2547 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
83cf17aa 2548 ch_bss.band == ch_bss_info_le.band &&
e756af5b
HM
2549 bss_info_le->SSID_len == bss->SSID_len &&
2550 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2551 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2552 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2553 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2554 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2555
e756af5b
HM
2556 /* preserve max RSSI if the measurements are
2557 * both on-channel or both off-channel
2558 */
029591f3 2559 if (bss_info_rssi > bss_rssi)
e756af5b
HM
2560 bss->RSSI = bss_info_le->RSSI;
2561 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2562 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2563 /* preserve the on-channel rssi measurement
2564 * if the new measurement is off channel
2565 */
2566 bss->RSSI = bss_info_le->RSSI;
2567 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2568 }
2569 return 1;
2570 }
2571 return 0;
2572}
2573
2574static s32
1993732e 2575brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2576 const struct brcmf_event_msg *e, void *data)
2577{
1993732e 2578 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e756af5b
HM
2579 s32 status;
2580 s32 err = 0;
2581 struct brcmf_escan_result_le *escan_result_le;
2582 struct brcmf_bss_info_le *bss_info_le;
2583 struct brcmf_bss_info_le *bss = NULL;
2584 u32 bi_length;
2585 struct brcmf_scan_results *list;
2586 u32 i;
97ed15c7 2587 bool aborted;
e756af5b 2588
5c36b99a 2589 status = e->status;
e756af5b 2590
a0f472ac
AS
2591 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2592 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
e756af5b
HM
2593 return -EPERM;
2594 }
2595
2596 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2597 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2598 escan_result_le = (struct brcmf_escan_result_le *) data;
2599 if (!escan_result_le) {
57d6e91a 2600 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2601 goto exit;
2602 }
e756af5b 2603 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2604 brcmf_err("Invalid bss_count %d: ignoring\n",
2605 escan_result_le->bss_count);
e756af5b
HM
2606 goto exit;
2607 }
2608 bss_info_le = &escan_result_le->bss_info_le;
2609
6eda4e2c
HM
2610 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2611 goto exit;
2612
2613 if (!cfg->scan_request) {
2614 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2615 goto exit;
2616 }
2617
e756af5b
HM
2618 bi_length = le32_to_cpu(bss_info_le->length);
2619 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2620 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
2621 brcmf_err("Invalid bss_info length %d: ignoring\n",
2622 bi_length);
e756af5b
HM
2623 goto exit;
2624 }
2625
27a68fe3 2626 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2627 BIT(NL80211_IFTYPE_ADHOC))) {
2628 if (le16_to_cpu(bss_info_le->capability) &
2629 WLAN_CAPABILITY_IBSS) {
57d6e91a 2630 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
2631 goto exit;
2632 }
2633 }
2634
2635 list = (struct brcmf_scan_results *)
27a68fe3 2636 cfg->escan_info.escan_buf;
e756af5b 2637 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 2638 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
2639 goto exit;
2640 }
2641
2642 for (i = 0; i < list->count; i++) {
2643 bss = bss ? (struct brcmf_bss_info_le *)
2644 ((unsigned char *)bss +
2645 le32_to_cpu(bss->length)) : list->bss_info_le;
83cf17aa
FL
2646 if (brcmf_compare_update_same_bss(cfg, bss,
2647 bss_info_le))
e756af5b
HM
2648 goto exit;
2649 }
27a68fe3 2650 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2651 bss_info_le, bi_length);
2652 list->version = le32_to_cpu(bss_info_le->version);
2653 list->buflen += bi_length;
2654 list->count++;
2655 } else {
27a68fe3 2656 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
2657 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2658 goto exit;
27a68fe3
AS
2659 if (cfg->scan_request) {
2660 cfg->bss_list = (struct brcmf_scan_results *)
2661 cfg->escan_info.escan_buf;
2662 brcmf_inform_bss(cfg);
97ed15c7 2663 aborted = status != BRCMF_E_STATUS_SUCCESS;
a0f472ac 2664 brcmf_notify_escan_complete(cfg, ifp, aborted,
97ed15c7 2665 false);
e756af5b 2666 } else
6eda4e2c
HM
2667 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2668 status);
e756af5b
HM
2669 }
2670exit:
2671 return err;
2672}
2673
27a68fe3 2674static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 2675{
5c36b99a
AS
2676 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2677 brcmf_cfg80211_escan_handler);
f0799895
HM
2678 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2679 /* Init scan_timeout timer */
2680 init_timer(&cfg->escan_timeout);
2681 cfg->escan_timeout.data = (unsigned long) cfg;
2682 cfg->escan_timeout.function = brcmf_escan_timeout;
2683 INIT_WORK(&cfg->escan_timeout_work,
2684 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2685}
2686
5addc0de 2687static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2688{
2689 if (ms < 1000 / HZ) {
2690 cond_resched();
2691 mdelay(ms);
2692 } else {
2693 msleep(ms);
2694 }
2695}
2696
2697static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2698{
d96b801f 2699 brcmf_dbg(TRACE, "Enter\n");
5b435de0 2700
5b435de0
AS
2701 return 0;
2702}
2703
2704static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2705 struct cfg80211_wowlan *wow)
2706{
27a68fe3
AS
2707 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2708 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 2709 struct brcmf_cfg80211_vif *vif;
5b435de0 2710
d96b801f 2711 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2712
2713 /*
7d641072
AS
2714 * if the primary net_device is not READY there is nothing
2715 * we can do but pray resume goes smoothly.
5b435de0 2716 */
7d641072
AS
2717 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2718 if (!check_vif_up(vif))
2719 goto exit;
5b435de0 2720
7d641072
AS
2721 list_for_each_entry(vif, &cfg->vif_list, list) {
2722 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2723 continue;
5b435de0 2724 /*
7d641072
AS
2725 * While going to suspend if associated with AP disassociate
2726 * from AP to save power while system is in suspended state
5b435de0 2727 */
903e0eee
AS
2728 brcmf_link_down(vif);
2729
2730 /* Make sure WPA_Supplicant receives all the event
2731 * generated due to DISASSOC call to the fw to keep
2732 * the state fw and WPA_Supplicant state consistent
2733 */
2734 brcmf_delay(500);
5b435de0
AS
2735 }
2736
7d641072
AS
2737 /* end any scanning */
2738 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 2739 brcmf_abort_scanning(cfg);
5b435de0
AS
2740
2741 /* Turn off watchdog timer */
f96aa07e 2742 brcmf_set_mpc(netdev_priv(ndev), 1);
5b435de0 2743
7d641072 2744exit:
d96b801f 2745 brcmf_dbg(TRACE, "Exit\n");
7d641072
AS
2746 /* clear any scanning activity */
2747 cfg->scan_status = 0;
5b435de0
AS
2748 return 0;
2749}
2750
5b435de0
AS
2751static __used s32
2752brcmf_update_pmklist(struct net_device *ndev,
2753 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2754{
2755 int i, j;
40c8e95a 2756 int pmkid_len;
5b435de0 2757
40c8e95a
AS
2758 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2759
16886735 2760 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
40c8e95a 2761 for (i = 0; i < pmkid_len; i++) {
16886735
AS
2762 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2763 &pmk_list->pmkids.pmkid[i].BSSID);
5b435de0 2764 for (j = 0; j < WLAN_PMKID_LEN; j++)
16886735
AS
2765 brcmf_dbg(CONN, "%02x\n",
2766 pmk_list->pmkids.pmkid[i].PMKID[j]);
5b435de0
AS
2767 }
2768
2769 if (!err)
ac24be6f
AS
2770 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2771 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
2772
2773 return err;
2774}
2775
2776static s32
2777brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2778 struct cfg80211_pmksa *pmksa)
2779{
27a68fe3 2780 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2781 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2782 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
2783 s32 err = 0;
2784 int i;
40c8e95a 2785 int pmkid_len;
5b435de0 2786
d96b801f 2787 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2788 if (!check_vif_up(ifp->vif))
5b435de0
AS
2789 return -EIO;
2790
40c8e95a
AS
2791 pmkid_len = le32_to_cpu(pmkids->npmkid);
2792 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
2793 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2794 break;
2795 if (i < WL_NUM_PMKIDS_MAX) {
2796 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2797 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
2798 if (i == pmkid_len) {
2799 pmkid_len++;
2800 pmkids->npmkid = cpu_to_le32(pmkid_len);
2801 }
5b435de0
AS
2802 } else
2803 err = -EINVAL;
2804
16886735
AS
2805 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2806 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 2807 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2808 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 2809
27a68fe3 2810 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2811
d96b801f 2812 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2813 return err;
2814}
2815
2816static s32
2817brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2818 struct cfg80211_pmksa *pmksa)
2819{
27a68fe3 2820 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2821 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2822 struct pmkid_list pmkid;
2823 s32 err = 0;
40c8e95a 2824 int i, pmkid_len;
5b435de0 2825
d96b801f 2826 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2827 if (!check_vif_up(ifp->vif))
5b435de0
AS
2828 return -EIO;
2829
2830 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2831 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2832
16886735
AS
2833 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2834 &pmkid.pmkid[0].BSSID);
5b435de0 2835 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2836 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
5b435de0 2837
27a68fe3 2838 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 2839 for (i = 0; i < pmkid_len; i++)
5b435de0 2840 if (!memcmp
27a68fe3 2841 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
2842 ETH_ALEN))
2843 break;
2844
40c8e95a
AS
2845 if ((pmkid_len > 0)
2846 && (i < pmkid_len)) {
27a68fe3 2847 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 2848 sizeof(struct pmkid));
40c8e95a 2849 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
2850 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2851 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 2852 ETH_ALEN);
27a68fe3
AS
2853 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2854 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
2855 WLAN_PMKID_LEN);
2856 }
27a68fe3 2857 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
2858 } else
2859 err = -EINVAL;
2860
27a68fe3 2861 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2862
d96b801f 2863 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2864 return err;
2865
2866}
2867
2868static s32
2869brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2870{
27a68fe3 2871 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2872 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2873 s32 err = 0;
2874
d96b801f 2875 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2876 if (!check_vif_up(ifp->vif))
5b435de0
AS
2877 return -EIO;
2878
27a68fe3
AS
2879 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2880 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2881
d96b801f 2882 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2883 return err;
2884
2885}
2886
e5806072
AS
2887/*
2888 * PFN result doesn't have all the info which are
2889 * required by the supplicant
2890 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2891 * via wl_inform_single_bss in the required format. Escan does require the
2892 * scan request in the form of cfg80211_scan_request. For timebeing, create
2893 * cfg80211_scan_request one out of the received PNO event.
2894 */
2895static s32
1993732e 2896brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
2897 const struct brcmf_event_msg *e, void *data)
2898{
1993732e 2899 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e5806072
AS
2900 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2901 struct cfg80211_scan_request *request = NULL;
2902 struct cfg80211_ssid *ssid = NULL;
2903 struct ieee80211_channel *channel = NULL;
27a68fe3 2904 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
2905 int err = 0;
2906 int channel_req = 0;
2907 int band = 0;
2908 struct brcmf_pno_scanresults_le *pfn_result;
2909 u32 result_count;
2910 u32 status;
2911
4e8a008e 2912 brcmf_dbg(SCAN, "Enter\n");
e5806072 2913
5c36b99a 2914 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
4e8a008e 2915 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
e5806072
AS
2916 return 0;
2917 }
2918
2919 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2920 result_count = le32_to_cpu(pfn_result->count);
2921 status = le32_to_cpu(pfn_result->status);
2922
2923 /*
2924 * PFN event is limited to fit 512 bytes so we may get
2925 * multiple NET_FOUND events. For now place a warning here.
2926 */
2927 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
4e8a008e 2928 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
e5806072
AS
2929 if (result_count > 0) {
2930 int i;
2931
2932 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
2933 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2934 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
2935 if (!request || !ssid || !channel) {
2936 err = -ENOMEM;
2937 goto out_err;
2938 }
2939
2940 request->wiphy = wiphy;
2941 data += sizeof(struct brcmf_pno_scanresults_le);
2942 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2943
2944 for (i = 0; i < result_count; i++) {
2945 netinfo = &netinfo_start[i];
2946 if (!netinfo) {
57d6e91a
AS
2947 brcmf_err("Invalid netinfo ptr. index: %d\n",
2948 i);
e5806072
AS
2949 err = -EINVAL;
2950 goto out_err;
2951 }
2952
4e8a008e
AS
2953 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2954 netinfo->SSID, netinfo->channel);
e5806072
AS
2955 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2956 ssid[i].ssid_len = netinfo->SSID_len;
2957 request->n_ssids++;
2958
2959 channel_req = netinfo->channel;
2960 if (channel_req <= CH_MAX_2G_CHANNEL)
2961 band = NL80211_BAND_2GHZ;
2962 else
2963 band = NL80211_BAND_5GHZ;
2964 channel[i].center_freq =
2965 ieee80211_channel_to_frequency(channel_req,
2966 band);
2967 channel[i].band = band;
2968 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2969 request->channels[i] = &channel[i];
2970 request->n_channels++;
2971 }
2972
2973 /* assign parsed ssid array */
2974 if (request->n_ssids)
2975 request->ssids = &ssid[0];
2976
c1179033 2977 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 2978 /* Abort any on-going scan */
27a68fe3 2979 brcmf_abort_scanning(cfg);
e5806072
AS
2980 }
2981
c1179033 2982 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
a0f472ac 2983 err = brcmf_do_escan(cfg, wiphy, ifp, request);
e5806072 2984 if (err) {
c1179033 2985 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
2986 goto out_err;
2987 }
27a68fe3
AS
2988 cfg->sched_escan = true;
2989 cfg->scan_request = request;
e5806072 2990 } else {
57d6e91a 2991 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
e5806072
AS
2992 goto out_err;
2993 }
2994
2995 kfree(ssid);
2996 kfree(channel);
2997 kfree(request);
2998 return 0;
2999
3000out_err:
3001 kfree(ssid);
3002 kfree(channel);
3003 kfree(request);
3004 cfg80211_sched_scan_stopped(wiphy);
3005 return err;
3006}
3007
e5806072
AS
3008static int brcmf_dev_pno_clean(struct net_device *ndev)
3009{
e5806072
AS
3010 int ret;
3011
3012 /* Disable pfn */
ac24be6f 3013 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3014 if (ret == 0) {
3015 /* clear pfn */
ac24be6f
AS
3016 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3017 NULL, 0);
e5806072
AS
3018 }
3019 if (ret < 0)
57d6e91a 3020 brcmf_err("failed code %d\n", ret);
e5806072
AS
3021
3022 return ret;
3023}
3024
3025static int brcmf_dev_pno_config(struct net_device *ndev)
3026{
3027 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3028
3029 memset(&pfn_param, 0, sizeof(pfn_param));
3030 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3031
3032 /* set extra pno params */
3033 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3034 pfn_param.repeat = BRCMF_PNO_REPEAT;
3035 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3036
3037 /* set up pno scan fr */
3038 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3039
ac24be6f
AS
3040 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3041 &pfn_param, sizeof(pfn_param));
e5806072
AS
3042}
3043
3044static int
3045brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3046 struct net_device *ndev,
3047 struct cfg80211_sched_scan_request *request)
3048{
c1179033 3049 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3050 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3051 struct brcmf_pno_net_param_le pfn;
3052 int i;
3053 int ret = 0;
3054
dc7bdbf1 3055 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
4e8a008e 3056 request->n_match_sets, request->n_ssids);
c1179033 3057 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 3058 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3059 return -EAGAIN;
3060 }
1687eee2
AS
3061 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3062 brcmf_err("Scanning suppressed: status (%lu)\n",
3063 cfg->scan_status);
3064 return -EAGAIN;
3065 }
e5806072 3066
dc7bdbf1 3067 if (!request->n_ssids || !request->n_match_sets) {
57d6e91a 3068 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
dc7bdbf1 3069 request->n_ssids);
e5806072
AS
3070 return -EINVAL;
3071 }
3072
3073 if (request->n_ssids > 0) {
3074 for (i = 0; i < request->n_ssids; i++) {
3075 /* Active scan req for ssids */
4e8a008e
AS
3076 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3077 request->ssids[i].ssid);
e5806072
AS
3078
3079 /*
3080 * match_set ssids is a supert set of n_ssid list,
3081 * so we need not add these set seperately.
3082 */
3083 }
3084 }
3085
3086 if (request->n_match_sets > 0) {
3087 /* clean up everything */
3088 ret = brcmf_dev_pno_clean(ndev);
3089 if (ret < 0) {
57d6e91a 3090 brcmf_err("failed error=%d\n", ret);
e5806072
AS
3091 return ret;
3092 }
3093
3094 /* configure pno */
3095 ret = brcmf_dev_pno_config(ndev);
3096 if (ret < 0) {
57d6e91a 3097 brcmf_err("PNO setup failed!! ret=%d\n", ret);
e5806072
AS
3098 return -EINVAL;
3099 }
3100
3101 /* configure each match set */
3102 for (i = 0; i < request->n_match_sets; i++) {
3103 struct cfg80211_ssid *ssid;
3104 u32 ssid_len;
3105
3106 ssid = &request->match_sets[i].ssid;
3107 ssid_len = ssid->ssid_len;
3108
3109 if (!ssid_len) {
57d6e91a 3110 brcmf_err("skip broadcast ssid\n");
e5806072
AS
3111 continue;
3112 }
3113 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3114 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3115 pfn.wsec = cpu_to_le32(0);
3116 pfn.infra = cpu_to_le32(1);
3117 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3118 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3119 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3120 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3121 sizeof(pfn));
4e8a008e
AS
3122 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3123 ret == 0 ? "set" : "failed", ssid->ssid);
e5806072
AS
3124 }
3125 /* Enable the PNO */
c1179033 3126 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
57d6e91a 3127 brcmf_err("PNO enable failed!! ret=%d\n", ret);
e5806072
AS
3128 return -EINVAL;
3129 }
3130 } else {
3131 return -EINVAL;
3132 }
3133
3134 return 0;
3135}
3136
3137static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3138 struct net_device *ndev)
3139{
27a68fe3 3140 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072 3141
4e8a008e 3142 brcmf_dbg(SCAN, "enter\n");
e5806072 3143 brcmf_dev_pno_clean(ndev);
27a68fe3 3144 if (cfg->sched_escan)
a0f472ac 3145 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
e5806072
AS
3146 return 0;
3147}
e5806072 3148
cbaa177d
AS
3149#ifdef CONFIG_NL80211_TESTMODE
3150static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3151{
27a68fe3 3152 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3153 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3154 struct brcmf_dcmd *dcmd = data;
3155 struct sk_buff *reply;
3156 int ret;
3157
d96b801f
AS
3158 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3159 dcmd->buf, dcmd->len);
f368a5b6
HM
3160
3161 if (dcmd->set)
ac24be6f
AS
3162 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3163 dcmd->buf, dcmd->len);
f368a5b6 3164 else
ac24be6f
AS
3165 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3166 dcmd->buf, dcmd->len);
cbaa177d
AS
3167 if (ret == 0) {
3168 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3169 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3170 ret = cfg80211_testmode_reply(reply);
3171 }
3172 return ret;
3173}
3174#endif
3175
1f170110 3176static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3177{
3178 s32 err;
3179
3180 /* set auth */
ac24be6f 3181 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3182 if (err < 0) {
57d6e91a 3183 brcmf_err("auth error %d\n", err);
1a873342
HM
3184 return err;
3185 }
3186 /* set wsec */
ac24be6f 3187 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3188 if (err < 0) {
57d6e91a 3189 brcmf_err("wsec error %d\n", err);
1a873342
HM
3190 return err;
3191 }
3192 /* set upper-layer auth */
ac24be6f 3193 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3194 if (err < 0) {
57d6e91a 3195 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3196 return err;
3197 }
3198
3199 return 0;
3200}
3201
3202static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3203{
3204 if (is_rsn_ie)
3205 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3206
3207 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3208}
3209
3210static s32
3211brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
34778529 3212 bool is_rsn_ie)
1a873342 3213{
ac24be6f 3214 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3215 u32 auth = 0; /* d11 open authentication */
3216 u16 count;
3217 s32 err = 0;
3218 s32 len = 0;
3219 u32 i;
3220 u32 wsec;
3221 u32 pval = 0;
3222 u32 gval = 0;
3223 u32 wpa_auth = 0;
3224 u32 offset;
3225 u8 *data;
3226 u16 rsn_cap;
3227 u32 wme_bss_disable;
3228
d96b801f 3229 brcmf_dbg(TRACE, "Enter\n");
1a873342
HM
3230 if (wpa_ie == NULL)
3231 goto exit;
3232
3233 len = wpa_ie->len + TLV_HDR_LEN;
3234 data = (u8 *)wpa_ie;
619c5a9a 3235 offset = TLV_HDR_LEN;
1a873342
HM
3236 if (!is_rsn_ie)
3237 offset += VS_IE_FIXED_HDR_LEN;
619c5a9a
HM
3238 else
3239 offset += WPA_IE_VERSION_LEN;
1a873342
HM
3240
3241 /* check for multicast cipher suite */
3242 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3243 err = -EINVAL;
57d6e91a 3244 brcmf_err("no multicast cipher suite\n");
1a873342
HM
3245 goto exit;
3246 }
3247
3248 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3249 err = -EINVAL;
57d6e91a 3250 brcmf_err("ivalid OUI\n");
1a873342
HM
3251 goto exit;
3252 }
3253 offset += TLV_OUI_LEN;
3254
3255 /* pick up multicast cipher */
3256 switch (data[offset]) {
3257 case WPA_CIPHER_NONE:
3258 gval = 0;
3259 break;
3260 case WPA_CIPHER_WEP_40:
3261 case WPA_CIPHER_WEP_104:
3262 gval = WEP_ENABLED;
3263 break;
3264 case WPA_CIPHER_TKIP:
3265 gval = TKIP_ENABLED;
3266 break;
3267 case WPA_CIPHER_AES_CCM:
3268 gval = AES_ENABLED;
3269 break;
3270 default:
3271 err = -EINVAL;
57d6e91a 3272 brcmf_err("Invalid multi cast cipher info\n");
1a873342
HM
3273 goto exit;
3274 }
3275
3276 offset++;
3277 /* walk thru unicast cipher list and pick up what we recognize */
3278 count = data[offset] + (data[offset + 1] << 8);
3279 offset += WPA_IE_SUITE_COUNT_LEN;
3280 /* Check for unicast suite(s) */
3281 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3282 err = -EINVAL;
57d6e91a 3283 brcmf_err("no unicast cipher suite\n");
1a873342
HM
3284 goto exit;
3285 }
3286 for (i = 0; i < count; i++) {
3287 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3288 err = -EINVAL;
57d6e91a 3289 brcmf_err("ivalid OUI\n");
1a873342
HM
3290 goto exit;
3291 }
3292 offset += TLV_OUI_LEN;
3293 switch (data[offset]) {
3294 case WPA_CIPHER_NONE:
3295 break;
3296 case WPA_CIPHER_WEP_40:
3297 case WPA_CIPHER_WEP_104:
3298 pval |= WEP_ENABLED;
3299 break;
3300 case WPA_CIPHER_TKIP:
3301 pval |= TKIP_ENABLED;
3302 break;
3303 case WPA_CIPHER_AES_CCM:
3304 pval |= AES_ENABLED;
3305 break;
3306 default:
57d6e91a 3307 brcmf_err("Ivalid unicast security info\n");
1a873342
HM
3308 }
3309 offset++;
3310 }
3311 /* walk thru auth management suite list and pick up what we recognize */
3312 count = data[offset] + (data[offset + 1] << 8);
3313 offset += WPA_IE_SUITE_COUNT_LEN;
3314 /* Check for auth key management suite(s) */
3315 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3316 err = -EINVAL;
57d6e91a 3317 brcmf_err("no auth key mgmt suite\n");
1a873342
HM
3318 goto exit;
3319 }
3320 for (i = 0; i < count; i++) {
3321 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3322 err = -EINVAL;
57d6e91a 3323 brcmf_err("ivalid OUI\n");
1a873342
HM
3324 goto exit;
3325 }
3326 offset += TLV_OUI_LEN;
3327 switch (data[offset]) {
3328 case RSN_AKM_NONE:
d96b801f 3329 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
1a873342
HM
3330 wpa_auth |= WPA_AUTH_NONE;
3331 break;
3332 case RSN_AKM_UNSPECIFIED:
d96b801f 3333 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
1a873342
HM
3334 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3335 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3336 break;
3337 case RSN_AKM_PSK:
d96b801f 3338 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
1a873342
HM
3339 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3340 (wpa_auth |= WPA_AUTH_PSK);
3341 break;
3342 default:
57d6e91a 3343 brcmf_err("Ivalid key mgmt info\n");
1a873342
HM
3344 }
3345 offset++;
3346 }
3347
3348 if (is_rsn_ie) {
3349 wme_bss_disable = 1;
3350 if ((offset + RSN_CAP_LEN) <= len) {
3351 rsn_cap = data[offset] + (data[offset + 1] << 8);
3352 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3353 wme_bss_disable = 0;
3354 }
3355 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3356 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3357 wme_bss_disable);
1a873342 3358 if (err < 0) {
57d6e91a 3359 brcmf_err("wme_bss_disable error %d\n", err);
1a873342
HM
3360 goto exit;
3361 }
3362 }
3363 /* FOR WPS , set SES_OW_ENABLED */
3364 wsec = (pval | gval | SES_OW_ENABLED);
3365
3366 /* set auth */
ac24be6f 3367 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342 3368 if (err < 0) {
57d6e91a 3369 brcmf_err("auth error %d\n", err);
1a873342
HM
3370 goto exit;
3371 }
3372 /* set wsec */
ac24be6f 3373 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342 3374 if (err < 0) {
57d6e91a 3375 brcmf_err("wsec error %d\n", err);
1a873342
HM
3376 goto exit;
3377 }
3378 /* set upper-layer auth */
ac24be6f 3379 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342 3380 if (err < 0) {
57d6e91a 3381 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3382 goto exit;
3383 }
3384
3385exit:
3386 return err;
3387}
3388
3389static s32
3082b9be 3390brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
3391 struct parsed_vndr_ies *vndr_ies)
3392{
3393 s32 err = 0;
3394 struct brcmf_vs_tlv *vndrie;
3395 struct brcmf_tlv *ie;
3396 struct parsed_vndr_ie_info *parsed_info;
3397 s32 remaining_len;
3398
3399 remaining_len = (s32)vndr_ie_len;
3400 memset(vndr_ies, 0, sizeof(*vndr_ies));
3401
3402 ie = (struct brcmf_tlv *)vndr_ie_buf;
3403 while (ie) {
3404 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3405 goto next;
3406 vndrie = (struct brcmf_vs_tlv *)ie;
3407 /* len should be bigger than OUI length + one */
3408 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
57d6e91a
AS
3409 brcmf_err("invalid vndr ie. length is too small %d\n",
3410 vndrie->len);
1a873342
HM
3411 goto next;
3412 }
3413 /* if wpa or wme ie, do not add ie */
3414 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3415 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3416 (vndrie->oui_type == WME_OUI_TYPE))) {
d96b801f 3417 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
1a873342
HM
3418 goto next;
3419 }
3420
3421 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3422
3423 /* save vndr ie information */
3424 parsed_info->ie_ptr = (char *)vndrie;
3425 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3426 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3427
3428 vndr_ies->count++;
3429
d96b801f
AS
3430 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3431 parsed_info->vndrie.oui[0],
3432 parsed_info->vndrie.oui[1],
3433 parsed_info->vndrie.oui[2],
3434 parsed_info->vndrie.oui_type);
1a873342 3435
9f440b7b 3436 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
1a873342
HM
3437 break;
3438next:
b41fc3d7
HM
3439 remaining_len -= (ie->len + TLV_HDR_LEN);
3440 if (remaining_len <= TLV_HDR_LEN)
1a873342
HM
3441 ie = NULL;
3442 else
b41fc3d7
HM
3443 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3444 TLV_HDR_LEN);
1a873342
HM
3445 }
3446 return err;
3447}
3448
3449static u32
3450brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3451{
3452
3453 __le32 iecount_le;
3454 __le32 pktflag_le;
3455
3456 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3457 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3458
3459 iecount_le = cpu_to_le32(1);
3460 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3461
3462 pktflag_le = cpu_to_le32(pktflag);
3463 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3464
3465 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3466
3467 return ie_len + VNDR_IE_HDR_SIZE;
3468}
3469
1332e26e
AS
3470s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3471 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 3472{
1332e26e
AS
3473 struct brcmf_if *ifp;
3474 struct vif_saved_ie *saved_ie;
1a873342
HM
3475 s32 err = 0;
3476 u8 *iovar_ie_buf;
3477 u8 *curr_ie_buf;
3478 u8 *mgmt_ie_buf = NULL;
3e4f319d 3479 int mgmt_ie_buf_len;
81118d16 3480 u32 *mgmt_ie_len;
1a873342
HM
3481 u32 del_add_ie_buf_len = 0;
3482 u32 total_ie_buf_len = 0;
3483 u32 parsed_ie_buf_len = 0;
3484 struct parsed_vndr_ies old_vndr_ies;
3485 struct parsed_vndr_ies new_vndr_ies;
3486 struct parsed_vndr_ie_info *vndrie_info;
3487 s32 i;
3488 u8 *ptr;
3e4f319d 3489 int remained_buf_len;
1a873342 3490
1332e26e
AS
3491 if (!vif)
3492 return -ENODEV;
3493 ifp = vif->ifp;
3494 saved_ie = &vif->saved_ie;
3495
d96b801f 3496 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
1a873342
HM
3497 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3498 if (!iovar_ie_buf)
3499 return -ENOMEM;
3500 curr_ie_buf = iovar_ie_buf;
89286dc9
HM
3501 switch (pktflag) {
3502 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3503 mgmt_ie_buf = saved_ie->probe_req_ie;
3504 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3505 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3506 break;
3507 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3508 mgmt_ie_buf = saved_ie->probe_res_ie;
3509 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3510 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3511 break;
3512 case BRCMF_VNDR_IE_BEACON_FLAG:
3513 mgmt_ie_buf = saved_ie->beacon_ie;
3514 mgmt_ie_len = &saved_ie->beacon_ie_len;
3515 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3516 break;
3517 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3518 mgmt_ie_buf = saved_ie->assoc_req_ie;
3519 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3520 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3521 break;
3522 default:
3523 err = -EPERM;
3524 brcmf_err("not suitable type\n");
3525 goto exit;
1a873342
HM
3526 }
3527
3528 if (vndr_ie_len > mgmt_ie_buf_len) {
3529 err = -ENOMEM;
57d6e91a 3530 brcmf_err("extra IE size too big\n");
1a873342
HM
3531 goto exit;
3532 }
3533
3534 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3535 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3536 ptr = curr_ie_buf;
3537 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3538 for (i = 0; i < new_vndr_ies.count; i++) {
3539 vndrie_info = &new_vndr_ies.ie_info[i];
3540 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3541 vndrie_info->ie_len);
3542 parsed_ie_buf_len += vndrie_info->ie_len;
3543 }
3544 }
3545
b41fc3d7 3546 if (mgmt_ie_buf && *mgmt_ie_len) {
1a873342
HM
3547 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3548 (memcmp(mgmt_ie_buf, curr_ie_buf,
3549 parsed_ie_buf_len) == 0)) {
d96b801f 3550 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
1a873342
HM
3551 goto exit;
3552 }
3553
3554 /* parse old vndr_ie */
3555 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3556
3557 /* make a command to delete old ie */
3558 for (i = 0; i < old_vndr_ies.count; i++) {
3559 vndrie_info = &old_vndr_ies.ie_info[i];
3560
d96b801f
AS
3561 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3562 vndrie_info->vndrie.id,
3563 vndrie_info->vndrie.len,
3564 vndrie_info->vndrie.oui[0],
3565 vndrie_info->vndrie.oui[1],
3566 vndrie_info->vndrie.oui[2]);
1a873342
HM
3567
3568 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3569 vndrie_info->ie_ptr,
3570 vndrie_info->ie_len,
3571 "del");
3572 curr_ie_buf += del_add_ie_buf_len;
3573 total_ie_buf_len += del_add_ie_buf_len;
3574 }
3575 }
3576
3577 *mgmt_ie_len = 0;
3578 /* Add if there is any extra IE */
3579 if (mgmt_ie_buf && parsed_ie_buf_len) {
3580 ptr = mgmt_ie_buf;
3581
3582 remained_buf_len = mgmt_ie_buf_len;
3583
3584 /* make a command to add new ie */
3585 for (i = 0; i < new_vndr_ies.count; i++) {
3586 vndrie_info = &new_vndr_ies.ie_info[i];
3587
b41fc3d7
HM
3588 /* verify remained buf size before copy data */
3589 if (remained_buf_len < (vndrie_info->vndrie.len +
3590 VNDR_IE_VSIE_OFFSET)) {
57d6e91a
AS
3591 brcmf_err("no space in mgmt_ie_buf: len left %d",
3592 remained_buf_len);
b41fc3d7
HM
3593 break;
3594 }
3595 remained_buf_len -= (vndrie_info->ie_len +
3596 VNDR_IE_VSIE_OFFSET);
3597
d96b801f
AS
3598 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3599 vndrie_info->vndrie.id,
3600 vndrie_info->vndrie.len,
3601 vndrie_info->vndrie.oui[0],
3602 vndrie_info->vndrie.oui[1],
3603 vndrie_info->vndrie.oui[2]);
1a873342
HM
3604
3605 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3606 vndrie_info->ie_ptr,
3607 vndrie_info->ie_len,
3608 "add");
1a873342
HM
3609
3610 /* save the parsed IE in wl struct */
3611 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3612 vndrie_info->ie_len);
3613 *mgmt_ie_len += vndrie_info->ie_len;
3614
3615 curr_ie_buf += del_add_ie_buf_len;
3616 total_ie_buf_len += del_add_ie_buf_len;
3617 }
3618 }
3619 if (total_ie_buf_len) {
c1179033 3620 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3621 total_ie_buf_len);
1a873342 3622 if (err)
57d6e91a 3623 brcmf_err("vndr ie set error : %d\n", err);
1a873342
HM
3624 }
3625
3626exit:
3627 kfree(iovar_ie_buf);
3628 return err;
3629}
3630
5f4f9f11
AS
3631s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3632{
3633 s32 pktflags[] = {
3634 BRCMF_VNDR_IE_PRBREQ_FLAG,
3635 BRCMF_VNDR_IE_PRBRSP_FLAG,
3636 BRCMF_VNDR_IE_BEACON_FLAG
3637 };
3638 int i;
3639
3640 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3641 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3642
3643 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3644 return 0;
3645}
3646
a0f07959
HM
3647static s32
3648brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3649 struct cfg80211_beacon_data *beacon)
3650{
3651 s32 err;
3652
3653 /* Set Beacon IEs to FW */
3654 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3655 beacon->tail, beacon->tail_len);
3656 if (err) {
3657 brcmf_err("Set Beacon IE Failed\n");
3658 return err;
3659 }
3660 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3661
3662 /* Set Probe Response IEs to FW */
3663 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3664 beacon->proberesp_ies,
3665 beacon->proberesp_ies_len);
3666 if (err)
3667 brcmf_err("Set Probe Resp IE Failed\n");
3668 else
3669 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3670
3671 return err;
3672}
3673
1a873342
HM
3674static s32
3675brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3676 struct cfg80211_ap_settings *settings)
3677{
3678 s32 ie_offset;
ac24be6f 3679 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3680 struct brcmf_tlv *ssid_ie;
3681 struct brcmf_ssid_le ssid_le;
1a873342
HM
3682 s32 err = -EPERM;
3683 struct brcmf_tlv *rsn_ie;
3684 struct brcmf_vs_tlv *wpa_ie;
3685 struct brcmf_join_params join_params;
a0f07959
HM
3686 enum nl80211_iftype dev_role;
3687 struct brcmf_fil_bss_enable_le bss_enable;
1a873342 3688
d96b801f
AS
3689 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3690 cfg80211_get_chandef_type(&settings->chandef),
3691 settings->beacon_interval,
3692 settings->dtim_period);
3693 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3694 settings->ssid, settings->ssid_len, settings->auth_type,
3695 settings->inactivity_timeout);
1a873342 3696
426d0a56 3697 dev_role = ifp->vif->wdev.iftype;
1a873342
HM
3698
3699 memset(&ssid_le, 0, sizeof(ssid_le));
3700 if (settings->ssid == NULL || settings->ssid_len == 0) {
3701 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3702 ssid_ie = brcmf_parse_tlvs(
3703 (u8 *)&settings->beacon.head[ie_offset],
3704 settings->beacon.head_len - ie_offset,
3705 WLAN_EID_SSID);
3706 if (!ssid_ie)
3707 return -EINVAL;
3708
3709 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3710 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
d96b801f 3711 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
1a873342
HM
3712 } else {
3713 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3714 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3715 }
3716
f96aa07e 3717 brcmf_set_mpc(ifp, 0);
b3657453 3718 brcmf_configure_arp_offload(ifp, false);
1a873342
HM
3719
3720 /* find the RSN_IE */
3721 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3722 settings->beacon.tail_len, WLAN_EID_RSN);
3723
3724 /* find the WPA_IE */
3725 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3726 settings->beacon.tail_len);
3727
1a873342 3728 if ((wpa_ie != NULL || rsn_ie != NULL)) {
d96b801f 3729 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
1a873342
HM
3730 if (wpa_ie != NULL) {
3731 /* WPA IE */
34778529 3732 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
1a873342
HM
3733 if (err < 0)
3734 goto exit;
1a873342
HM
3735 } else {
3736 /* RSN IE */
3737 err = brcmf_configure_wpaie(ndev,
34778529 3738 (struct brcmf_vs_tlv *)rsn_ie, true);
1a873342
HM
3739 if (err < 0)
3740 goto exit;
1a873342 3741 }
1a873342 3742 } else {
d96b801f 3743 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
1f170110 3744 brcmf_configure_opensecurity(ifp);
1a873342 3745 }
1a873342 3746
a0f07959 3747 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
1a873342
HM
3748
3749 if (settings->beacon_interval) {
ac24be6f 3750 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 3751 settings->beacon_interval);
1a873342 3752 if (err < 0) {
57d6e91a 3753 brcmf_err("Beacon Interval Set Error, %d\n", err);
1a873342
HM
3754 goto exit;
3755 }
3756 }
3757 if (settings->dtim_period) {
ac24be6f 3758 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 3759 settings->dtim_period);
1a873342 3760 if (err < 0) {
57d6e91a 3761 brcmf_err("DTIM Interval Set Error, %d\n", err);
1a873342
HM
3762 goto exit;
3763 }
3764 }
a0f07959
HM
3765
3766 if (dev_role == NL80211_IFTYPE_AP) {
3767 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3768 if (err < 0) {
3769 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3770 goto exit;
3771 }
2880b868 3772 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
1a873342
HM
3773 }
3774
a0f07959 3775 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342 3776 if (err < 0) {
a0f07959 3777 brcmf_err("SET INFRA error %d\n", err);
1a873342
HM
3778 goto exit;
3779 }
a0f07959
HM
3780 if (dev_role == NL80211_IFTYPE_AP) {
3781 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3782 if (err < 0) {
3783 brcmf_err("setting AP mode failed %d\n", err);
3784 goto exit;
3785 }
3786 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3787 if (err < 0) {
3788 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3789 goto exit;
3790 }
3791
3792 memset(&join_params, 0, sizeof(join_params));
3793 /* join parameters starts with ssid */
3794 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3795 /* create softap */
3796 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3797 &join_params, sizeof(join_params));
3798 if (err < 0) {
3799 brcmf_err("SET SSID error (%d)\n", err);
3800 goto exit;
3801 }
3802 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3803 } else {
3804 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3805 sizeof(ssid_le));
3806 if (err < 0) {
3807 brcmf_err("setting ssid failed %d\n", err);
3808 goto exit;
3809 }
3810 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3811 bss_enable.enable = cpu_to_le32(1);
3812 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3813 sizeof(bss_enable));
3814 if (err < 0) {
3815 brcmf_err("bss_enable config failed %d\n", err);
3816 goto exit;
3817 }
3818
3819 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3820 }
c1179033
AS
3821 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3822 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
3823
3824exit:
b3657453 3825 if (err) {
f96aa07e 3826 brcmf_set_mpc(ifp, 1);
b3657453
HM
3827 brcmf_configure_arp_offload(ifp, true);
3828 }
1a873342
HM
3829 return err;
3830}
3831
3832static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3833{
c1179033 3834 struct brcmf_if *ifp = netdev_priv(ndev);
5c33a942 3835 s32 err;
426d0a56 3836 struct brcmf_fil_bss_enable_le bss_enable;
5c33a942 3837 struct brcmf_join_params join_params;
1a873342 3838
d96b801f 3839 brcmf_dbg(TRACE, "Enter\n");
1a873342 3840
426d0a56 3841 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
1a873342
HM
3842 /* Due to most likely deauths outstanding we sleep */
3843 /* first to make sure they get processed by fw. */
3844 msleep(400);
5c33a942
HM
3845
3846 memset(&join_params, 0, sizeof(join_params));
3847 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3848 &join_params, sizeof(join_params));
3849 if (err < 0)
3850 brcmf_err("SET SSID error (%d)\n", err);
128ce3b6 3851 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5c33a942 3852 if (err < 0)
57d6e91a 3853 brcmf_err("BRCMF_C_UP error %d\n", err);
5c33a942
HM
3854 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3855 if (err < 0)
3856 brcmf_err("setting AP mode failed %d\n", err);
3857 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3858 if (err < 0)
3859 brcmf_err("setting INFRA mode failed %d\n", err);
426d0a56
HM
3860 } else {
3861 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3862 bss_enable.enable = cpu_to_le32(0);
3863 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3864 sizeof(bss_enable));
3865 if (err < 0)
3866 brcmf_err("bss_enable config failed %d\n", err);
1a873342 3867 }
f96aa07e 3868 brcmf_set_mpc(ifp, 1);
b3657453 3869 brcmf_configure_arp_offload(ifp, true);
426d0a56
HM
3870 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3871 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3872
1a873342
HM
3873 return err;
3874}
3875
a0f07959
HM
3876static s32
3877brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3878 struct cfg80211_beacon_data *info)
3879{
a0f07959
HM
3880 struct brcmf_if *ifp = netdev_priv(ndev);
3881 s32 err;
3882
3883 brcmf_dbg(TRACE, "Enter\n");
3884
a0f07959
HM
3885 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3886
3887 return err;
3888}
3889
1a873342
HM
3890static int
3891brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3892 u8 *mac)
3893{
a0f07959 3894 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342 3895 struct brcmf_scb_val_le scbval;
0abb5f21 3896 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3897 s32 err;
3898
3899 if (!mac)
3900 return -EFAULT;
3901
d96b801f 3902 brcmf_dbg(TRACE, "Enter %pM\n", mac);
1a873342 3903
a0f07959
HM
3904 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3905 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ce81e317 3906 if (!check_vif_up(ifp->vif))
1a873342
HM
3907 return -EIO;
3908
3909 memcpy(&scbval.ea, mac, ETH_ALEN);
3910 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 3911 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 3912 &scbval, sizeof(scbval));
1a873342 3913 if (err)
57d6e91a 3914 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
7ab6acd0 3915
d96b801f 3916 brcmf_dbg(TRACE, "Exit\n");
1a873342
HM
3917 return err;
3918}
3919
0de8aace
HM
3920
3921static void
3922brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3923 struct wireless_dev *wdev,
3924 u16 frame_type, bool reg)
3925{
7fa2e352 3926 struct brcmf_cfg80211_vif *vif;
0de8aace
HM
3927 u16 mgmt_type;
3928
3929 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3930
3931 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
7fa2e352 3932 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
0de8aace
HM
3933 if (reg)
3934 vif->mgmt_rx_reg |= BIT(mgmt_type);
3935 else
318a64ce 3936 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
0de8aace
HM
3937}
3938
3939
3940static int
3941brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3942 struct ieee80211_channel *chan, bool offchan,
3943 unsigned int wait, const u8 *buf, size_t len,
3944 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3945{
3946 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3947 const struct ieee80211_mgmt *mgmt;
3948 struct brcmf_cfg80211_vif *vif;
3949 s32 err = 0;
3950 s32 ie_offset;
3951 s32 ie_len;
18e2f61d
HM
3952 struct brcmf_fil_action_frame_le *action_frame;
3953 struct brcmf_fil_af_params_le *af_params;
3954 bool ack;
3955 s32 chan_nr;
0de8aace
HM
3956
3957 brcmf_dbg(TRACE, "Enter\n");
3958
3959 *cookie = 0;
3960
3961 mgmt = (const struct ieee80211_mgmt *)buf;
3962
a0f07959
HM
3963 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
3964 brcmf_err("Driver only allows MGMT packet type\n");
3965 return -EPERM;
3966 }
0de8aace 3967
a0f07959
HM
3968 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3969 /* Right now the only reason to get a probe response */
3970 /* is for p2p listen response or for p2p GO from */
3971 /* wpa_supplicant. Unfortunately the probe is send */
3972 /* on primary ndev, while dongle wants it on the p2p */
3973 /* vif. Since this is only reason for a probe */
3974 /* response to be sent, the vif is taken from cfg. */
3975 /* If ever desired to send proberesp for non p2p */
3976 /* response then data should be checked for */
3977 /* "DIRECT-". Note in future supplicant will take */
3978 /* dedicated p2p wdev to do this and then this 'hack'*/
3979 /* is not needed anymore. */
3980 ie_offset = DOT11_MGMT_HDR_LEN +
3981 DOT11_BCN_PRB_FIXED_LEN;
3982 ie_len = len - ie_offset;
7fa2e352 3983 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
a0f07959 3984 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
0de8aace 3985 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
a0f07959
HM
3986 err = brcmf_vif_set_mgmt_ie(vif,
3987 BRCMF_VNDR_IE_PRBRSP_FLAG,
3988 &buf[ie_offset],
3989 ie_len);
3990 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3991 GFP_KERNEL);
18e2f61d
HM
3992 } else if (ieee80211_is_action(mgmt->frame_control)) {
3993 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
3994 if (af_params == NULL) {
3995 brcmf_err("unable to allocate frame\n");
3996 err = -ENOMEM;
3997 goto exit;
3998 }
3999 action_frame = &af_params->action_frame;
4000 /* Add the packet Id */
4001 action_frame->packet_id = cpu_to_le32(*cookie);
4002 /* Add BSSID */
4003 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4004 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4005 /* Add the length exepted for 802.11 header */
4006 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
4007 /* Add the channel */
4008 chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
4009 af_params->channel = cpu_to_le32(chan_nr);
4010
4011 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4012 le16_to_cpu(action_frame->len));
4013
4014 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
4015 *cookie, le16_to_cpu(action_frame->len),
4016 chan->center_freq);
4017
7fa2e352 4018 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
18e2f61d
HM
4019 af_params);
4020
4021 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4022 GFP_KERNEL);
4023 kfree(af_params);
a0f07959
HM
4024 } else {
4025 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4026 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
0de8aace 4027 }
a0f07959 4028
18e2f61d 4029exit:
0de8aace
HM
4030 return err;
4031}
4032
4033
4034static int
4035brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4036 struct wireless_dev *wdev,
4037 u64 cookie)
4038{
4039 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4040 struct brcmf_cfg80211_vif *vif;
4041 int err = 0;
4042
4043 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4044
4045 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4046 if (vif == NULL) {
4047 brcmf_err("No p2p device available for probe response\n");
4048 err = -ENODEV;
4049 goto exit;
4050 }
4051 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4052exit:
4053 return err;
4054}
4055
61730d4d
PH
4056static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4057 struct wireless_dev *wdev,
4058 enum nl80211_crit_proto_id proto,
4059 u16 duration)
4060{
4061 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4062 struct brcmf_cfg80211_vif *vif;
4063
4064 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4065
4066 /* only DHCP support for now */
4067 if (proto != NL80211_CRIT_PROTO_DHCP)
4068 return -EINVAL;
4069
4070 /* suppress and abort scanning */
4071 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4072 brcmf_abort_scanning(cfg);
4073
4074 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4075}
4076
4077static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4078 struct wireless_dev *wdev)
4079{
4080 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4081 struct brcmf_cfg80211_vif *vif;
4082
4083 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4084
4085 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4086 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4087}
4088
5b435de0 4089static struct cfg80211_ops wl_cfg80211_ops = {
9f440b7b
AS
4090 .add_virtual_intf = brcmf_cfg80211_add_iface,
4091 .del_virtual_intf = brcmf_cfg80211_del_iface,
5b435de0
AS
4092 .change_virtual_intf = brcmf_cfg80211_change_iface,
4093 .scan = brcmf_cfg80211_scan,
4094 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4095 .join_ibss = brcmf_cfg80211_join_ibss,
4096 .leave_ibss = brcmf_cfg80211_leave_ibss,
4097 .get_station = brcmf_cfg80211_get_station,
4098 .set_tx_power = brcmf_cfg80211_set_tx_power,
4099 .get_tx_power = brcmf_cfg80211_get_tx_power,
4100 .add_key = brcmf_cfg80211_add_key,
4101 .del_key = brcmf_cfg80211_del_key,
4102 .get_key = brcmf_cfg80211_get_key,
4103 .set_default_key = brcmf_cfg80211_config_default_key,
4104 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4105 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
5b435de0
AS
4106 .connect = brcmf_cfg80211_connect,
4107 .disconnect = brcmf_cfg80211_disconnect,
4108 .suspend = brcmf_cfg80211_suspend,
4109 .resume = brcmf_cfg80211_resume,
4110 .set_pmksa = brcmf_cfg80211_set_pmksa,
4111 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4112 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4113 .start_ap = brcmf_cfg80211_start_ap,
4114 .stop_ap = brcmf_cfg80211_stop_ap,
a0f07959 4115 .change_beacon = brcmf_cfg80211_change_beacon,
1a873342 4116 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
4117 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4118 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
0de8aace
HM
4119 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4120 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4121 .remain_on_channel = brcmf_p2p_remain_on_channel,
4122 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
27f10e38
AS
4123 .start_p2p_device = brcmf_p2p_start_device,
4124 .stop_p2p_device = brcmf_p2p_stop_device,
61730d4d
PH
4125 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4126 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
cbaa177d
AS
4127#ifdef CONFIG_NL80211_TESTMODE
4128 .testmode_cmd = brcmf_cfg80211_testmode
4129#endif
5b435de0
AS
4130};
4131
9f440b7b 4132static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
5b435de0 4133{
9f440b7b
AS
4134 switch (type) {
4135 case NL80211_IFTYPE_AP_VLAN:
4136 case NL80211_IFTYPE_WDS:
4137 case NL80211_IFTYPE_MONITOR:
4138 case NL80211_IFTYPE_MESH_POINT:
4139 return -ENOTSUPP;
4140 case NL80211_IFTYPE_ADHOC:
4141 return WL_MODE_IBSS;
4142 case NL80211_IFTYPE_STATION:
4143 case NL80211_IFTYPE_P2P_CLIENT:
4144 return WL_MODE_BSS;
4145 case NL80211_IFTYPE_AP:
4146 case NL80211_IFTYPE_P2P_GO:
4147 return WL_MODE_AP;
4148 case NL80211_IFTYPE_P2P_DEVICE:
4149 return WL_MODE_P2P;
4150 case NL80211_IFTYPE_UNSPECIFIED:
5b435de0 4151 default:
9f440b7b 4152 break;
5b435de0
AS
4153 }
4154
9f440b7b 4155 return -EINVAL;
5b435de0
AS
4156}
4157
e5806072
AS
4158static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4159{
e5806072
AS
4160 /* scheduled scan settings */
4161 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4162 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4163 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4164 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
e5806072
AS
4165}
4166
9f440b7b
AS
4167static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4168 {
dded3d53 4169 .max = 2,
9f440b7b
AS
4170 .types = BIT(NL80211_IFTYPE_STATION) |
4171 BIT(NL80211_IFTYPE_ADHOC) |
4172 BIT(NL80211_IFTYPE_AP)
4173 },
4174 {
4175 .max = 1,
4176 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4177 BIT(NL80211_IFTYPE_P2P_GO)
4178 },
9af221b3
AS
4179 {
4180 .max = 1,
4181 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4182 }
9f440b7b
AS
4183};
4184static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4185 {
dded3d53 4186 .max_interfaces = BRCMF_IFACE_MAX_CNT,
9f440b7b
AS
4187 .num_different_channels = 1, /* no multi-channel for now */
4188 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4189 .limits = brcmf_iface_limits
4190 }
4191};
4192
0de8aace
HM
4193static const struct ieee80211_txrx_stypes
4194brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4195 [NL80211_IFTYPE_STATION] = {
4196 .tx = 0xffff,
4197 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4198 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4199 },
4200 [NL80211_IFTYPE_P2P_CLIENT] = {
4201 .tx = 0xffff,
4202 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4203 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4204 },
4205 [NL80211_IFTYPE_P2P_GO] = {
4206 .tx = 0xffff,
4207 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4208 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4209 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4210 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4211 BIT(IEEE80211_STYPE_AUTH >> 4) |
4212 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4213 BIT(IEEE80211_STYPE_ACTION >> 4)
bffc61c9
AS
4214 },
4215 [NL80211_IFTYPE_P2P_DEVICE] = {
4216 .tx = 0xffff,
4217 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4218 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
0de8aace
HM
4219 }
4220};
4221
3eacf866 4222static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 4223{
3eacf866 4224 struct wiphy *wiphy;
5b435de0
AS
4225 s32 err = 0;
4226
3eacf866
AS
4227 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4228 if (!wiphy) {
57d6e91a 4229 brcmf_err("Could not allocate wiphy device\n");
3eacf866
AS
4230 return ERR_PTR(-ENOMEM);
4231 }
4232 set_wiphy_dev(wiphy, phydev);
4233 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
9f440b7b 4234 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3eacf866
AS
4235 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4236 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4237 BIT(NL80211_IFTYPE_ADHOC) |
9f440b7b
AS
4238 BIT(NL80211_IFTYPE_AP) |
4239 BIT(NL80211_IFTYPE_P2P_CLIENT) |
9af221b3
AS
4240 BIT(NL80211_IFTYPE_P2P_GO) |
4241 BIT(NL80211_IFTYPE_P2P_DEVICE);
9f440b7b
AS
4242 wiphy->iface_combinations = brcmf_iface_combos;
4243 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
3eacf866 4244 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3eacf866
AS
4245 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4246 wiphy->cipher_suites = __wl_cipher_suites;
4247 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
0de8aace 4248 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6eda4e2c 4249 WIPHY_FLAG_OFFCHAN_TX |
0de8aace
HM
4250 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
4251 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4252 wiphy->max_remain_on_channel_duration = 5000;
3eacf866 4253 brcmf_wiphy_pno_params(wiphy);
d48200ba
HM
4254 brcmf_dbg(INFO, "Registering custom regulatory\n");
4255 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
4256 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
3eacf866 4257 err = wiphy_register(wiphy);
5b435de0 4258 if (err < 0) {
57d6e91a 4259 brcmf_err("Could not register wiphy device (%d)\n", err);
3eacf866
AS
4260 wiphy_free(wiphy);
4261 return ERR_PTR(err);
5b435de0 4262 }
3eacf866
AS
4263 return wiphy;
4264}
4265
3eacf866 4266struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
9f440b7b
AS
4267 enum nl80211_iftype type,
4268 bool pm_block)
3eacf866
AS
4269{
4270 struct brcmf_cfg80211_vif *vif;
5b435de0 4271
3eacf866
AS
4272 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4273 return ERR_PTR(-ENOSPC);
5b435de0 4274
33a6b157 4275 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
9f440b7b 4276 sizeof(*vif));
3eacf866
AS
4277 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4278 if (!vif)
4279 return ERR_PTR(-ENOMEM);
4280
4281 vif->wdev.wiphy = cfg->wiphy;
9f440b7b 4282 vif->wdev.iftype = type;
5b435de0 4283
9f440b7b 4284 vif->mode = brcmf_nl80211_iftype_to_mode(type);
3eacf866
AS
4285 vif->pm_block = pm_block;
4286 vif->roam_off = -1;
4287
6ac4f4ed
AS
4288 brcmf_init_prof(&vif->profile);
4289
3eacf866
AS
4290 list_add_tail(&vif->list, &cfg->vif_list);
4291 cfg->vif_cnt++;
4292 return vif;
5b435de0
AS
4293}
4294
24e28bee
AS
4295void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
4296 struct brcmf_cfg80211_vif *vif)
5b435de0 4297{
3eacf866
AS
4298 list_del(&vif->list);
4299 cfg->vif_cnt--;
4300
4301 kfree(vif);
4302 if (!cfg->vif_cnt) {
24e28bee
AS
4303 wiphy_unregister(cfg->wiphy);
4304 wiphy_free(cfg->wiphy);
5b435de0 4305 }
5b435de0
AS
4306}
4307
903e0eee 4308static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
5b435de0 4309{
5c36b99a
AS
4310 u32 event = e->event_code;
4311 u32 status = e->status;
5b435de0
AS
4312
4313 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
16886735 4314 brcmf_dbg(CONN, "Processing set ssid\n");
5b435de0
AS
4315 return true;
4316 }
4317
4318 return false;
4319}
4320
903e0eee 4321static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
5b435de0 4322{
5c36b99a
AS
4323 u32 event = e->event_code;
4324 u16 flags = e->flags;
5b435de0
AS
4325
4326 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
16886735 4327 brcmf_dbg(CONN, "Processing link down\n");
5b435de0
AS
4328 return true;
4329 }
4330 return false;
4331}
4332
27a68fe3 4333static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4334 const struct brcmf_event_msg *e)
4335{
5c36b99a
AS
4336 u32 event = e->event_code;
4337 u32 status = e->status;
5b435de0
AS
4338
4339 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
16886735
AS
4340 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4341 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
4342 return true;
4343 }
4344
4345 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
16886735 4346 brcmf_dbg(CONN, "Processing connecting & no network found\n");
5b435de0
AS
4347 return true;
4348 }
4349
4350 return false;
4351}
4352
27a68fe3 4353static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4354{
27a68fe3 4355 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4356
4357 kfree(conn_info->req_ie);
4358 conn_info->req_ie = NULL;
4359 conn_info->req_ie_len = 0;
4360 kfree(conn_info->resp_ie);
4361 conn_info->resp_ie = NULL;
4362 conn_info->resp_ie_len = 0;
4363}
4364
89286dc9
HM
4365static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4366 struct brcmf_if *ifp)
5b435de0 4367{
c4e382d2 4368 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4369 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4370 u32 req_len;
4371 u32 resp_len;
4372 s32 err = 0;
4373
27a68fe3 4374 brcmf_clear_assoc_ies(cfg);
5b435de0 4375
ac24be6f
AS
4376 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4377 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0 4378 if (err) {
57d6e91a 4379 brcmf_err("could not get assoc info (%d)\n", err);
5b435de0
AS
4380 return err;
4381 }
c4e382d2 4382 assoc_info =
27a68fe3 4383 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4384 req_len = le32_to_cpu(assoc_info->req_len);
4385 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4386 if (req_len) {
ac24be6f 4387 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4388 cfg->extra_buf,
4389 WL_ASSOC_INFO_MAX);
5b435de0 4390 if (err) {
57d6e91a 4391 brcmf_err("could not get assoc req (%d)\n", err);
5b435de0
AS
4392 return err;
4393 }
4394 conn_info->req_ie_len = req_len;
4395 conn_info->req_ie =
27a68fe3 4396 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4397 GFP_KERNEL);
4398 } else {
4399 conn_info->req_ie_len = 0;
4400 conn_info->req_ie = NULL;
4401 }
4402 if (resp_len) {
ac24be6f 4403 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4404 cfg->extra_buf,
4405 WL_ASSOC_INFO_MAX);
5b435de0 4406 if (err) {
57d6e91a 4407 brcmf_err("could not get assoc resp (%d)\n", err);
5b435de0
AS
4408 return err;
4409 }
4410 conn_info->resp_ie_len = resp_len;
4411 conn_info->resp_ie =
27a68fe3 4412 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4413 GFP_KERNEL);
4414 } else {
4415 conn_info->resp_ie_len = 0;
4416 conn_info->resp_ie = NULL;
4417 }
16886735
AS
4418 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4419 conn_info->req_ie_len, conn_info->resp_ie_len);
5b435de0
AS
4420
4421 return err;
4422}
4423
4424static s32
27a68fe3 4425brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4426 struct net_device *ndev,
4427 const struct brcmf_event_msg *e)
4428{
c1179033
AS
4429 struct brcmf_if *ifp = netdev_priv(ndev);
4430 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4431 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4432 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4433 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4434 struct ieee80211_supported_band *band;
a180b83b 4435 struct brcmf_bss_info_le *bi;
83cf17aa 4436 struct brcmu_chan ch;
5b435de0
AS
4437 u32 freq;
4438 s32 err = 0;
a180b83b 4439 u8 *buf;
5b435de0 4440
d96b801f 4441 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4442
89286dc9 4443 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4444 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9 4445 brcmf_update_bss_info(cfg, ifp);
5b435de0 4446
a180b83b
FL
4447 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4448 if (buf == NULL) {
4449 err = -ENOMEM;
4450 goto done;
4451 }
4452
4453 /* data sent to dongle has to be little endian */
4454 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4455 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4456 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4457
4458 if (err)
4459 goto done;
5b435de0 4460
a180b83b 4461 bi = (struct brcmf_bss_info_le *)(buf + 4);
83cf17aa
FL
4462 ch.chspec = le16_to_cpu(bi->chanspec);
4463 cfg->d11inf.decchspec(&ch);
5b435de0 4464
83cf17aa 4465 if (ch.band == BRCMU_CHAN_BAND_2G)
5b435de0
AS
4466 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4467 else
4468 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4469
83cf17aa 4470 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
5b435de0
AS
4471 notify_channel = ieee80211_get_channel(wiphy, freq);
4472
a180b83b
FL
4473done:
4474 kfree(buf);
06bb123e 4475 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4476 conn_info->req_ie, conn_info->req_ie_len,
4477 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16886735 4478 brcmf_dbg(CONN, "Report roaming result\n");
5b435de0 4479
c1179033 4480 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
d96b801f 4481 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4482 return err;
4483}
4484
4485static s32
27a68fe3 4486brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4487 struct net_device *ndev, const struct brcmf_event_msg *e,
4488 bool completed)
4489{
c1179033
AS
4490 struct brcmf_if *ifp = netdev_priv(ndev);
4491 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4492 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4493 s32 err = 0;
4494
d96b801f 4495 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4496
c1179033
AS
4497 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4498 &ifp->vif->sme_state)) {
5b435de0 4499 if (completed) {
89286dc9 4500 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4501 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9
HM
4502 brcmf_update_bss_info(cfg, ifp);
4503 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4504 &ifp->vif->sme_state);
5b435de0
AS
4505 }
4506 cfg80211_connect_result(ndev,
06bb123e 4507 (u8 *)profile->bssid,
5b435de0
AS
4508 conn_info->req_ie,
4509 conn_info->req_ie_len,
4510 conn_info->resp_ie,
4511 conn_info->resp_ie_len,
4512 completed ? WLAN_STATUS_SUCCESS :
4513 WLAN_STATUS_AUTH_TIMEOUT,
4514 GFP_KERNEL);
16886735
AS
4515 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4516 completed ? "succeeded" : "failed");
5b435de0 4517 }
d96b801f 4518 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4519 return err;
4520}
4521
4522static s32
27a68fe3 4523brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4524 struct net_device *ndev,
4525 const struct brcmf_event_msg *e, void *data)
4526{
7ee29602 4527 static int generation;
5c36b99a
AS
4528 u32 event = e->event_code;
4529 u32 reason = e->reason;
1a873342
HM
4530 struct station_info sinfo;
4531
16886735 4532 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
5f4f9f11
AS
4533 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4534 ndev != cfg_to_ndev(cfg)) {
4535 brcmf_dbg(CONN, "AP mode link down\n");
4536 complete(&cfg->vif_disabled);
4537 return 0;
4538 }
1a873342 4539
1a873342 4540 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
7ee29602
HM
4541 (reason == BRCMF_E_STATUS_SUCCESS)) {
4542 memset(&sinfo, 0, sizeof(sinfo));
1a873342
HM
4543 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4544 if (!data) {
57d6e91a 4545 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
1a873342
HM
4546 return -EINVAL;
4547 }
4548 sinfo.assoc_req_ies = data;
7ee29602 4549 sinfo.assoc_req_ies_len = e->datalen;
1a873342
HM
4550 generation++;
4551 sinfo.generation = generation;
7ee29602 4552 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
1a873342
HM
4553 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4554 (event == BRCMF_E_DEAUTH_IND) ||
4555 (event == BRCMF_E_DEAUTH)) {
7ee29602 4556 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
1a873342 4557 }
7ee29602 4558 return 0;
1a873342
HM
4559}
4560
5b435de0 4561static s32
1993732e 4562brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
4563 const struct brcmf_event_msg *e, void *data)
4564{
1993732e
AS
4565 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4566 struct net_device *ndev = ifp->ndev;
c1179033 4567 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4568 s32 err = 0;
4569
128ce3b6 4570 if (ifp->vif->mode == WL_MODE_AP) {
27a68fe3 4571 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
903e0eee 4572 } else if (brcmf_is_linkup(e)) {
16886735 4573 brcmf_dbg(CONN, "Linkup\n");
128ce3b6 4574 if (brcmf_is_ibssmode(ifp->vif)) {
6c8c4f72 4575 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4576 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4577 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4578 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4579 &ifp->vif->sme_state);
4580 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4581 &ifp->vif->sme_state);
5b435de0 4582 } else
27a68fe3 4583 brcmf_bss_connect_done(cfg, ndev, e, true);
903e0eee 4584 } else if (brcmf_is_linkdown(e)) {
16886735 4585 brcmf_dbg(CONN, "Linkdown\n");
128ce3b6 4586 if (!brcmf_is_ibssmode(ifp->vif)) {
27a68fe3 4587 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033 4588 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
903e0eee 4589 &ifp->vif->sme_state))
5b435de0 4590 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4591 GFP_KERNEL);
5b435de0 4592 }
903e0eee 4593 brcmf_link_down(ifp->vif);
6ac4f4ed 4594 brcmf_init_prof(ndev_to_prof(ndev));
5f4f9f11
AS
4595 if (ndev != cfg_to_ndev(cfg))
4596 complete(&cfg->vif_disabled);
27a68fe3 4597 } else if (brcmf_is_nonetwork(cfg, e)) {
128ce3b6 4598 if (brcmf_is_ibssmode(ifp->vif))
c1179033
AS
4599 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4600 &ifp->vif->sme_state);
5b435de0 4601 else
27a68fe3 4602 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4603 }
4604
4605 return err;
4606}
4607
4608static s32
1993732e 4609brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
4610 const struct brcmf_event_msg *e, void *data)
4611{
1993732e 4612 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0 4613 s32 err = 0;
5c36b99a
AS
4614 u32 event = e->event_code;
4615 u32 status = e->status;
5b435de0
AS
4616
4617 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4618 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 4619 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 4620 else
1993732e 4621 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
4622 }
4623
4624 return err;
4625}
4626
4627static s32
1993732e 4628brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
4629 const struct brcmf_event_msg *e, void *data)
4630{
5c36b99a 4631 u16 flags = e->flags;
5b435de0
AS
4632 enum nl80211_key_type key_type;
4633
4634 if (flags & BRCMF_EVENT_MSG_GROUP)
4635 key_type = NL80211_KEYTYPE_GROUP;
4636 else
4637 key_type = NL80211_KEYTYPE_PAIRWISE;
4638
1993732e 4639 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
4640 NULL, GFP_KERNEL);
4641
4642 return 0;
4643}
4644
d3c0b633
AS
4645static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4646 const struct brcmf_event_msg *e, void *data)
4647{
4648 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4649 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4650 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4651 struct brcmf_cfg80211_vif *vif;
4652
4653 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4654 ifevent->action, ifevent->flags, ifevent->ifidx,
4655 ifevent->bssidx);
4656
d3c0b633
AS
4657 mutex_lock(&event->vif_event_lock);
4658 event->action = ifevent->action;
4659 vif = event->vif;
4660
4661 switch (ifevent->action) {
4662 case BRCMF_E_IF_ADD:
4663 /* waiting process may have timed out */
dc4a787c
WY
4664 if (!cfg->vif_event.vif) {
4665 mutex_unlock(&event->vif_event_lock);
d3c0b633 4666 return -EBADF;
dc4a787c 4667 }
d3c0b633
AS
4668
4669 ifp->vif = vif;
4670 vif->ifp = ifp;
01b8e7db
AS
4671 if (ifp->ndev) {
4672 vif->wdev.netdev = ifp->ndev;
4673 ifp->ndev->ieee80211_ptr = &vif->wdev;
4674 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4675 }
d3c0b633
AS
4676 mutex_unlock(&event->vif_event_lock);
4677 wake_up(&event->vif_wq);
4b3a89de 4678 return 0;
d3c0b633
AS
4679
4680 case BRCMF_E_IF_DEL:
d3c0b633
AS
4681 mutex_unlock(&event->vif_event_lock);
4682 /* event may not be upon user request */
4683 if (brcmf_cfg80211_vif_event_armed(cfg))
4684 wake_up(&event->vif_wq);
4685 return 0;
4686
7a5c1f64
HM
4687 case BRCMF_E_IF_CHANGE:
4688 mutex_unlock(&event->vif_event_lock);
4689 wake_up(&event->vif_wq);
4690 return 0;
4691
d3c0b633
AS
4692 default:
4693 mutex_unlock(&event->vif_event_lock);
4694 break;
4695 }
4696 return -EINVAL;
4697}
4698
5b435de0
AS
4699static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4700{
5b435de0
AS
4701 conf->frag_threshold = (u32)-1;
4702 conf->rts_threshold = (u32)-1;
4703 conf->retry_short = (u32)-1;
4704 conf->retry_long = (u32)-1;
4705 conf->tx_power = -1;
4706}
4707
5c36b99a 4708static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 4709{
5c36b99a
AS
4710 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4711 brcmf_notify_connect_status);
4712 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4713 brcmf_notify_connect_status);
4714 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4715 brcmf_notify_connect_status);
4716 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4717 brcmf_notify_connect_status);
4718 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4719 brcmf_notify_connect_status);
4720 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4721 brcmf_notify_connect_status);
4722 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4723 brcmf_notify_roaming_status);
4724 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4725 brcmf_notify_mic_status);
4726 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4727 brcmf_notify_connect_status);
4728 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4729 brcmf_notify_sched_scan_results);
d3c0b633
AS
4730 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4731 brcmf_notify_vif_event);
0de8aace 4732 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
6eda4e2c 4733 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
0de8aace
HM
4734 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4735 brcmf_p2p_notify_listen_complete);
e6da3400
HM
4736 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4737 brcmf_p2p_notify_action_frame_rx);
18e2f61d
HM
4738 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4739 brcmf_p2p_notify_action_tx_complete);
6eda4e2c
HM
4740 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4741 brcmf_p2p_notify_action_tx_complete);
5b435de0
AS
4742}
4743
27a68fe3
AS
4744static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4745{
27a68fe3
AS
4746 kfree(cfg->conf);
4747 cfg->conf = NULL;
27a68fe3
AS
4748 kfree(cfg->escan_ioctl_buf);
4749 cfg->escan_ioctl_buf = NULL;
27a68fe3
AS
4750 kfree(cfg->extra_buf);
4751 cfg->extra_buf = NULL;
27a68fe3
AS
4752 kfree(cfg->pmk_list);
4753 cfg->pmk_list = NULL;
27a68fe3
AS
4754}
4755
4756static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4757{
27a68fe3
AS
4758 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4759 if (!cfg->conf)
5b435de0 4760 goto init_priv_mem_out;
27a68fe3
AS
4761 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4762 if (!cfg->escan_ioctl_buf)
e756af5b 4763 goto init_priv_mem_out;
27a68fe3
AS
4764 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4765 if (!cfg->extra_buf)
5b435de0 4766 goto init_priv_mem_out;
27a68fe3
AS
4767 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4768 if (!cfg->pmk_list)
5b435de0
AS
4769 goto init_priv_mem_out;
4770
4771 return 0;
4772
4773init_priv_mem_out:
27a68fe3 4774 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4775
4776 return -ENOMEM;
4777}
4778
27a68fe3 4779static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4780{
4781 s32 err = 0;
4782
27a68fe3
AS
4783 cfg->scan_request = NULL;
4784 cfg->pwr_save = true;
27a68fe3 4785 cfg->roam_on = true; /* roam on & off switch.
5b435de0 4786 we enable roam per default */
27a68fe3 4787 cfg->active_scan = true; /* we do active scan for
5b435de0 4788 specific scan per default */
27a68fe3 4789 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 4790 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4791 if (err)
4792 return err;
5c36b99a 4793 brcmf_register_event_handlers(cfg);
27a68fe3 4794 mutex_init(&cfg->usr_sync);
27a68fe3
AS
4795 brcmf_init_escan(cfg);
4796 brcmf_init_conf(cfg->conf);
5f4f9f11 4797 init_completion(&cfg->vif_disabled);
5b435de0
AS
4798 return err;
4799}
4800
27a68fe3 4801static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4802{
27a68fe3 4803 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
4804 brcmf_abort_scanning(cfg);
4805 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4806}
4807
d3c0b633
AS
4808static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4809{
4810 init_waitqueue_head(&event->vif_wq);
d3c0b633
AS
4811 mutex_init(&event->vif_event_lock);
4812}
4813
d9cb2596
AS
4814struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4815 struct device *busdev)
5b435de0 4816{
1ed9baf0 4817 struct net_device *ndev = drvr->iflist[0]->ndev;
27a68fe3 4818 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4819 struct wiphy *wiphy;
4820 struct brcmf_cfg80211_vif *vif;
4821 struct brcmf_if *ifp;
5b435de0 4822 s32 err = 0;
83cf17aa 4823 s32 io_type;
5b435de0
AS
4824
4825 if (!ndev) {
57d6e91a 4826 brcmf_err("ndev is invalid\n");
5b435de0
AS
4827 return NULL;
4828 }
5b435de0 4829
3eacf866
AS
4830 ifp = netdev_priv(ndev);
4831 wiphy = brcmf_setup_wiphy(busdev);
4832 if (IS_ERR(wiphy))
5b435de0 4833 return NULL;
5b435de0 4834
3eacf866
AS
4835 cfg = wiphy_priv(wiphy);
4836 cfg->wiphy = wiphy;
27a68fe3 4837 cfg->pub = drvr;
d3c0b633 4838 init_vif_event(&cfg->vif_event);
3eacf866
AS
4839 INIT_LIST_HEAD(&cfg->vif_list);
4840
d3c0b633 4841 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
3eacf866
AS
4842 if (IS_ERR(vif)) {
4843 wiphy_free(wiphy);
4844 return NULL;
4845 }
4846
d3c0b633
AS
4847 vif->ifp = ifp;
4848 vif->wdev.netdev = ndev;
4849 ndev->ieee80211_ptr = &vif->wdev;
4850 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4851
27a68fe3 4852 err = wl_init_priv(cfg);
5b435de0 4853 if (err) {
57d6e91a 4854 brcmf_err("Failed to init iwm_priv (%d)\n", err);
5b435de0
AS
4855 goto cfg80211_attach_out;
4856 }
3eacf866 4857 ifp->vif = vif;
2fde59d9
HM
4858
4859 err = brcmf_p2p_attach(cfg);
4860 if (err) {
4861 brcmf_err("P2P initilisation failed (%d)\n", err);
4862 goto cfg80211_p2p_attach_out;
4863 }
61730d4d
PH
4864 err = brcmf_btcoex_attach(cfg);
4865 if (err) {
4866 brcmf_err("BT-coex initialisation failed (%d)\n", err);
4867 brcmf_p2p_detach(&cfg->p2p);
4868 goto cfg80211_p2p_attach_out;
4869 }
2fde59d9 4870
83cf17aa
FL
4871 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
4872 &io_type);
4873 if (err) {
4874 brcmf_err("Failed to get D11 version (%d)\n", err);
4875 goto cfg80211_p2p_attach_out;
4876 }
4877 cfg->d11inf.io_type = (u8)io_type;
4878 brcmu_d11_attach(&cfg->d11inf);
4879
27a68fe3 4880 return cfg;
5b435de0 4881
2fde59d9
HM
4882cfg80211_p2p_attach_out:
4883 wl_deinit_priv(cfg);
4884
5b435de0 4885cfg80211_attach_out:
24e28bee 4886 brcmf_free_vif(cfg, vif);
5b435de0
AS
4887 return NULL;
4888}
4889
27a68fe3 4890void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 4891{
3eacf866
AS
4892 struct brcmf_cfg80211_vif *vif;
4893 struct brcmf_cfg80211_vif *tmp;
4894
27a68fe3 4895 wl_deinit_priv(cfg);
61730d4d 4896 brcmf_btcoex_detach(cfg);
3eacf866 4897 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
24e28bee 4898 brcmf_free_vif(cfg, vif);
3eacf866 4899 }
5b435de0
AS
4900}
4901
5b435de0 4902static s32
40a23296 4903brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
5b435de0 4904{
5b435de0 4905 s32 err = 0;
f588bc0c
AS
4906 __le32 roamtrigger[2];
4907 __le32 roam_delta[2];
5b435de0
AS
4908
4909 /*
4910 * Setup timeout if Beacons are lost and roam is
4911 * off to report link down
4912 */
4913 if (roamvar) {
ac24be6f 4914 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0 4915 if (err) {
57d6e91a 4916 brcmf_err("bcn_timeout error (%d)\n", err);
5b435de0
AS
4917 goto dongle_rom_out;
4918 }
4919 }
4920
4921 /*
4922 * Enable/Disable built-in roaming to allow supplicant
4923 * to take care of roaming
4924 */
647c9ae0 4925 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 4926 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0 4927 if (err) {
57d6e91a 4928 brcmf_err("roam_off error (%d)\n", err);
5b435de0
AS
4929 goto dongle_rom_out;
4930 }
4931
f588bc0c
AS
4932 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4933 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4934 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 4935 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0 4936 if (err) {
57d6e91a 4937 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5b435de0
AS
4938 goto dongle_rom_out;
4939 }
4940
f588bc0c
AS
4941 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4942 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4943 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 4944 (void *)roam_delta, sizeof(roam_delta));
5b435de0 4945 if (err) {
57d6e91a 4946 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
5b435de0
AS
4947 goto dongle_rom_out;
4948 }
4949
4950dongle_rom_out:
4951 return err;
4952}
4953
4954static s32
40a23296 4955brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
c68cdc0f 4956 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0
AS
4957{
4958 s32 err = 0;
4959
ac24be6f 4960 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 4961 scan_assoc_time);
5b435de0
AS
4962 if (err) {
4963 if (err == -EOPNOTSUPP)
647c9ae0 4964 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
5b435de0 4965 else
57d6e91a 4966 brcmf_err("Scan assoc time error (%d)\n", err);
5b435de0
AS
4967 goto dongle_scantime_out;
4968 }
ac24be6f 4969 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 4970 scan_unassoc_time);
5b435de0
AS
4971 if (err) {
4972 if (err == -EOPNOTSUPP)
647c9ae0 4973 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
5b435de0 4974 else
57d6e91a 4975 brcmf_err("Scan unassoc time error (%d)\n", err);
5b435de0
AS
4976 goto dongle_scantime_out;
4977 }
4978
ac24be6f 4979 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 4980 scan_passive_time);
5b435de0
AS
4981 if (err) {
4982 if (err == -EOPNOTSUPP)
647c9ae0 4983 brcmf_dbg(INFO, "Scan passive time is not supported\n");
5b435de0 4984 else
57d6e91a 4985 brcmf_err("Scan passive time error (%d)\n", err);
5b435de0
AS
4986 goto dongle_scantime_out;
4987 }
4988
4989dongle_scantime_out:
4990 return err;
4991}
4992
d48200ba
HM
4993
4994static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
4995{
4996 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
4997 struct ieee80211_channel *band_chan_arr;
4998 struct brcmf_chanspec_list *list;
83cf17aa 4999 struct brcmu_chan ch;
d48200ba
HM
5000 s32 err;
5001 u8 *pbuf;
5002 u32 i, j;
5003 u32 total;
d48200ba
HM
5004 enum ieee80211_band band;
5005 u32 channel;
5006 u32 *n_cnt;
5007 bool ht40_allowed;
5008 u32 index;
5009 u32 ht40_flag;
5010 bool update;
5011 u32 array_size;
5012
5013 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5014
5015 if (pbuf == NULL)
5016 return -ENOMEM;
5017
5018 list = (struct brcmf_chanspec_list *)pbuf;
5019
5020 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5021 BRCMF_DCMD_MEDLEN);
5022 if (err) {
5023 brcmf_err("get chanspecs error (%d)\n", err);
5024 goto exit;
5025 }
5026
5027 __wl_band_2ghz.n_channels = 0;
5028 __wl_band_5ghz_a.n_channels = 0;
5029
5030 total = le32_to_cpu(list->count);
5031 for (i = 0; i < total; i++) {
83cf17aa
FL
5032 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5033 cfg->d11inf.decchspec(&ch);
d48200ba 5034
83cf17aa 5035 if (ch.band == BRCMU_CHAN_BAND_2G) {
d48200ba
HM
5036 band_chan_arr = __wl_2ghz_channels;
5037 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5038 n_cnt = &__wl_band_2ghz.n_channels;
5039 band = IEEE80211_BAND_2GHZ;
5040 ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
83cf17aa 5041 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
d48200ba
HM
5042 band_chan_arr = __wl_5ghz_a_channels;
5043 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
5044 n_cnt = &__wl_band_5ghz_a.n_channels;
5045 band = IEEE80211_BAND_5GHZ;
5046 ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
5047 } else {
83cf17aa 5048 brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
d48200ba
HM
5049 continue;
5050 }
83cf17aa 5051 if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40)
d48200ba
HM
5052 continue;
5053 update = false;
5054 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
83cf17aa 5055 if (band_chan_arr[j].hw_value == ch.chnum) {
d48200ba
HM
5056 update = true;
5057 break;
5058 }
5059 }
5060 if (update)
5061 index = j;
5062 else
5063 index = *n_cnt;
5064 if (index < array_size) {
5065 band_chan_arr[index].center_freq =
83cf17aa
FL
5066 ieee80211_channel_to_frequency(ch.chnum, band);
5067 band_chan_arr[index].hw_value = ch.chnum;
d48200ba 5068
83cf17aa 5069 if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
d48200ba
HM
5070 /* assuming the order is HT20, HT40 Upper,
5071 * HT40 lower from chanspecs
5072 */
5073 ht40_flag = band_chan_arr[index].flags &
5074 IEEE80211_CHAN_NO_HT40;
83cf17aa 5075 if (ch.sb == BRCMU_CHAN_SB_U) {
d48200ba
HM
5076 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5077 band_chan_arr[index].flags &=
5078 ~IEEE80211_CHAN_NO_HT40;
5079 band_chan_arr[index].flags |=
5080 IEEE80211_CHAN_NO_HT40PLUS;
5081 } else {
5082 /* It should be one of
5083 * IEEE80211_CHAN_NO_HT40 or
5084 * IEEE80211_CHAN_NO_HT40PLUS
5085 */
5086 band_chan_arr[index].flags &=
5087 ~IEEE80211_CHAN_NO_HT40;
5088 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5089 band_chan_arr[index].flags |=
5090 IEEE80211_CHAN_NO_HT40MINUS;
5091 }
5092 } else {
5093 band_chan_arr[index].flags =
5094 IEEE80211_CHAN_NO_HT40;
83cf17aa
FL
5095 ch.bw = BRCMU_CHAN_BW_20;
5096 cfg->d11inf.encchspec(&ch);
5097 channel = ch.chspec;
d48200ba
HM
5098 err = brcmf_fil_bsscfg_int_get(ifp,
5099 "per_chan_info",
5100 &channel);
5101 if (!err) {
5102 if (channel & WL_CHAN_RADAR)
5103 band_chan_arr[index].flags |=
5104 (IEEE80211_CHAN_RADAR |
5105 IEEE80211_CHAN_NO_IBSS);
5106 if (channel & WL_CHAN_PASSIVE)
5107 band_chan_arr[index].flags |=
5108 IEEE80211_CHAN_PASSIVE_SCAN;
5109 }
5110 }
5111 if (!update)
5112 (*n_cnt)++;
5113 }
5114 }
5115exit:
5116 kfree(pbuf);
5117 return err;
5118}
5119
5120
5121static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 5122{
ac24be6f 5123 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5124 struct wiphy *wiphy;
5125 s32 phy_list;
d48200ba
HM
5126 u32 band_list[3];
5127 u32 nmode;
5128 u32 bw_cap = 0;
5b435de0 5129 s8 phy;
d48200ba
HM
5130 s32 err;
5131 u32 nband;
5132 s32 i;
5133 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
5134 s32 index;
5b435de0 5135
b87e2c48 5136 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
81f5dcb8 5137 &phy_list, sizeof(phy_list));
5b435de0 5138 if (err) {
d48200ba 5139 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
5b435de0
AS
5140 return err;
5141 }
5142
3ba81376 5143 phy = ((char *)&phy_list)[0];
d48200ba
HM
5144 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5145
5146
5147 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5148 &band_list, sizeof(band_list));
5149 if (err) {
5150 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5151 return err;
5b435de0 5152 }
d48200ba
HM
5153 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5154 band_list[0], band_list[1], band_list[2]);
5155
5156 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5157 if (err) {
5158 brcmf_err("nmode error (%d)\n", err);
5159 } else {
5160 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
5161 if (err)
5162 brcmf_err("mimo_bw_cap error (%d)\n", err);
5163 }
5164 brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
5165
5166 err = brcmf_construct_reginfo(cfg, bw_cap);
5167 if (err) {
5168 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5169 return err;
5170 }
5171
5172 nband = band_list[0];
5173 memset(bands, 0, sizeof(bands));
5174
5175 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
5176 index = -1;
5177 if ((band_list[i] == WLC_BAND_5G) &&
5178 (__wl_band_5ghz_a.n_channels > 0)) {
5179 index = IEEE80211_BAND_5GHZ;
5180 bands[index] = &__wl_band_5ghz_a;
5181 if ((bw_cap == WLC_N_BW_40ALL) ||
5182 (bw_cap == WLC_N_BW_20IN2G_40IN5G))
5183 bands[index]->ht_cap.cap |=
5184 IEEE80211_HT_CAP_SGI_40;
5185 } else if ((band_list[i] == WLC_BAND_2G) &&
5186 (__wl_band_2ghz.n_channels > 0)) {
5187 index = IEEE80211_BAND_2GHZ;
5188 bands[index] = &__wl_band_2ghz;
5189 if (bw_cap == WLC_N_BW_40ALL)
5190 bands[index]->ht_cap.cap |=
5191 IEEE80211_HT_CAP_SGI_40;
5192 }
5193
5194 if ((index >= 0) && nmode) {
5195 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5196 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5197 bands[index]->ht_cap.ht_supported = true;
5198 bands[index]->ht_cap.ampdu_factor =
5199 IEEE80211_HT_MAX_AMPDU_64K;
5200 bands[index]->ht_cap.ampdu_density =
5201 IEEE80211_HT_MPDU_DENSITY_16;
5202 /* An HT shall support all EQM rates for one spatial
5203 * stream
5204 */
5205 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
5206 }
5207 }
5208
5209 wiphy = cfg_to_wiphy(cfg);
5210 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5211 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5212 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
5b435de0
AS
5213
5214 return err;
5215}
5216
d48200ba 5217
27a68fe3 5218static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 5219{
d48200ba 5220 return brcmf_update_wiphybands(cfg);
5b435de0
AS
5221}
5222
27a68fe3 5223static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5224{
5225 struct net_device *ndev;
5226 struct wireless_dev *wdev;
40a23296 5227 struct brcmf_if *ifp;
5b435de0
AS
5228 s32 power_mode;
5229 s32 err = 0;
5230
27a68fe3 5231 if (cfg->dongle_up)
5b435de0
AS
5232 return err;
5233
27a68fe3 5234 ndev = cfg_to_ndev(cfg);
5b435de0 5235 wdev = ndev->ieee80211_ptr;
40a23296
HM
5236 ifp = netdev_priv(ndev);
5237
5238 /* make sure RF is ready for work */
5239 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5b435de0 5240
40a23296
HM
5241 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5242 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5b435de0 5243
27a68fe3 5244 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
40a23296 5245 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5b435de0
AS
5246 if (err)
5247 goto default_conf_out;
647c9ae0
AS
5248 brcmf_dbg(INFO, "power save set to %s\n",
5249 (power_mode ? "enabled" : "disabled"));
5b435de0 5250
40a23296 5251 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
5b435de0
AS
5252 if (err)
5253 goto default_conf_out;
5dd161ff
FL
5254 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5255 NULL, NULL);
40a23296 5256 if (err)
5b435de0 5257 goto default_conf_out;
27a68fe3 5258 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
5259 if (err)
5260 goto default_conf_out;
5261
b3657453
HM
5262 brcmf_configure_arp_offload(ifp, true);
5263
27a68fe3 5264 cfg->dongle_up = true;
40a23296 5265default_conf_out:
5b435de0
AS
5266
5267 return err;
5268
5269}
5270
bdf5ff51 5271static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5b435de0 5272{
c1179033 5273 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5274
bdf5ff51 5275 return brcmf_config_dongle(ifp->drvr->config);
5b435de0
AS
5276}
5277
bdf5ff51 5278static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5b435de0 5279{
bdf5ff51 5280 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
c1179033 5281
5b435de0
AS
5282 /*
5283 * While going down, if associated with AP disassociate
5284 * from AP to save power
5285 */
903e0eee
AS
5286 if (check_vif_up(ifp->vif)) {
5287 brcmf_link_down(ifp->vif);
5b435de0
AS
5288
5289 /* Make sure WPA_Supplicant receives all the event
5290 generated due to DISASSOC call to the fw to keep
5291 the state fw and WPA_Supplicant state consistent
5292 */
5293 brcmf_delay(500);
5294 }
5295
27a68fe3 5296 brcmf_abort_scanning(cfg);
c1179033 5297 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5298
5b435de0
AS
5299 return 0;
5300}
5301
bdf5ff51 5302s32 brcmf_cfg80211_up(struct net_device *ndev)
5b435de0 5303{
bdf5ff51
AS
5304 struct brcmf_if *ifp = netdev_priv(ndev);
5305 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5306 s32 err = 0;
5307
27a68fe3 5308 mutex_lock(&cfg->usr_sync);
bdf5ff51 5309 err = __brcmf_cfg80211_up(ifp);
27a68fe3 5310 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5311
5312 return err;
5313}
5314
bdf5ff51 5315s32 brcmf_cfg80211_down(struct net_device *ndev)
5b435de0 5316{
bdf5ff51
AS
5317 struct brcmf_if *ifp = netdev_priv(ndev);
5318 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5319 s32 err = 0;
5320
27a68fe3 5321 mutex_lock(&cfg->usr_sync);
bdf5ff51 5322 err = __brcmf_cfg80211_down(ifp);
27a68fe3 5323 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5324
5325 return err;
5326}
5327
a7965fbb
AS
5328enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5329{
5330 struct wireless_dev *wdev = &ifp->vif->wdev;
5331
5332 return wdev->iftype;
5333}
5334
9f440b7b
AS
5335u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5336{
5337 struct brcmf_cfg80211_vif *vif;
5338 bool result = 0;
5339
5340 list_for_each_entry(vif, &cfg->vif_list, list) {
5341 if (test_bit(state, &vif->sme_state))
5342 result++;
5343 }
5344 return result;
5345}
d3c0b633
AS
5346
5347static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5348 u8 action)
5349{
5350 u8 evt_action;
5351
5352 mutex_lock(&event->vif_event_lock);
5353 evt_action = event->action;
5354 mutex_unlock(&event->vif_event_lock);
5355 return evt_action == action;
5356}
5357
5358void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5359 struct brcmf_cfg80211_vif *vif)
5360{
5361 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5362
5363 mutex_lock(&event->vif_event_lock);
5364 event->vif = vif;
5365 event->action = 0;
5366 mutex_unlock(&event->vif_event_lock);
5367}
5368
5369bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5370{
5371 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5372 bool armed;
5373
5374 mutex_lock(&event->vif_event_lock);
5375 armed = event->vif != NULL;
5376 mutex_unlock(&event->vif_event_lock);
5377
5378 return armed;
5379}
5380int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5381 u8 action, ulong timeout)
5382{
5383 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5384
5385 return wait_event_timeout(event->vif_wq,
5386 vif_event_equals(event, action), timeout);
5387}
5388
This page took 0.543136 seconds and 5 git commands to generate.