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