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