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