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