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