brcmutil: add new d11 interface support
[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{
992f6068 1847 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 1848 struct brcmf_wsec_key key;
5b435de0 1849 s32 err = 0;
992f6068 1850 u8 keybuf[8];
5b435de0
AS
1851
1852 memset(&key, 0, sizeof(key));
1853 key.index = (u32) key_idx;
1854 /* Instead of bcast for ea address for default wep keys,
1855 driver needs it to be Null */
1856 if (!is_multicast_ether_addr(mac_addr))
1857 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1858 key.len = (u32) params->key_len;
1859 /* check for key index change */
1860 if (key.len == 0) {
1861 /* key delete */
2eaba7e8 1862 err = send_key_to_dongle(ndev, &key);
5b435de0 1863 if (err)
57d6e91a 1864 brcmf_err("key delete error (%d)\n", err);
5b435de0
AS
1865 } else {
1866 if (key.len > sizeof(key.data)) {
57d6e91a 1867 brcmf_err("Invalid key length (%d)\n", key.len);
5b435de0
AS
1868 return -EINVAL;
1869 }
1870
16886735 1871 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
5b435de0
AS
1872 memcpy(key.data, params->key, key.len);
1873
992f6068
HM
1874 if ((ifp->vif->mode != WL_MODE_AP) &&
1875 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1876 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
5b435de0
AS
1877 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1878 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1879 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1880 }
1881
1882 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1883 if (params->seq && params->seq_len == 6) {
1884 /* rx iv */
1885 u8 *ivptr;
1886 ivptr = (u8 *) params->seq;
1887 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1888 (ivptr[3] << 8) | ivptr[2];
1889 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1890 key.iv_initialized = true;
1891 }
1892
1893 switch (params->cipher) {
1894 case WLAN_CIPHER_SUITE_WEP40:
1895 key.algo = CRYPTO_ALGO_WEP1;
16886735 1896 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
1897 break;
1898 case WLAN_CIPHER_SUITE_WEP104:
1899 key.algo = CRYPTO_ALGO_WEP128;
16886735 1900 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
1901 break;
1902 case WLAN_CIPHER_SUITE_TKIP:
1903 key.algo = CRYPTO_ALGO_TKIP;
16886735 1904 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
1905 break;
1906 case WLAN_CIPHER_SUITE_AES_CMAC:
1907 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 1908 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
1909 break;
1910 case WLAN_CIPHER_SUITE_CCMP:
1911 key.algo = CRYPTO_ALGO_AES_CCM;
16886735 1912 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
1913 break;
1914 default:
57d6e91a 1915 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
1916 return -EINVAL;
1917 }
2eaba7e8 1918 err = send_key_to_dongle(ndev, &key);
f09d0c02 1919 if (err)
57d6e91a 1920 brcmf_err("wsec_key error (%d)\n", err);
5b435de0
AS
1921 }
1922 return err;
1923}
1924
1925static s32
1926brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1927 u8 key_idx, bool pairwise, const u8 *mac_addr,
1928 struct key_params *params)
1929{
0abb5f21 1930 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1931 struct brcmf_wsec_key key;
1932 s32 val;
1933 s32 wsec;
1934 s32 err = 0;
1935 u8 keybuf[8];
1936
d96b801f 1937 brcmf_dbg(TRACE, "Enter\n");
16886735 1938 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 1939 if (!check_vif_up(ifp->vif))
5b435de0
AS
1940 return -EIO;
1941
1942 if (mac_addr) {
d96b801f 1943 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
1944 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1945 }
1946 memset(&key, 0, sizeof(key));
1947
1948 key.len = (u32) params->key_len;
1949 key.index = (u32) key_idx;
1950
1951 if (key.len > sizeof(key.data)) {
57d6e91a 1952 brcmf_err("Too long key length (%u)\n", key.len);
5b435de0
AS
1953 err = -EINVAL;
1954 goto done;
1955 }
1956 memcpy(key.data, params->key, key.len);
1957
1958 key.flags = BRCMF_PRIMARY_KEY;
1959 switch (params->cipher) {
1960 case WLAN_CIPHER_SUITE_WEP40:
1961 key.algo = CRYPTO_ALGO_WEP1;
f09d0c02 1962 val = WEP_ENABLED;
16886735 1963 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
1964 break;
1965 case WLAN_CIPHER_SUITE_WEP104:
1966 key.algo = CRYPTO_ALGO_WEP128;
f09d0c02 1967 val = WEP_ENABLED;
16886735 1968 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
1969 break;
1970 case WLAN_CIPHER_SUITE_TKIP:
128ce3b6 1971 if (ifp->vif->mode != WL_MODE_AP) {
992f6068 1972 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
1a873342
HM
1973 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1974 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1975 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1976 }
5b435de0 1977 key.algo = CRYPTO_ALGO_TKIP;
f09d0c02 1978 val = TKIP_ENABLED;
16886735 1979 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
1980 break;
1981 case WLAN_CIPHER_SUITE_AES_CMAC:
1982 key.algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 1983 val = AES_ENABLED;
16886735 1984 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
1985 break;
1986 case WLAN_CIPHER_SUITE_CCMP:
1987 key.algo = CRYPTO_ALGO_AES_CCM;
f09d0c02 1988 val = AES_ENABLED;
16886735 1989 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
5b435de0
AS
1990 break;
1991 default:
57d6e91a 1992 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
5b435de0
AS
1993 err = -EINVAL;
1994 goto done;
1995 }
1996
2eaba7e8 1997 err = send_key_to_dongle(ndev, &key);
5b435de0
AS
1998 if (err)
1999 goto done;
2000
0abb5f21 2001 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2002 if (err) {
57d6e91a 2003 brcmf_err("get wsec error (%d)\n", err);
5b435de0
AS
2004 goto done;
2005 }
5b435de0 2006 wsec |= val;
0abb5f21 2007 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
5b435de0 2008 if (err) {
57d6e91a 2009 brcmf_err("set wsec error (%d)\n", err);
5b435de0
AS
2010 goto done;
2011 }
2012
5b435de0 2013done:
d96b801f 2014 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2015 return err;
2016}
2017
2018static s32
2019brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2020 u8 key_idx, bool pairwise, const u8 *mac_addr)
2021{
0abb5f21 2022 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2023 struct brcmf_wsec_key key;
2024 s32 err = 0;
5b435de0 2025
d96b801f 2026 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2027 if (!check_vif_up(ifp->vif))
5b435de0
AS
2028 return -EIO;
2029
256c374f
HM
2030 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2031 /* we ignore this key index in this case */
57d6e91a 2032 brcmf_err("invalid key index (%d)\n", key_idx);
256c374f
HM
2033 return -EINVAL;
2034 }
2035
5b435de0
AS
2036 memset(&key, 0, sizeof(key));
2037
2038 key.index = (u32) key_idx;
2039 key.flags = BRCMF_PRIMARY_KEY;
2040 key.algo = CRYPTO_ALGO_OFF;
2041
16886735 2042 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
5b435de0
AS
2043
2044 /* Set the new key/index */
2eaba7e8 2045 err = send_key_to_dongle(ndev, &key);
5b435de0 2046
d96b801f 2047 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2048 return err;
2049}
2050
2051static s32
2052brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2053 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2054 void (*callback) (void *cookie, struct key_params * params))
2055{
2056 struct key_params params;
0abb5f21
AS
2057 struct brcmf_if *ifp = netdev_priv(ndev);
2058 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2059 struct brcmf_cfg80211_security *sec;
2060 s32 wsec;
2061 s32 err = 0;
2062
d96b801f 2063 brcmf_dbg(TRACE, "Enter\n");
16886735 2064 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
ce81e317 2065 if (!check_vif_up(ifp->vif))
5b435de0
AS
2066 return -EIO;
2067
2068 memset(&params, 0, sizeof(params));
2069
0abb5f21 2070 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
5b435de0 2071 if (err) {
57d6e91a 2072 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
5b435de0
AS
2073 /* Ignore this error, may happen during DISASSOC */
2074 err = -EAGAIN;
2075 goto done;
2076 }
c5bf53a8 2077 if (wsec & WEP_ENABLED) {
06bb123e 2078 sec = &profile->sec;
5b435de0
AS
2079 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2080 params.cipher = WLAN_CIPHER_SUITE_WEP40;
16886735 2081 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2082 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2083 params.cipher = WLAN_CIPHER_SUITE_WEP104;
16886735 2084 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0 2085 }
c5bf53a8 2086 } else if (wsec & TKIP_ENABLED) {
5b435de0 2087 params.cipher = WLAN_CIPHER_SUITE_TKIP;
16886735 2088 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
c5bf53a8 2089 } else if (wsec & AES_ENABLED) {
5b435de0 2090 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
16886735 2091 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
c5bf53a8 2092 } else {
57d6e91a 2093 brcmf_err("Invalid algo (0x%x)\n", wsec);
5b435de0
AS
2094 err = -EINVAL;
2095 goto done;
2096 }
2097 callback(cookie, &params);
2098
2099done:
d96b801f 2100 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2101 return err;
2102}
2103
2104static s32
2105brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2106 struct net_device *ndev, u8 key_idx)
2107{
647c9ae0 2108 brcmf_dbg(INFO, "Not supported\n");
5b435de0
AS
2109
2110 return -EOPNOTSUPP;
2111}
2112
2113static s32
2114brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
1a873342 2115 u8 *mac, struct station_info *sinfo)
5b435de0 2116{
0abb5f21
AS
2117 struct brcmf_if *ifp = netdev_priv(ndev);
2118 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2119 struct brcmf_scb_val_le scb_val;
2120 int rssi;
2121 s32 rate;
2122 s32 err = 0;
06bb123e 2123 u8 *bssid = profile->bssid;
81f5dcb8 2124 struct brcmf_sta_info_le sta_info_le;
5b435de0 2125
d96b801f 2126 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
ce81e317 2127 if (!check_vif_up(ifp->vif))
5b435de0
AS
2128 return -EIO;
2129
128ce3b6 2130 if (ifp->vif->mode == WL_MODE_AP) {
81f5dcb8 2131 memcpy(&sta_info_le, mac, ETH_ALEN);
0abb5f21 2132 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
ac24be6f 2133 &sta_info_le,
81f5dcb8 2134 sizeof(sta_info_le));
1a873342 2135 if (err < 0) {
57d6e91a 2136 brcmf_err("GET STA INFO failed, %d\n", err);
1a873342
HM
2137 goto done;
2138 }
1a873342 2139 sinfo->filled = STATION_INFO_INACTIVE_TIME;
81f5dcb8
HM
2140 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2141 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
1a873342 2142 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
81f5dcb8 2143 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
1a873342 2144 }
d96b801f
AS
2145 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2146 sinfo->inactive_time, sinfo->connected_time);
128ce3b6 2147 } else if (ifp->vif->mode == WL_MODE_BSS) {
1a873342 2148 if (memcmp(mac, bssid, ETH_ALEN)) {
57d6e91a
AS
2149 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2150 mac, bssid);
1a873342
HM
2151 err = -ENOENT;
2152 goto done;
2153 }
2154 /* Report the current tx rate */
89286dc9 2155 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
7f6c562d 2156 if (err) {
57d6e91a 2157 brcmf_err("Could not get rate (%d)\n", err);
1a873342 2158 goto done;
7f6c562d 2159 } else {
1a873342
HM
2160 sinfo->filled |= STATION_INFO_TX_BITRATE;
2161 sinfo->txrate.legacy = rate * 5;
16886735 2162 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
7f6c562d 2163 }
5b435de0 2164
c1179033
AS
2165 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2166 &ifp->vif->sme_state)) {
1a873342 2167 memset(&scb_val, 0, sizeof(scb_val));
c1179033
AS
2168 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2169 &scb_val, sizeof(scb_val));
1a873342 2170 if (err) {
57d6e91a 2171 brcmf_err("Could not get rssi (%d)\n", err);
1a873342
HM
2172 goto done;
2173 } else {
2174 rssi = le32_to_cpu(scb_val.val);
2175 sinfo->filled |= STATION_INFO_SIGNAL;
2176 sinfo->signal = rssi;
16886735 2177 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
1a873342
HM
2178 }
2179 }
2180 } else
2181 err = -EPERM;
5b435de0 2182done:
d96b801f 2183 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2184 return err;
2185}
2186
2187static s32
2188brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2189 bool enabled, s32 timeout)
2190{
2191 s32 pm;
2192 s32 err = 0;
27a68fe3 2193 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2194 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2195
d96b801f 2196 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2197
2198 /*
2199 * Powersave enable/disable request is coming from the
2200 * cfg80211 even before the interface is up. In that
2201 * scenario, driver will be storing the power save
27a68fe3 2202 * preference in cfg struct to apply this to
5b435de0
AS
2203 * FW later while initializing the dongle
2204 */
27a68fe3 2205 cfg->pwr_save = enabled;
ce81e317 2206 if (!check_vif_up(ifp->vif)) {
5b435de0 2207
647c9ae0 2208 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
5b435de0
AS
2209 goto done;
2210 }
2211
2212 pm = enabled ? PM_FAST : PM_OFF;
647c9ae0 2213 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2214
c1179033 2215 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2216 if (err) {
2217 if (err == -ENODEV)
57d6e91a 2218 brcmf_err("net_device is not ready yet\n");
5b435de0 2219 else
57d6e91a 2220 brcmf_err("error (%d)\n", err);
5b435de0
AS
2221 }
2222done:
d96b801f 2223 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2224 return err;
2225}
2226
27a68fe3 2227static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2228 struct brcmf_bss_info_le *bi)
5b435de0 2229{
27a68fe3 2230 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2231 struct ieee80211_channel *notify_channel;
2232 struct cfg80211_bss *bss;
2233 struct ieee80211_supported_band *band;
2234 s32 err = 0;
2235 u16 channel;
2236 u32 freq;
5b435de0
AS
2237 u16 notify_capability;
2238 u16 notify_interval;
2239 u8 *notify_ie;
2240 size_t notify_ielen;
2241 s32 notify_signal;
2242
2243 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2244 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2245 return 0;
2246 }
2247
2248 channel = bi->ctl_ch ? bi->ctl_ch :
2249 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2250
2251 if (channel <= CH_MAX_2G_CHANNEL)
2252 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2253 else
2254 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2255
2256 freq = ieee80211_channel_to_frequency(channel, band->band);
2257 notify_channel = ieee80211_get_channel(wiphy, freq);
2258
5b435de0
AS
2259 notify_capability = le16_to_cpu(bi->capability);
2260 notify_interval = le16_to_cpu(bi->beacon_period);
2261 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2262 notify_ielen = le32_to_cpu(bi->ie_length);
2263 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2264
16886735
AS
2265 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2266 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2267 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2268 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2269 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0
AS
2270
2271 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
8e6cffb3 2272 0, notify_capability, notify_interval, notify_ie,
5b435de0
AS
2273 notify_ielen, notify_signal, GFP_KERNEL);
2274
e78946e1
FL
2275 if (!bss)
2276 return -ENOMEM;
2277
5b112d3d 2278 cfg80211_put_bss(wiphy, bss);
5b435de0
AS
2279
2280 return err;
2281}
2282
6f09be0a
RV
2283static struct brcmf_bss_info_le *
2284next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2285{
2286 if (bss == NULL)
2287 return list->bss_info_le;
2288 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2289 le32_to_cpu(bss->length));
2290}
2291
27a68fe3 2292static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2293{
2294 struct brcmf_scan_results *bss_list;
d34bf64f 2295 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2296 s32 err = 0;
2297 int i;
2298
27a68fe3 2299 bss_list = cfg->bss_list;
0ecd8164
AS
2300 if (bss_list->count != 0 &&
2301 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2302 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2303 bss_list->version);
5b435de0
AS
2304 return -EOPNOTSUPP;
2305 }
4e8a008e 2306 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2307 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2308 bi = next_bss_le(bss_list, bi);
27a68fe3 2309 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2310 if (err)
2311 break;
2312 }
2313 return err;
2314}
2315
27a68fe3 2316static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2317 struct net_device *ndev, const u8 *bssid)
2318{
27a68fe3 2319 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2320 struct ieee80211_channel *notify_channel;
d34bf64f 2321 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2322 struct ieee80211_supported_band *band;
e78946e1 2323 struct cfg80211_bss *bss;
5b435de0
AS
2324 u8 *buf = NULL;
2325 s32 err = 0;
2326 u16 channel;
2327 u32 freq;
5b435de0
AS
2328 u16 notify_capability;
2329 u16 notify_interval;
2330 u8 *notify_ie;
2331 size_t notify_ielen;
2332 s32 notify_signal;
2333
d96b801f 2334 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2335
2336 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2337 if (buf == NULL) {
2338 err = -ENOMEM;
2339 goto CleanUp;
2340 }
2341
2342 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2343
ac24be6f
AS
2344 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2345 buf, WL_BSS_INFO_MAX);
5b435de0 2346 if (err) {
57d6e91a 2347 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2348 goto CleanUp;
2349 }
2350
d34bf64f 2351 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0
AS
2352
2353 channel = bi->ctl_ch ? bi->ctl_ch :
2354 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2355
2356 if (channel <= CH_MAX_2G_CHANNEL)
2357 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2358 else
2359 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2360
2361 freq = ieee80211_channel_to_frequency(channel, band->band);
2362 notify_channel = ieee80211_get_channel(wiphy, freq);
2363
5b435de0
AS
2364 notify_capability = le16_to_cpu(bi->capability);
2365 notify_interval = le16_to_cpu(bi->beacon_period);
2366 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2367 notify_ielen = le32_to_cpu(bi->ie_length);
2368 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2369
16886735
AS
2370 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2371 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2372 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2373 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2374
e78946e1 2375 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
8e6cffb3 2376 0, notify_capability, notify_interval,
5b435de0
AS
2377 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2378
e78946e1
FL
2379 if (!bss) {
2380 err = -ENOMEM;
2381 goto CleanUp;
2382 }
2383
5b112d3d 2384 cfg80211_put_bss(wiphy, bss);
e78946e1 2385
5b435de0
AS
2386CleanUp:
2387
2388 kfree(buf);
2389
d96b801f 2390 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2391
2392 return err;
2393}
2394
128ce3b6 2395static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
5b435de0 2396{
128ce3b6 2397 return vif->mode == WL_MODE_IBSS;
5b435de0
AS
2398}
2399
89286dc9
HM
2400static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2401 struct brcmf_if *ifp)
1a873342 2402{
89286dc9 2403 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
d34bf64f 2404 struct brcmf_bss_info_le *bi;
5b435de0 2405 struct brcmf_ssid *ssid;
f8e4b412 2406 struct brcmf_tlv *tim;
5b435de0
AS
2407 u16 beacon_interval;
2408 u8 dtim_period;
2409 size_t ie_len;
2410 u8 *ie;
2411 s32 err = 0;
2412
d96b801f 2413 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2414 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2415 return err;
2416
06bb123e 2417 ssid = &profile->ssid;
5b435de0 2418
27a68fe3 2419 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2420 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2421 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2422 if (err) {
57d6e91a 2423 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2424 goto update_bss_info_out;
2425 }
2426
27a68fe3
AS
2427 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2428 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2429 if (err)
2430 goto update_bss_info_out;
2431
2432 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2433 ie_len = le32_to_cpu(bi->ie_length);
2434 beacon_interval = le16_to_cpu(bi->beacon_period);
2435
f8e4b412 2436 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2437 if (tim)
2438 dtim_period = tim->data[1];
2439 else {
2440 /*
2441 * active scan was done so we could not get dtim
2442 * information out of probe response.
2443 * so we speficially query dtim information to dongle.
2444 */
2445 u32 var;
ac24be6f 2446 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2447 if (err) {
57d6e91a 2448 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2449 goto update_bss_info_out;
2450 }
2451 dtim_period = (u8)var;
2452 }
2453
5b435de0 2454update_bss_info_out:
d96b801f 2455 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2456 return err;
2457}
2458
18e2f61d 2459void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2460{
27a68fe3 2461 struct escan_info *escan = &cfg->escan_info;
5b435de0 2462
c1179033 2463 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2464 if (cfg->scan_request) {
108a4bee 2465 escan->escan_state = WL_ESCAN_STATE_IDLE;
a0f472ac 2466 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
5b435de0 2467 }
c1179033
AS
2468 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2469 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2470}
2471
e756af5b
HM
2472static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2473{
27a68fe3
AS
2474 struct brcmf_cfg80211_info *cfg =
2475 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2476 escan_timeout_work);
2477
a0f472ac 2478 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
e756af5b
HM
2479}
2480
2481static void brcmf_escan_timeout(unsigned long data)
2482{
27a68fe3
AS
2483 struct brcmf_cfg80211_info *cfg =
2484 (struct brcmf_cfg80211_info *)data;
e756af5b 2485
27a68fe3 2486 if (cfg->scan_request) {
57d6e91a 2487 brcmf_err("timer expired\n");
f0799895 2488 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2489 }
2490}
2491
2492static s32
2493brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2494 struct brcmf_bss_info_le *bss_info_le)
2495{
2496 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2497 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2498 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2499 bss_info_le->SSID_len == bss->SSID_len &&
2500 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2501 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2502 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2503 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2504 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2505
e756af5b
HM
2506 /* preserve max RSSI if the measurements are
2507 * both on-channel or both off-channel
2508 */
029591f3 2509 if (bss_info_rssi > bss_rssi)
e756af5b
HM
2510 bss->RSSI = bss_info_le->RSSI;
2511 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2512 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2513 /* preserve the on-channel rssi measurement
2514 * if the new measurement is off channel
2515 */
2516 bss->RSSI = bss_info_le->RSSI;
2517 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2518 }
2519 return 1;
2520 }
2521 return 0;
2522}
2523
2524static s32
1993732e 2525brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2526 const struct brcmf_event_msg *e, void *data)
2527{
1993732e 2528 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e756af5b
HM
2529 s32 status;
2530 s32 err = 0;
2531 struct brcmf_escan_result_le *escan_result_le;
2532 struct brcmf_bss_info_le *bss_info_le;
2533 struct brcmf_bss_info_le *bss = NULL;
2534 u32 bi_length;
2535 struct brcmf_scan_results *list;
2536 u32 i;
97ed15c7 2537 bool aborted;
e756af5b 2538
5c36b99a 2539 status = e->status;
e756af5b 2540
a0f472ac
AS
2541 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2542 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
e756af5b
HM
2543 return -EPERM;
2544 }
2545
2546 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2547 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2548 escan_result_le = (struct brcmf_escan_result_le *) data;
2549 if (!escan_result_le) {
57d6e91a 2550 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2551 goto exit;
2552 }
e756af5b 2553 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2554 brcmf_err("Invalid bss_count %d: ignoring\n",
2555 escan_result_le->bss_count);
e756af5b
HM
2556 goto exit;
2557 }
2558 bss_info_le = &escan_result_le->bss_info_le;
2559
6eda4e2c
HM
2560 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2561 goto exit;
2562
2563 if (!cfg->scan_request) {
2564 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2565 goto exit;
2566 }
2567
e756af5b
HM
2568 bi_length = le32_to_cpu(bss_info_le->length);
2569 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2570 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
2571 brcmf_err("Invalid bss_info length %d: ignoring\n",
2572 bi_length);
e756af5b
HM
2573 goto exit;
2574 }
2575
27a68fe3 2576 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2577 BIT(NL80211_IFTYPE_ADHOC))) {
2578 if (le16_to_cpu(bss_info_le->capability) &
2579 WLAN_CAPABILITY_IBSS) {
57d6e91a 2580 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
2581 goto exit;
2582 }
2583 }
2584
2585 list = (struct brcmf_scan_results *)
27a68fe3 2586 cfg->escan_info.escan_buf;
e756af5b 2587 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 2588 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
2589 goto exit;
2590 }
2591
2592 for (i = 0; i < list->count; i++) {
2593 bss = bss ? (struct brcmf_bss_info_le *)
2594 ((unsigned char *)bss +
2595 le32_to_cpu(bss->length)) : list->bss_info_le;
2596 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2597 goto exit;
2598 }
27a68fe3 2599 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2600 bss_info_le, bi_length);
2601 list->version = le32_to_cpu(bss_info_le->version);
2602 list->buflen += bi_length;
2603 list->count++;
2604 } else {
27a68fe3 2605 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
2606 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2607 goto exit;
27a68fe3
AS
2608 if (cfg->scan_request) {
2609 cfg->bss_list = (struct brcmf_scan_results *)
2610 cfg->escan_info.escan_buf;
2611 brcmf_inform_bss(cfg);
97ed15c7 2612 aborted = status != BRCMF_E_STATUS_SUCCESS;
a0f472ac 2613 brcmf_notify_escan_complete(cfg, ifp, aborted,
97ed15c7 2614 false);
e756af5b 2615 } else
6eda4e2c
HM
2616 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2617 status);
e756af5b
HM
2618 }
2619exit:
2620 return err;
2621}
2622
27a68fe3 2623static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 2624{
5c36b99a
AS
2625 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2626 brcmf_cfg80211_escan_handler);
f0799895
HM
2627 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2628 /* Init scan_timeout timer */
2629 init_timer(&cfg->escan_timeout);
2630 cfg->escan_timeout.data = (unsigned long) cfg;
2631 cfg->escan_timeout.function = brcmf_escan_timeout;
2632 INIT_WORK(&cfg->escan_timeout_work,
2633 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2634}
2635
5addc0de 2636static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2637{
2638 if (ms < 1000 / HZ) {
2639 cond_resched();
2640 mdelay(ms);
2641 } else {
2642 msleep(ms);
2643 }
2644}
2645
2646static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2647{
d96b801f 2648 brcmf_dbg(TRACE, "Enter\n");
5b435de0 2649
5b435de0
AS
2650 return 0;
2651}
2652
2653static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2654 struct cfg80211_wowlan *wow)
2655{
27a68fe3
AS
2656 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2657 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 2658 struct brcmf_cfg80211_vif *vif;
5b435de0 2659
d96b801f 2660 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2661
2662 /*
7d641072
AS
2663 * if the primary net_device is not READY there is nothing
2664 * we can do but pray resume goes smoothly.
5b435de0 2665 */
7d641072
AS
2666 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2667 if (!check_vif_up(vif))
2668 goto exit;
5b435de0 2669
7d641072
AS
2670 list_for_each_entry(vif, &cfg->vif_list, list) {
2671 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2672 continue;
5b435de0 2673 /*
7d641072
AS
2674 * While going to suspend if associated with AP disassociate
2675 * from AP to save power while system is in suspended state
5b435de0 2676 */
903e0eee
AS
2677 brcmf_link_down(vif);
2678
2679 /* Make sure WPA_Supplicant receives all the event
2680 * generated due to DISASSOC call to the fw to keep
2681 * the state fw and WPA_Supplicant state consistent
2682 */
2683 brcmf_delay(500);
5b435de0
AS
2684 }
2685
7d641072
AS
2686 /* end any scanning */
2687 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 2688 brcmf_abort_scanning(cfg);
5b435de0
AS
2689
2690 /* Turn off watchdog timer */
f96aa07e 2691 brcmf_set_mpc(netdev_priv(ndev), 1);
5b435de0 2692
7d641072 2693exit:
d96b801f 2694 brcmf_dbg(TRACE, "Exit\n");
7d641072
AS
2695 /* clear any scanning activity */
2696 cfg->scan_status = 0;
5b435de0
AS
2697 return 0;
2698}
2699
5b435de0
AS
2700static __used s32
2701brcmf_update_pmklist(struct net_device *ndev,
2702 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2703{
2704 int i, j;
40c8e95a 2705 int pmkid_len;
5b435de0 2706
40c8e95a
AS
2707 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2708
16886735 2709 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
40c8e95a 2710 for (i = 0; i < pmkid_len; i++) {
16886735
AS
2711 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2712 &pmk_list->pmkids.pmkid[i].BSSID);
5b435de0 2713 for (j = 0; j < WLAN_PMKID_LEN; j++)
16886735
AS
2714 brcmf_dbg(CONN, "%02x\n",
2715 pmk_list->pmkids.pmkid[i].PMKID[j]);
5b435de0
AS
2716 }
2717
2718 if (!err)
ac24be6f
AS
2719 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2720 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
2721
2722 return err;
2723}
2724
2725static s32
2726brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2727 struct cfg80211_pmksa *pmksa)
2728{
27a68fe3 2729 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2730 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2731 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
2732 s32 err = 0;
2733 int i;
40c8e95a 2734 int pmkid_len;
5b435de0 2735
d96b801f 2736 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2737 if (!check_vif_up(ifp->vif))
5b435de0
AS
2738 return -EIO;
2739
40c8e95a
AS
2740 pmkid_len = le32_to_cpu(pmkids->npmkid);
2741 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
2742 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2743 break;
2744 if (i < WL_NUM_PMKIDS_MAX) {
2745 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2746 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
2747 if (i == pmkid_len) {
2748 pmkid_len++;
2749 pmkids->npmkid = cpu_to_le32(pmkid_len);
2750 }
5b435de0
AS
2751 } else
2752 err = -EINVAL;
2753
16886735
AS
2754 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2755 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 2756 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2757 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 2758
27a68fe3 2759 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2760
d96b801f 2761 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2762 return err;
2763}
2764
2765static s32
2766brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2767 struct cfg80211_pmksa *pmksa)
2768{
27a68fe3 2769 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2770 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2771 struct pmkid_list pmkid;
2772 s32 err = 0;
40c8e95a 2773 int i, pmkid_len;
5b435de0 2774
d96b801f 2775 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2776 if (!check_vif_up(ifp->vif))
5b435de0
AS
2777 return -EIO;
2778
2779 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2780 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2781
16886735
AS
2782 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2783 &pmkid.pmkid[0].BSSID);
5b435de0 2784 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2785 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
5b435de0 2786
27a68fe3 2787 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 2788 for (i = 0; i < pmkid_len; i++)
5b435de0 2789 if (!memcmp
27a68fe3 2790 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
2791 ETH_ALEN))
2792 break;
2793
40c8e95a
AS
2794 if ((pmkid_len > 0)
2795 && (i < pmkid_len)) {
27a68fe3 2796 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 2797 sizeof(struct pmkid));
40c8e95a 2798 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
2799 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2800 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 2801 ETH_ALEN);
27a68fe3
AS
2802 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2803 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
2804 WLAN_PMKID_LEN);
2805 }
27a68fe3 2806 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
2807 } else
2808 err = -EINVAL;
2809
27a68fe3 2810 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2811
d96b801f 2812 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2813 return err;
2814
2815}
2816
2817static s32
2818brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2819{
27a68fe3 2820 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2821 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2822 s32 err = 0;
2823
d96b801f 2824 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2825 if (!check_vif_up(ifp->vif))
5b435de0
AS
2826 return -EIO;
2827
27a68fe3
AS
2828 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2829 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2830
d96b801f 2831 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2832 return err;
2833
2834}
2835
e5806072
AS
2836/*
2837 * PFN result doesn't have all the info which are
2838 * required by the supplicant
2839 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2840 * via wl_inform_single_bss in the required format. Escan does require the
2841 * scan request in the form of cfg80211_scan_request. For timebeing, create
2842 * cfg80211_scan_request one out of the received PNO event.
2843 */
2844static s32
1993732e 2845brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
2846 const struct brcmf_event_msg *e, void *data)
2847{
1993732e 2848 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
e5806072
AS
2849 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2850 struct cfg80211_scan_request *request = NULL;
2851 struct cfg80211_ssid *ssid = NULL;
2852 struct ieee80211_channel *channel = NULL;
27a68fe3 2853 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
2854 int err = 0;
2855 int channel_req = 0;
2856 int band = 0;
2857 struct brcmf_pno_scanresults_le *pfn_result;
2858 u32 result_count;
2859 u32 status;
2860
4e8a008e 2861 brcmf_dbg(SCAN, "Enter\n");
e5806072 2862
5c36b99a 2863 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
4e8a008e 2864 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
e5806072
AS
2865 return 0;
2866 }
2867
2868 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2869 result_count = le32_to_cpu(pfn_result->count);
2870 status = le32_to_cpu(pfn_result->status);
2871
2872 /*
2873 * PFN event is limited to fit 512 bytes so we may get
2874 * multiple NET_FOUND events. For now place a warning here.
2875 */
2876 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
4e8a008e 2877 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
e5806072
AS
2878 if (result_count > 0) {
2879 int i;
2880
2881 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
2882 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2883 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
2884 if (!request || !ssid || !channel) {
2885 err = -ENOMEM;
2886 goto out_err;
2887 }
2888
2889 request->wiphy = wiphy;
2890 data += sizeof(struct brcmf_pno_scanresults_le);
2891 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2892
2893 for (i = 0; i < result_count; i++) {
2894 netinfo = &netinfo_start[i];
2895 if (!netinfo) {
57d6e91a
AS
2896 brcmf_err("Invalid netinfo ptr. index: %d\n",
2897 i);
e5806072
AS
2898 err = -EINVAL;
2899 goto out_err;
2900 }
2901
4e8a008e
AS
2902 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2903 netinfo->SSID, netinfo->channel);
e5806072
AS
2904 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2905 ssid[i].ssid_len = netinfo->SSID_len;
2906 request->n_ssids++;
2907
2908 channel_req = netinfo->channel;
2909 if (channel_req <= CH_MAX_2G_CHANNEL)
2910 band = NL80211_BAND_2GHZ;
2911 else
2912 band = NL80211_BAND_5GHZ;
2913 channel[i].center_freq =
2914 ieee80211_channel_to_frequency(channel_req,
2915 band);
2916 channel[i].band = band;
2917 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2918 request->channels[i] = &channel[i];
2919 request->n_channels++;
2920 }
2921
2922 /* assign parsed ssid array */
2923 if (request->n_ssids)
2924 request->ssids = &ssid[0];
2925
c1179033 2926 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 2927 /* Abort any on-going scan */
27a68fe3 2928 brcmf_abort_scanning(cfg);
e5806072
AS
2929 }
2930
c1179033 2931 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
a0f472ac 2932 err = brcmf_do_escan(cfg, wiphy, ifp, request);
e5806072 2933 if (err) {
c1179033 2934 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
2935 goto out_err;
2936 }
27a68fe3
AS
2937 cfg->sched_escan = true;
2938 cfg->scan_request = request;
e5806072 2939 } else {
57d6e91a 2940 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
e5806072
AS
2941 goto out_err;
2942 }
2943
2944 kfree(ssid);
2945 kfree(channel);
2946 kfree(request);
2947 return 0;
2948
2949out_err:
2950 kfree(ssid);
2951 kfree(channel);
2952 kfree(request);
2953 cfg80211_sched_scan_stopped(wiphy);
2954 return err;
2955}
2956
e5806072
AS
2957static int brcmf_dev_pno_clean(struct net_device *ndev)
2958{
e5806072
AS
2959 int ret;
2960
2961 /* Disable pfn */
ac24be6f 2962 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
2963 if (ret == 0) {
2964 /* clear pfn */
ac24be6f
AS
2965 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2966 NULL, 0);
e5806072
AS
2967 }
2968 if (ret < 0)
57d6e91a 2969 brcmf_err("failed code %d\n", ret);
e5806072
AS
2970
2971 return ret;
2972}
2973
2974static int brcmf_dev_pno_config(struct net_device *ndev)
2975{
2976 struct brcmf_pno_param_le pfn_param;
e5806072
AS
2977
2978 memset(&pfn_param, 0, sizeof(pfn_param));
2979 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2980
2981 /* set extra pno params */
2982 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2983 pfn_param.repeat = BRCMF_PNO_REPEAT;
2984 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2985
2986 /* set up pno scan fr */
2987 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2988
ac24be6f
AS
2989 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2990 &pfn_param, sizeof(pfn_param));
e5806072
AS
2991}
2992
2993static int
2994brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2995 struct net_device *ndev,
2996 struct cfg80211_sched_scan_request *request)
2997{
c1179033 2998 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2999 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3000 struct brcmf_pno_net_param_le pfn;
3001 int i;
3002 int ret = 0;
3003
dc7bdbf1 3004 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
4e8a008e 3005 request->n_match_sets, request->n_ssids);
c1179033 3006 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 3007 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3008 return -EAGAIN;
3009 }
3010
dc7bdbf1 3011 if (!request->n_ssids || !request->n_match_sets) {
57d6e91a 3012 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
dc7bdbf1 3013 request->n_ssids);
e5806072
AS
3014 return -EINVAL;
3015 }
3016
3017 if (request->n_ssids > 0) {
3018 for (i = 0; i < request->n_ssids; i++) {
3019 /* Active scan req for ssids */
4e8a008e
AS
3020 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3021 request->ssids[i].ssid);
e5806072
AS
3022
3023 /*
3024 * match_set ssids is a supert set of n_ssid list,
3025 * so we need not add these set seperately.
3026 */
3027 }
3028 }
3029
3030 if (request->n_match_sets > 0) {
3031 /* clean up everything */
3032 ret = brcmf_dev_pno_clean(ndev);
3033 if (ret < 0) {
57d6e91a 3034 brcmf_err("failed error=%d\n", ret);
e5806072
AS
3035 return ret;
3036 }
3037
3038 /* configure pno */
3039 ret = brcmf_dev_pno_config(ndev);
3040 if (ret < 0) {
57d6e91a 3041 brcmf_err("PNO setup failed!! ret=%d\n", ret);
e5806072
AS
3042 return -EINVAL;
3043 }
3044
3045 /* configure each match set */
3046 for (i = 0; i < request->n_match_sets; i++) {
3047 struct cfg80211_ssid *ssid;
3048 u32 ssid_len;
3049
3050 ssid = &request->match_sets[i].ssid;
3051 ssid_len = ssid->ssid_len;
3052
3053 if (!ssid_len) {
57d6e91a 3054 brcmf_err("skip broadcast ssid\n");
e5806072
AS
3055 continue;
3056 }
3057 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3058 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3059 pfn.wsec = cpu_to_le32(0);
3060 pfn.infra = cpu_to_le32(1);
3061 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3062 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3063 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3064 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3065 sizeof(pfn));
4e8a008e
AS
3066 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3067 ret == 0 ? "set" : "failed", ssid->ssid);
e5806072
AS
3068 }
3069 /* Enable the PNO */
c1179033 3070 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
57d6e91a 3071 brcmf_err("PNO enable failed!! ret=%d\n", ret);
e5806072
AS
3072 return -EINVAL;
3073 }
3074 } else {
3075 return -EINVAL;
3076 }
3077
3078 return 0;
3079}
3080
3081static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3082 struct net_device *ndev)
3083{
27a68fe3 3084 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072 3085
4e8a008e 3086 brcmf_dbg(SCAN, "enter\n");
e5806072 3087 brcmf_dev_pno_clean(ndev);
27a68fe3 3088 if (cfg->sched_escan)
a0f472ac 3089 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
e5806072
AS
3090 return 0;
3091}
e5806072 3092
cbaa177d
AS
3093#ifdef CONFIG_NL80211_TESTMODE
3094static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3095{
27a68fe3 3096 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3097 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3098 struct brcmf_dcmd *dcmd = data;
3099 struct sk_buff *reply;
3100 int ret;
3101
d96b801f
AS
3102 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3103 dcmd->buf, dcmd->len);
f368a5b6
HM
3104
3105 if (dcmd->set)
ac24be6f
AS
3106 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3107 dcmd->buf, dcmd->len);
f368a5b6 3108 else
ac24be6f
AS
3109 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3110 dcmd->buf, dcmd->len);
cbaa177d
AS
3111 if (ret == 0) {
3112 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3113 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3114 ret = cfg80211_testmode_reply(reply);
3115 }
3116 return ret;
3117}
3118#endif
3119
1f170110 3120static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3121{
3122 s32 err;
3123
3124 /* set auth */
ac24be6f 3125 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3126 if (err < 0) {
57d6e91a 3127 brcmf_err("auth error %d\n", err);
1a873342
HM
3128 return err;
3129 }
3130 /* set wsec */
ac24be6f 3131 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3132 if (err < 0) {
57d6e91a 3133 brcmf_err("wsec error %d\n", err);
1a873342
HM
3134 return err;
3135 }
3136 /* set upper-layer auth */
ac24be6f 3137 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3138 if (err < 0) {
57d6e91a 3139 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3140 return err;
3141 }
3142
3143 return 0;
3144}
3145
3146static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3147{
3148 if (is_rsn_ie)
3149 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3150
3151 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3152}
3153
3154static s32
3155brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
34778529 3156 bool is_rsn_ie)
1a873342 3157{
ac24be6f 3158 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3159 u32 auth = 0; /* d11 open authentication */
3160 u16 count;
3161 s32 err = 0;
3162 s32 len = 0;
3163 u32 i;
3164 u32 wsec;
3165 u32 pval = 0;
3166 u32 gval = 0;
3167 u32 wpa_auth = 0;
3168 u32 offset;
3169 u8 *data;
3170 u16 rsn_cap;
3171 u32 wme_bss_disable;
3172
d96b801f 3173 brcmf_dbg(TRACE, "Enter\n");
1a873342
HM
3174 if (wpa_ie == NULL)
3175 goto exit;
3176
3177 len = wpa_ie->len + TLV_HDR_LEN;
3178 data = (u8 *)wpa_ie;
619c5a9a 3179 offset = TLV_HDR_LEN;
1a873342
HM
3180 if (!is_rsn_ie)
3181 offset += VS_IE_FIXED_HDR_LEN;
619c5a9a
HM
3182 else
3183 offset += WPA_IE_VERSION_LEN;
1a873342
HM
3184
3185 /* check for multicast cipher suite */
3186 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3187 err = -EINVAL;
57d6e91a 3188 brcmf_err("no multicast cipher suite\n");
1a873342
HM
3189 goto exit;
3190 }
3191
3192 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3193 err = -EINVAL;
57d6e91a 3194 brcmf_err("ivalid OUI\n");
1a873342
HM
3195 goto exit;
3196 }
3197 offset += TLV_OUI_LEN;
3198
3199 /* pick up multicast cipher */
3200 switch (data[offset]) {
3201 case WPA_CIPHER_NONE:
3202 gval = 0;
3203 break;
3204 case WPA_CIPHER_WEP_40:
3205 case WPA_CIPHER_WEP_104:
3206 gval = WEP_ENABLED;
3207 break;
3208 case WPA_CIPHER_TKIP:
3209 gval = TKIP_ENABLED;
3210 break;
3211 case WPA_CIPHER_AES_CCM:
3212 gval = AES_ENABLED;
3213 break;
3214 default:
3215 err = -EINVAL;
57d6e91a 3216 brcmf_err("Invalid multi cast cipher info\n");
1a873342
HM
3217 goto exit;
3218 }
3219
3220 offset++;
3221 /* walk thru unicast cipher list and pick up what we recognize */
3222 count = data[offset] + (data[offset + 1] << 8);
3223 offset += WPA_IE_SUITE_COUNT_LEN;
3224 /* Check for unicast suite(s) */
3225 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3226 err = -EINVAL;
57d6e91a 3227 brcmf_err("no unicast cipher suite\n");
1a873342
HM
3228 goto exit;
3229 }
3230 for (i = 0; i < count; i++) {
3231 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3232 err = -EINVAL;
57d6e91a 3233 brcmf_err("ivalid OUI\n");
1a873342
HM
3234 goto exit;
3235 }
3236 offset += TLV_OUI_LEN;
3237 switch (data[offset]) {
3238 case WPA_CIPHER_NONE:
3239 break;
3240 case WPA_CIPHER_WEP_40:
3241 case WPA_CIPHER_WEP_104:
3242 pval |= WEP_ENABLED;
3243 break;
3244 case WPA_CIPHER_TKIP:
3245 pval |= TKIP_ENABLED;
3246 break;
3247 case WPA_CIPHER_AES_CCM:
3248 pval |= AES_ENABLED;
3249 break;
3250 default:
57d6e91a 3251 brcmf_err("Ivalid unicast security info\n");
1a873342
HM
3252 }
3253 offset++;
3254 }
3255 /* walk thru auth management suite list and pick up what we recognize */
3256 count = data[offset] + (data[offset + 1] << 8);
3257 offset += WPA_IE_SUITE_COUNT_LEN;
3258 /* Check for auth key management suite(s) */
3259 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3260 err = -EINVAL;
57d6e91a 3261 brcmf_err("no auth key mgmt suite\n");
1a873342
HM
3262 goto exit;
3263 }
3264 for (i = 0; i < count; i++) {
3265 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3266 err = -EINVAL;
57d6e91a 3267 brcmf_err("ivalid OUI\n");
1a873342
HM
3268 goto exit;
3269 }
3270 offset += TLV_OUI_LEN;
3271 switch (data[offset]) {
3272 case RSN_AKM_NONE:
d96b801f 3273 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
1a873342
HM
3274 wpa_auth |= WPA_AUTH_NONE;
3275 break;
3276 case RSN_AKM_UNSPECIFIED:
d96b801f 3277 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
1a873342
HM
3278 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3279 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3280 break;
3281 case RSN_AKM_PSK:
d96b801f 3282 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
1a873342
HM
3283 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3284 (wpa_auth |= WPA_AUTH_PSK);
3285 break;
3286 default:
57d6e91a 3287 brcmf_err("Ivalid key mgmt info\n");
1a873342
HM
3288 }
3289 offset++;
3290 }
3291
3292 if (is_rsn_ie) {
3293 wme_bss_disable = 1;
3294 if ((offset + RSN_CAP_LEN) <= len) {
3295 rsn_cap = data[offset] + (data[offset + 1] << 8);
3296 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3297 wme_bss_disable = 0;
3298 }
3299 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3300 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3301 wme_bss_disable);
1a873342 3302 if (err < 0) {
57d6e91a 3303 brcmf_err("wme_bss_disable error %d\n", err);
1a873342
HM
3304 goto exit;
3305 }
3306 }
3307 /* FOR WPS , set SES_OW_ENABLED */
3308 wsec = (pval | gval | SES_OW_ENABLED);
3309
3310 /* set auth */
ac24be6f 3311 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342 3312 if (err < 0) {
57d6e91a 3313 brcmf_err("auth error %d\n", err);
1a873342
HM
3314 goto exit;
3315 }
3316 /* set wsec */
ac24be6f 3317 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342 3318 if (err < 0) {
57d6e91a 3319 brcmf_err("wsec error %d\n", err);
1a873342
HM
3320 goto exit;
3321 }
3322 /* set upper-layer auth */
ac24be6f 3323 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342 3324 if (err < 0) {
57d6e91a 3325 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3326 goto exit;
3327 }
3328
3329exit:
3330 return err;
3331}
3332
3333static s32
3082b9be 3334brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
3335 struct parsed_vndr_ies *vndr_ies)
3336{
3337 s32 err = 0;
3338 struct brcmf_vs_tlv *vndrie;
3339 struct brcmf_tlv *ie;
3340 struct parsed_vndr_ie_info *parsed_info;
3341 s32 remaining_len;
3342
3343 remaining_len = (s32)vndr_ie_len;
3344 memset(vndr_ies, 0, sizeof(*vndr_ies));
3345
3346 ie = (struct brcmf_tlv *)vndr_ie_buf;
3347 while (ie) {
3348 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3349 goto next;
3350 vndrie = (struct brcmf_vs_tlv *)ie;
3351 /* len should be bigger than OUI length + one */
3352 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
57d6e91a
AS
3353 brcmf_err("invalid vndr ie. length is too small %d\n",
3354 vndrie->len);
1a873342
HM
3355 goto next;
3356 }
3357 /* if wpa or wme ie, do not add ie */
3358 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3359 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3360 (vndrie->oui_type == WME_OUI_TYPE))) {
d96b801f 3361 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
1a873342
HM
3362 goto next;
3363 }
3364
3365 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3366
3367 /* save vndr ie information */
3368 parsed_info->ie_ptr = (char *)vndrie;
3369 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3370 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3371
3372 vndr_ies->count++;
3373
d96b801f
AS
3374 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3375 parsed_info->vndrie.oui[0],
3376 parsed_info->vndrie.oui[1],
3377 parsed_info->vndrie.oui[2],
3378 parsed_info->vndrie.oui_type);
1a873342 3379
9f440b7b 3380 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
1a873342
HM
3381 break;
3382next:
b41fc3d7
HM
3383 remaining_len -= (ie->len + TLV_HDR_LEN);
3384 if (remaining_len <= TLV_HDR_LEN)
1a873342
HM
3385 ie = NULL;
3386 else
b41fc3d7
HM
3387 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3388 TLV_HDR_LEN);
1a873342
HM
3389 }
3390 return err;
3391}
3392
3393static u32
3394brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3395{
3396
3397 __le32 iecount_le;
3398 __le32 pktflag_le;
3399
3400 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3401 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3402
3403 iecount_le = cpu_to_le32(1);
3404 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3405
3406 pktflag_le = cpu_to_le32(pktflag);
3407 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3408
3409 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3410
3411 return ie_len + VNDR_IE_HDR_SIZE;
3412}
3413
1332e26e
AS
3414s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3415 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 3416{
1332e26e
AS
3417 struct brcmf_if *ifp;
3418 struct vif_saved_ie *saved_ie;
1a873342
HM
3419 s32 err = 0;
3420 u8 *iovar_ie_buf;
3421 u8 *curr_ie_buf;
3422 u8 *mgmt_ie_buf = NULL;
3e4f319d 3423 int mgmt_ie_buf_len;
81118d16 3424 u32 *mgmt_ie_len;
1a873342
HM
3425 u32 del_add_ie_buf_len = 0;
3426 u32 total_ie_buf_len = 0;
3427 u32 parsed_ie_buf_len = 0;
3428 struct parsed_vndr_ies old_vndr_ies;
3429 struct parsed_vndr_ies new_vndr_ies;
3430 struct parsed_vndr_ie_info *vndrie_info;
3431 s32 i;
3432 u8 *ptr;
3e4f319d 3433 int remained_buf_len;
1a873342 3434
1332e26e
AS
3435 if (!vif)
3436 return -ENODEV;
3437 ifp = vif->ifp;
3438 saved_ie = &vif->saved_ie;
3439
d96b801f 3440 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
1a873342
HM
3441 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3442 if (!iovar_ie_buf)
3443 return -ENOMEM;
3444 curr_ie_buf = iovar_ie_buf;
89286dc9
HM
3445 switch (pktflag) {
3446 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3447 mgmt_ie_buf = saved_ie->probe_req_ie;
3448 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3449 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3450 break;
3451 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3452 mgmt_ie_buf = saved_ie->probe_res_ie;
3453 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3454 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3455 break;
3456 case BRCMF_VNDR_IE_BEACON_FLAG:
3457 mgmt_ie_buf = saved_ie->beacon_ie;
3458 mgmt_ie_len = &saved_ie->beacon_ie_len;
3459 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3460 break;
3461 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3462 mgmt_ie_buf = saved_ie->assoc_req_ie;
3463 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3464 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3465 break;
3466 default:
3467 err = -EPERM;
3468 brcmf_err("not suitable type\n");
3469 goto exit;
1a873342
HM
3470 }
3471
3472 if (vndr_ie_len > mgmt_ie_buf_len) {
3473 err = -ENOMEM;
57d6e91a 3474 brcmf_err("extra IE size too big\n");
1a873342
HM
3475 goto exit;
3476 }
3477
3478 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3479 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3480 ptr = curr_ie_buf;
3481 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3482 for (i = 0; i < new_vndr_ies.count; i++) {
3483 vndrie_info = &new_vndr_ies.ie_info[i];
3484 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3485 vndrie_info->ie_len);
3486 parsed_ie_buf_len += vndrie_info->ie_len;
3487 }
3488 }
3489
b41fc3d7 3490 if (mgmt_ie_buf && *mgmt_ie_len) {
1a873342
HM
3491 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3492 (memcmp(mgmt_ie_buf, curr_ie_buf,
3493 parsed_ie_buf_len) == 0)) {
d96b801f 3494 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
1a873342
HM
3495 goto exit;
3496 }
3497
3498 /* parse old vndr_ie */
3499 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3500
3501 /* make a command to delete old ie */
3502 for (i = 0; i < old_vndr_ies.count; i++) {
3503 vndrie_info = &old_vndr_ies.ie_info[i];
3504
d96b801f
AS
3505 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3506 vndrie_info->vndrie.id,
3507 vndrie_info->vndrie.len,
3508 vndrie_info->vndrie.oui[0],
3509 vndrie_info->vndrie.oui[1],
3510 vndrie_info->vndrie.oui[2]);
1a873342
HM
3511
3512 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3513 vndrie_info->ie_ptr,
3514 vndrie_info->ie_len,
3515 "del");
3516 curr_ie_buf += del_add_ie_buf_len;
3517 total_ie_buf_len += del_add_ie_buf_len;
3518 }
3519 }
3520
3521 *mgmt_ie_len = 0;
3522 /* Add if there is any extra IE */
3523 if (mgmt_ie_buf && parsed_ie_buf_len) {
3524 ptr = mgmt_ie_buf;
3525
3526 remained_buf_len = mgmt_ie_buf_len;
3527
3528 /* make a command to add new ie */
3529 for (i = 0; i < new_vndr_ies.count; i++) {
3530 vndrie_info = &new_vndr_ies.ie_info[i];
3531
b41fc3d7
HM
3532 /* verify remained buf size before copy data */
3533 if (remained_buf_len < (vndrie_info->vndrie.len +
3534 VNDR_IE_VSIE_OFFSET)) {
57d6e91a
AS
3535 brcmf_err("no space in mgmt_ie_buf: len left %d",
3536 remained_buf_len);
b41fc3d7
HM
3537 break;
3538 }
3539 remained_buf_len -= (vndrie_info->ie_len +
3540 VNDR_IE_VSIE_OFFSET);
3541
d96b801f
AS
3542 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3543 vndrie_info->vndrie.id,
3544 vndrie_info->vndrie.len,
3545 vndrie_info->vndrie.oui[0],
3546 vndrie_info->vndrie.oui[1],
3547 vndrie_info->vndrie.oui[2]);
1a873342
HM
3548
3549 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3550 vndrie_info->ie_ptr,
3551 vndrie_info->ie_len,
3552 "add");
1a873342
HM
3553
3554 /* save the parsed IE in wl struct */
3555 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3556 vndrie_info->ie_len);
3557 *mgmt_ie_len += vndrie_info->ie_len;
3558
3559 curr_ie_buf += del_add_ie_buf_len;
3560 total_ie_buf_len += del_add_ie_buf_len;
3561 }
3562 }
3563 if (total_ie_buf_len) {
c1179033 3564 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3565 total_ie_buf_len);
1a873342 3566 if (err)
57d6e91a 3567 brcmf_err("vndr ie set error : %d\n", err);
1a873342
HM
3568 }
3569
3570exit:
3571 kfree(iovar_ie_buf);
3572 return err;
3573}
3574
5f4f9f11
AS
3575s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3576{
3577 s32 pktflags[] = {
3578 BRCMF_VNDR_IE_PRBREQ_FLAG,
3579 BRCMF_VNDR_IE_PRBRSP_FLAG,
3580 BRCMF_VNDR_IE_BEACON_FLAG
3581 };
3582 int i;
3583
3584 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3585 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3586
3587 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3588 return 0;
3589}
3590
a0f07959
HM
3591static s32
3592brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3593 struct cfg80211_beacon_data *beacon)
3594{
3595 s32 err;
3596
3597 /* Set Beacon IEs to FW */
3598 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3599 beacon->tail, beacon->tail_len);
3600 if (err) {
3601 brcmf_err("Set Beacon IE Failed\n");
3602 return err;
3603 }
3604 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3605
3606 /* Set Probe Response IEs to FW */
3607 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3608 beacon->proberesp_ies,
3609 beacon->proberesp_ies_len);
3610 if (err)
3611 brcmf_err("Set Probe Resp IE Failed\n");
3612 else
3613 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3614
3615 return err;
3616}
3617
1a873342
HM
3618static s32
3619brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3620 struct cfg80211_ap_settings *settings)
3621{
3622 s32 ie_offset;
ac24be6f 3623 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3624 struct brcmf_tlv *ssid_ie;
3625 struct brcmf_ssid_le ssid_le;
1a873342
HM
3626 s32 err = -EPERM;
3627 struct brcmf_tlv *rsn_ie;
3628 struct brcmf_vs_tlv *wpa_ie;
3629 struct brcmf_join_params join_params;
a0f07959
HM
3630 enum nl80211_iftype dev_role;
3631 struct brcmf_fil_bss_enable_le bss_enable;
1a873342 3632
d96b801f
AS
3633 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3634 cfg80211_get_chandef_type(&settings->chandef),
3635 settings->beacon_interval,
3636 settings->dtim_period);
3637 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3638 settings->ssid, settings->ssid_len, settings->auth_type,
3639 settings->inactivity_timeout);
1a873342 3640
426d0a56 3641 dev_role = ifp->vif->wdev.iftype;
1a873342
HM
3642
3643 memset(&ssid_le, 0, sizeof(ssid_le));
3644 if (settings->ssid == NULL || settings->ssid_len == 0) {
3645 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3646 ssid_ie = brcmf_parse_tlvs(
3647 (u8 *)&settings->beacon.head[ie_offset],
3648 settings->beacon.head_len - ie_offset,
3649 WLAN_EID_SSID);
3650 if (!ssid_ie)
3651 return -EINVAL;
3652
3653 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3654 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
d96b801f 3655 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
1a873342
HM
3656 } else {
3657 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3658 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3659 }
3660
f96aa07e 3661 brcmf_set_mpc(ifp, 0);
1a873342
HM
3662
3663 /* find the RSN_IE */
3664 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3665 settings->beacon.tail_len, WLAN_EID_RSN);
3666
3667 /* find the WPA_IE */
3668 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3669 settings->beacon.tail_len);
3670
1a873342 3671 if ((wpa_ie != NULL || rsn_ie != NULL)) {
d96b801f 3672 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
1a873342
HM
3673 if (wpa_ie != NULL) {
3674 /* WPA IE */
34778529 3675 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
1a873342
HM
3676 if (err < 0)
3677 goto exit;
1a873342
HM
3678 } else {
3679 /* RSN IE */
3680 err = brcmf_configure_wpaie(ndev,
34778529 3681 (struct brcmf_vs_tlv *)rsn_ie, true);
1a873342
HM
3682 if (err < 0)
3683 goto exit;
1a873342 3684 }
1a873342 3685 } else {
d96b801f 3686 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
1f170110 3687 brcmf_configure_opensecurity(ifp);
1a873342 3688 }
1a873342 3689
a0f07959 3690 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
1a873342
HM
3691
3692 if (settings->beacon_interval) {
ac24be6f 3693 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 3694 settings->beacon_interval);
1a873342 3695 if (err < 0) {
57d6e91a 3696 brcmf_err("Beacon Interval Set Error, %d\n", err);
1a873342
HM
3697 goto exit;
3698 }
3699 }
3700 if (settings->dtim_period) {
ac24be6f 3701 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 3702 settings->dtim_period);
1a873342 3703 if (err < 0) {
57d6e91a 3704 brcmf_err("DTIM Interval Set Error, %d\n", err);
1a873342
HM
3705 goto exit;
3706 }
3707 }
a0f07959
HM
3708
3709 if (dev_role == NL80211_IFTYPE_AP) {
3710 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3711 if (err < 0) {
3712 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3713 goto exit;
3714 }
2880b868 3715 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
1a873342
HM
3716 }
3717
a0f07959 3718 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342 3719 if (err < 0) {
a0f07959 3720 brcmf_err("SET INFRA error %d\n", err);
1a873342
HM
3721 goto exit;
3722 }
a0f07959
HM
3723 if (dev_role == NL80211_IFTYPE_AP) {
3724 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3725 if (err < 0) {
3726 brcmf_err("setting AP mode failed %d\n", err);
3727 goto exit;
3728 }
3729 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3730 if (err < 0) {
3731 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3732 goto exit;
3733 }
3734
3735 memset(&join_params, 0, sizeof(join_params));
3736 /* join parameters starts with ssid */
3737 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3738 /* create softap */
3739 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3740 &join_params, sizeof(join_params));
3741 if (err < 0) {
3742 brcmf_err("SET SSID error (%d)\n", err);
3743 goto exit;
3744 }
3745 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3746 } else {
3747 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3748 sizeof(ssid_le));
3749 if (err < 0) {
3750 brcmf_err("setting ssid failed %d\n", err);
3751 goto exit;
3752 }
3753 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3754 bss_enable.enable = cpu_to_le32(1);
3755 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3756 sizeof(bss_enable));
3757 if (err < 0) {
3758 brcmf_err("bss_enable config failed %d\n", err);
3759 goto exit;
3760 }
3761
3762 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3763 }
c1179033
AS
3764 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3765 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
3766
3767exit:
3768 if (err)
f96aa07e 3769 brcmf_set_mpc(ifp, 1);
1a873342
HM
3770 return err;
3771}
3772
3773static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3774{
c1179033 3775 struct brcmf_if *ifp = netdev_priv(ndev);
5c33a942 3776 s32 err;
426d0a56 3777 struct brcmf_fil_bss_enable_le bss_enable;
5c33a942 3778 struct brcmf_join_params join_params;
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);
5c33a942
HM
3786
3787 memset(&join_params, 0, sizeof(join_params));
3788 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3789 &join_params, sizeof(join_params));
3790 if (err < 0)
3791 brcmf_err("SET SSID error (%d)\n", err);
128ce3b6 3792 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5c33a942 3793 if (err < 0)
57d6e91a 3794 brcmf_err("BRCMF_C_UP error %d\n", err);
5c33a942
HM
3795 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3796 if (err < 0)
3797 brcmf_err("setting AP mode failed %d\n", err);
3798 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3799 if (err < 0)
3800 brcmf_err("setting INFRA mode failed %d\n", err);
426d0a56
HM
3801 } else {
3802 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3803 bss_enable.enable = cpu_to_le32(0);
3804 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3805 sizeof(bss_enable));
3806 if (err < 0)
3807 brcmf_err("bss_enable config failed %d\n", err);
1a873342 3808 }
f96aa07e 3809 brcmf_set_mpc(ifp, 1);
426d0a56
HM
3810 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3811 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3812
1a873342
HM
3813 return err;
3814}
3815
a0f07959
HM
3816static s32
3817brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3818 struct cfg80211_beacon_data *info)
3819{
a0f07959
HM
3820 struct brcmf_if *ifp = netdev_priv(ndev);
3821 s32 err;
3822
3823 brcmf_dbg(TRACE, "Enter\n");
3824
a0f07959
HM
3825 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3826
3827 return err;
3828}
3829
1a873342
HM
3830static int
3831brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3832 u8 *mac)
3833{
a0f07959 3834 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342 3835 struct brcmf_scb_val_le scbval;
0abb5f21 3836 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3837 s32 err;
3838
3839 if (!mac)
3840 return -EFAULT;
3841
d96b801f 3842 brcmf_dbg(TRACE, "Enter %pM\n", mac);
1a873342 3843
a0f07959
HM
3844 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3845 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ce81e317 3846 if (!check_vif_up(ifp->vif))
1a873342
HM
3847 return -EIO;
3848
3849 memcpy(&scbval.ea, mac, ETH_ALEN);
3850 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 3851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 3852 &scbval, sizeof(scbval));
1a873342 3853 if (err)
57d6e91a 3854 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
7ab6acd0 3855
d96b801f 3856 brcmf_dbg(TRACE, "Exit\n");
1a873342
HM
3857 return err;
3858}
3859
0de8aace
HM
3860
3861static void
3862brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3863 struct wireless_dev *wdev,
3864 u16 frame_type, bool reg)
3865{
7fa2e352 3866 struct brcmf_cfg80211_vif *vif;
0de8aace
HM
3867 u16 mgmt_type;
3868
3869 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3870
3871 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
7fa2e352 3872 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
0de8aace
HM
3873 if (reg)
3874 vif->mgmt_rx_reg |= BIT(mgmt_type);
3875 else
318a64ce 3876 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
0de8aace
HM
3877}
3878
3879
3880static int
3881brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3882 struct ieee80211_channel *chan, bool offchan,
3883 unsigned int wait, const u8 *buf, size_t len,
3884 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3885{
3886 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3887 const struct ieee80211_mgmt *mgmt;
3888 struct brcmf_cfg80211_vif *vif;
3889 s32 err = 0;
3890 s32 ie_offset;
3891 s32 ie_len;
18e2f61d
HM
3892 struct brcmf_fil_action_frame_le *action_frame;
3893 struct brcmf_fil_af_params_le *af_params;
3894 bool ack;
3895 s32 chan_nr;
0de8aace
HM
3896
3897 brcmf_dbg(TRACE, "Enter\n");
3898
3899 *cookie = 0;
3900
3901 mgmt = (const struct ieee80211_mgmt *)buf;
3902
a0f07959
HM
3903 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
3904 brcmf_err("Driver only allows MGMT packet type\n");
3905 return -EPERM;
3906 }
0de8aace 3907
a0f07959
HM
3908 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3909 /* Right now the only reason to get a probe response */
3910 /* is for p2p listen response or for p2p GO from */
3911 /* wpa_supplicant. Unfortunately the probe is send */
3912 /* on primary ndev, while dongle wants it on the p2p */
3913 /* vif. Since this is only reason for a probe */
3914 /* response to be sent, the vif is taken from cfg. */
3915 /* If ever desired to send proberesp for non p2p */
3916 /* response then data should be checked for */
3917 /* "DIRECT-". Note in future supplicant will take */
3918 /* dedicated p2p wdev to do this and then this 'hack'*/
3919 /* is not needed anymore. */
3920 ie_offset = DOT11_MGMT_HDR_LEN +
3921 DOT11_BCN_PRB_FIXED_LEN;
3922 ie_len = len - ie_offset;
7fa2e352 3923 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
a0f07959 3924 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
0de8aace 3925 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
a0f07959
HM
3926 err = brcmf_vif_set_mgmt_ie(vif,
3927 BRCMF_VNDR_IE_PRBRSP_FLAG,
3928 &buf[ie_offset],
3929 ie_len);
3930 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3931 GFP_KERNEL);
18e2f61d
HM
3932 } else if (ieee80211_is_action(mgmt->frame_control)) {
3933 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
3934 if (af_params == NULL) {
3935 brcmf_err("unable to allocate frame\n");
3936 err = -ENOMEM;
3937 goto exit;
3938 }
3939 action_frame = &af_params->action_frame;
3940 /* Add the packet Id */
3941 action_frame->packet_id = cpu_to_le32(*cookie);
3942 /* Add BSSID */
3943 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
3944 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
3945 /* Add the length exepted for 802.11 header */
3946 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
3947 /* Add the channel */
3948 chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
3949 af_params->channel = cpu_to_le32(chan_nr);
3950
3951 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
3952 le16_to_cpu(action_frame->len));
3953
3954 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
3955 *cookie, le16_to_cpu(action_frame->len),
3956 chan->center_freq);
3957
7fa2e352 3958 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
18e2f61d
HM
3959 af_params);
3960
3961 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
3962 GFP_KERNEL);
3963 kfree(af_params);
a0f07959
HM
3964 } else {
3965 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
3966 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
0de8aace 3967 }
a0f07959 3968
18e2f61d 3969exit:
0de8aace
HM
3970 return err;
3971}
3972
3973
3974static int
3975brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
3976 struct wireless_dev *wdev,
3977 u64 cookie)
3978{
3979 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3980 struct brcmf_cfg80211_vif *vif;
3981 int err = 0;
3982
3983 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
3984
3985 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3986 if (vif == NULL) {
3987 brcmf_err("No p2p device available for probe response\n");
3988 err = -ENODEV;
3989 goto exit;
3990 }
3991 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
3992exit:
3993 return err;
3994}
3995
5b435de0 3996static struct cfg80211_ops wl_cfg80211_ops = {
9f440b7b
AS
3997 .add_virtual_intf = brcmf_cfg80211_add_iface,
3998 .del_virtual_intf = brcmf_cfg80211_del_iface,
5b435de0
AS
3999 .change_virtual_intf = brcmf_cfg80211_change_iface,
4000 .scan = brcmf_cfg80211_scan,
4001 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4002 .join_ibss = brcmf_cfg80211_join_ibss,
4003 .leave_ibss = brcmf_cfg80211_leave_ibss,
4004 .get_station = brcmf_cfg80211_get_station,
4005 .set_tx_power = brcmf_cfg80211_set_tx_power,
4006 .get_tx_power = brcmf_cfg80211_get_tx_power,
4007 .add_key = brcmf_cfg80211_add_key,
4008 .del_key = brcmf_cfg80211_del_key,
4009 .get_key = brcmf_cfg80211_get_key,
4010 .set_default_key = brcmf_cfg80211_config_default_key,
4011 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4012 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
5b435de0
AS
4013 .connect = brcmf_cfg80211_connect,
4014 .disconnect = brcmf_cfg80211_disconnect,
4015 .suspend = brcmf_cfg80211_suspend,
4016 .resume = brcmf_cfg80211_resume,
4017 .set_pmksa = brcmf_cfg80211_set_pmksa,
4018 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4019 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4020 .start_ap = brcmf_cfg80211_start_ap,
4021 .stop_ap = brcmf_cfg80211_stop_ap,
a0f07959 4022 .change_beacon = brcmf_cfg80211_change_beacon,
1a873342 4023 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
4024 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4025 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
0de8aace
HM
4026 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4027 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4028 .remain_on_channel = brcmf_p2p_remain_on_channel,
4029 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
27f10e38
AS
4030 .start_p2p_device = brcmf_p2p_start_device,
4031 .stop_p2p_device = brcmf_p2p_stop_device,
cbaa177d
AS
4032#ifdef CONFIG_NL80211_TESTMODE
4033 .testmode_cmd = brcmf_cfg80211_testmode
4034#endif
5b435de0
AS
4035};
4036
9f440b7b 4037static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
5b435de0 4038{
9f440b7b
AS
4039 switch (type) {
4040 case NL80211_IFTYPE_AP_VLAN:
4041 case NL80211_IFTYPE_WDS:
4042 case NL80211_IFTYPE_MONITOR:
4043 case NL80211_IFTYPE_MESH_POINT:
4044 return -ENOTSUPP;
4045 case NL80211_IFTYPE_ADHOC:
4046 return WL_MODE_IBSS;
4047 case NL80211_IFTYPE_STATION:
4048 case NL80211_IFTYPE_P2P_CLIENT:
4049 return WL_MODE_BSS;
4050 case NL80211_IFTYPE_AP:
4051 case NL80211_IFTYPE_P2P_GO:
4052 return WL_MODE_AP;
4053 case NL80211_IFTYPE_P2P_DEVICE:
4054 return WL_MODE_P2P;
4055 case NL80211_IFTYPE_UNSPECIFIED:
5b435de0 4056 default:
9f440b7b 4057 break;
5b435de0
AS
4058 }
4059
9f440b7b 4060 return -EINVAL;
5b435de0
AS
4061}
4062
e5806072
AS
4063static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4064{
e5806072
AS
4065 /* scheduled scan settings */
4066 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4067 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4068 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4069 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
e5806072
AS
4070}
4071
9f440b7b
AS
4072static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4073 {
dded3d53 4074 .max = 2,
9f440b7b
AS
4075 .types = BIT(NL80211_IFTYPE_STATION) |
4076 BIT(NL80211_IFTYPE_ADHOC) |
4077 BIT(NL80211_IFTYPE_AP)
4078 },
dded3d53
HM
4079 {
4080 .max = 1,
4081 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4082 },
9f440b7b
AS
4083 {
4084 .max = 1,
4085 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4086 BIT(NL80211_IFTYPE_P2P_GO)
4087 },
4088};
4089static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4090 {
dded3d53 4091 .max_interfaces = BRCMF_IFACE_MAX_CNT,
9f440b7b
AS
4092 .num_different_channels = 1, /* no multi-channel for now */
4093 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4094 .limits = brcmf_iface_limits
4095 }
4096};
4097
0de8aace
HM
4098static const struct ieee80211_txrx_stypes
4099brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4100 [NL80211_IFTYPE_STATION] = {
4101 .tx = 0xffff,
4102 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4103 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4104 },
4105 [NL80211_IFTYPE_P2P_CLIENT] = {
4106 .tx = 0xffff,
4107 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4108 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4109 },
4110 [NL80211_IFTYPE_P2P_GO] = {
4111 .tx = 0xffff,
4112 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4113 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4114 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4115 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4116 BIT(IEEE80211_STYPE_AUTH >> 4) |
4117 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4118 BIT(IEEE80211_STYPE_ACTION >> 4)
bffc61c9
AS
4119 },
4120 [NL80211_IFTYPE_P2P_DEVICE] = {
4121 .tx = 0xffff,
4122 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4123 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
0de8aace
HM
4124 }
4125};
4126
3eacf866 4127static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 4128{
3eacf866 4129 struct wiphy *wiphy;
5b435de0
AS
4130 s32 err = 0;
4131
3eacf866
AS
4132 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4133 if (!wiphy) {
57d6e91a 4134 brcmf_err("Could not allocate wiphy device\n");
3eacf866
AS
4135 return ERR_PTR(-ENOMEM);
4136 }
4137 set_wiphy_dev(wiphy, phydev);
4138 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
9f440b7b 4139 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3eacf866
AS
4140 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4141 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4142 BIT(NL80211_IFTYPE_ADHOC) |
9f440b7b
AS
4143 BIT(NL80211_IFTYPE_AP) |
4144 BIT(NL80211_IFTYPE_P2P_CLIENT) |
dded3d53
HM
4145 BIT(NL80211_IFTYPE_P2P_GO) |
4146 BIT(NL80211_IFTYPE_P2P_DEVICE);
9f440b7b
AS
4147 wiphy->iface_combinations = brcmf_iface_combos;
4148 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
3eacf866 4149 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3eacf866
AS
4150 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4151 wiphy->cipher_suites = __wl_cipher_suites;
4152 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
0de8aace 4153 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6eda4e2c 4154 WIPHY_FLAG_OFFCHAN_TX |
0de8aace
HM
4155 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
4156 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4157 wiphy->max_remain_on_channel_duration = 5000;
3eacf866 4158 brcmf_wiphy_pno_params(wiphy);
d48200ba
HM
4159 brcmf_dbg(INFO, "Registering custom regulatory\n");
4160 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
4161 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
3eacf866 4162 err = wiphy_register(wiphy);
5b435de0 4163 if (err < 0) {
57d6e91a 4164 brcmf_err("Could not register wiphy device (%d)\n", err);
3eacf866
AS
4165 wiphy_free(wiphy);
4166 return ERR_PTR(err);
5b435de0 4167 }
3eacf866
AS
4168 return wiphy;
4169}
4170
3eacf866 4171struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
9f440b7b
AS
4172 enum nl80211_iftype type,
4173 bool pm_block)
3eacf866
AS
4174{
4175 struct brcmf_cfg80211_vif *vif;
5b435de0 4176
3eacf866
AS
4177 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4178 return ERR_PTR(-ENOSPC);
5b435de0 4179
33a6b157 4180 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
9f440b7b 4181 sizeof(*vif));
3eacf866
AS
4182 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4183 if (!vif)
4184 return ERR_PTR(-ENOMEM);
4185
4186 vif->wdev.wiphy = cfg->wiphy;
9f440b7b 4187 vif->wdev.iftype = type;
5b435de0 4188
9f440b7b 4189 vif->mode = brcmf_nl80211_iftype_to_mode(type);
3eacf866
AS
4190 vif->pm_block = pm_block;
4191 vif->roam_off = -1;
4192
6ac4f4ed
AS
4193 brcmf_init_prof(&vif->profile);
4194
3eacf866
AS
4195 list_add_tail(&vif->list, &cfg->vif_list);
4196 cfg->vif_cnt++;
4197 return vif;
5b435de0
AS
4198}
4199
9f440b7b 4200void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4201{
3eacf866
AS
4202 struct brcmf_cfg80211_info *cfg;
4203 struct wiphy *wiphy;
5b435de0 4204
3eacf866
AS
4205 wiphy = vif->wdev.wiphy;
4206 cfg = wiphy_priv(wiphy);
4207 list_del(&vif->list);
4208 cfg->vif_cnt--;
4209
4210 kfree(vif);
4211 if (!cfg->vif_cnt) {
4212 wiphy_unregister(wiphy);
4213 wiphy_free(wiphy);
5b435de0 4214 }
5b435de0
AS
4215}
4216
903e0eee 4217static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
5b435de0 4218{
5c36b99a
AS
4219 u32 event = e->event_code;
4220 u32 status = e->status;
5b435de0
AS
4221
4222 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
16886735 4223 brcmf_dbg(CONN, "Processing set ssid\n");
5b435de0
AS
4224 return true;
4225 }
4226
4227 return false;
4228}
4229
903e0eee 4230static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
5b435de0 4231{
5c36b99a
AS
4232 u32 event = e->event_code;
4233 u16 flags = e->flags;
5b435de0
AS
4234
4235 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
16886735 4236 brcmf_dbg(CONN, "Processing link down\n");
5b435de0
AS
4237 return true;
4238 }
4239 return false;
4240}
4241
27a68fe3 4242static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4243 const struct brcmf_event_msg *e)
4244{
5c36b99a
AS
4245 u32 event = e->event_code;
4246 u32 status = e->status;
5b435de0
AS
4247
4248 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
16886735
AS
4249 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4250 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
4251 return true;
4252 }
4253
4254 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
16886735 4255 brcmf_dbg(CONN, "Processing connecting & no network found\n");
5b435de0
AS
4256 return true;
4257 }
4258
4259 return false;
4260}
4261
27a68fe3 4262static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4263{
27a68fe3 4264 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4265
4266 kfree(conn_info->req_ie);
4267 conn_info->req_ie = NULL;
4268 conn_info->req_ie_len = 0;
4269 kfree(conn_info->resp_ie);
4270 conn_info->resp_ie = NULL;
4271 conn_info->resp_ie_len = 0;
4272}
4273
89286dc9
HM
4274static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4275 struct brcmf_if *ifp)
5b435de0 4276{
c4e382d2 4277 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4278 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4279 u32 req_len;
4280 u32 resp_len;
4281 s32 err = 0;
4282
27a68fe3 4283 brcmf_clear_assoc_ies(cfg);
5b435de0 4284
ac24be6f
AS
4285 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4286 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0 4287 if (err) {
57d6e91a 4288 brcmf_err("could not get assoc info (%d)\n", err);
5b435de0
AS
4289 return err;
4290 }
c4e382d2 4291 assoc_info =
27a68fe3 4292 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4293 req_len = le32_to_cpu(assoc_info->req_len);
4294 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4295 if (req_len) {
ac24be6f 4296 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4297 cfg->extra_buf,
4298 WL_ASSOC_INFO_MAX);
5b435de0 4299 if (err) {
57d6e91a 4300 brcmf_err("could not get assoc req (%d)\n", err);
5b435de0
AS
4301 return err;
4302 }
4303 conn_info->req_ie_len = req_len;
4304 conn_info->req_ie =
27a68fe3 4305 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4306 GFP_KERNEL);
4307 } else {
4308 conn_info->req_ie_len = 0;
4309 conn_info->req_ie = NULL;
4310 }
4311 if (resp_len) {
ac24be6f 4312 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4313 cfg->extra_buf,
4314 WL_ASSOC_INFO_MAX);
5b435de0 4315 if (err) {
57d6e91a 4316 brcmf_err("could not get assoc resp (%d)\n", err);
5b435de0
AS
4317 return err;
4318 }
4319 conn_info->resp_ie_len = resp_len;
4320 conn_info->resp_ie =
27a68fe3 4321 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4322 GFP_KERNEL);
4323 } else {
4324 conn_info->resp_ie_len = 0;
4325 conn_info->resp_ie = NULL;
4326 }
16886735
AS
4327 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4328 conn_info->req_ie_len, conn_info->resp_ie_len);
5b435de0
AS
4329
4330 return err;
4331}
4332
4333static s32
27a68fe3 4334brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4335 struct net_device *ndev,
4336 const struct brcmf_event_msg *e)
4337{
c1179033
AS
4338 struct brcmf_if *ifp = netdev_priv(ndev);
4339 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4340 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4341 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4342 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4343 struct ieee80211_supported_band *band;
a180b83b 4344 struct brcmf_bss_info_le *bi;
5b435de0
AS
4345 u32 freq;
4346 s32 err = 0;
4347 u32 target_channel;
a180b83b 4348 u8 *buf;
5b435de0 4349
d96b801f 4350 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4351
89286dc9 4352 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4353 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9 4354 brcmf_update_bss_info(cfg, ifp);
5b435de0 4355
a180b83b
FL
4356 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4357 if (buf == NULL) {
4358 err = -ENOMEM;
4359 goto done;
4360 }
4361
4362 /* data sent to dongle has to be little endian */
4363 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4364 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4365 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4366
4367 if (err)
4368 goto done;
5b435de0 4369
a180b83b
FL
4370 bi = (struct brcmf_bss_info_le *)(buf + 4);
4371 target_channel = bi->ctl_ch ? bi->ctl_ch :
4372 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
5b435de0
AS
4373
4374 if (target_channel <= CH_MAX_2G_CHANNEL)
4375 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4376 else
4377 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4378
4379 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4380 notify_channel = ieee80211_get_channel(wiphy, freq);
4381
a180b83b
FL
4382done:
4383 kfree(buf);
06bb123e 4384 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4385 conn_info->req_ie, conn_info->req_ie_len,
4386 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16886735 4387 brcmf_dbg(CONN, "Report roaming result\n");
5b435de0 4388
c1179033 4389 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
d96b801f 4390 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4391 return err;
4392}
4393
4394static s32
27a68fe3 4395brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4396 struct net_device *ndev, const struct brcmf_event_msg *e,
4397 bool completed)
4398{
c1179033
AS
4399 struct brcmf_if *ifp = netdev_priv(ndev);
4400 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4401 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4402 s32 err = 0;
4403
d96b801f 4404 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4405
c1179033
AS
4406 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4407 &ifp->vif->sme_state)) {
5b435de0 4408 if (completed) {
89286dc9 4409 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4410 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9
HM
4411 brcmf_update_bss_info(cfg, ifp);
4412 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4413 &ifp->vif->sme_state);
5b435de0
AS
4414 }
4415 cfg80211_connect_result(ndev,
06bb123e 4416 (u8 *)profile->bssid,
5b435de0
AS
4417 conn_info->req_ie,
4418 conn_info->req_ie_len,
4419 conn_info->resp_ie,
4420 conn_info->resp_ie_len,
4421 completed ? WLAN_STATUS_SUCCESS :
4422 WLAN_STATUS_AUTH_TIMEOUT,
4423 GFP_KERNEL);
16886735
AS
4424 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4425 completed ? "succeeded" : "failed");
5b435de0 4426 }
d96b801f 4427 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4428 return err;
4429}
4430
4431static s32
27a68fe3 4432brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4433 struct net_device *ndev,
4434 const struct brcmf_event_msg *e, void *data)
4435{
7ee29602 4436 static int generation;
5c36b99a
AS
4437 u32 event = e->event_code;
4438 u32 reason = e->reason;
1a873342
HM
4439 struct station_info sinfo;
4440
16886735 4441 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
5f4f9f11
AS
4442 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4443 ndev != cfg_to_ndev(cfg)) {
4444 brcmf_dbg(CONN, "AP mode link down\n");
4445 complete(&cfg->vif_disabled);
4446 return 0;
4447 }
1a873342 4448
1a873342 4449 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
7ee29602
HM
4450 (reason == BRCMF_E_STATUS_SUCCESS)) {
4451 memset(&sinfo, 0, sizeof(sinfo));
1a873342
HM
4452 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4453 if (!data) {
57d6e91a 4454 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
1a873342
HM
4455 return -EINVAL;
4456 }
4457 sinfo.assoc_req_ies = data;
7ee29602 4458 sinfo.assoc_req_ies_len = e->datalen;
1a873342
HM
4459 generation++;
4460 sinfo.generation = generation;
7ee29602 4461 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
1a873342
HM
4462 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4463 (event == BRCMF_E_DEAUTH_IND) ||
4464 (event == BRCMF_E_DEAUTH)) {
7ee29602 4465 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
1a873342 4466 }
7ee29602 4467 return 0;
1a873342
HM
4468}
4469
5b435de0 4470static s32
1993732e 4471brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
4472 const struct brcmf_event_msg *e, void *data)
4473{
1993732e
AS
4474 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4475 struct net_device *ndev = ifp->ndev;
c1179033 4476 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4477 s32 err = 0;
4478
128ce3b6 4479 if (ifp->vif->mode == WL_MODE_AP) {
27a68fe3 4480 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
903e0eee 4481 } else if (brcmf_is_linkup(e)) {
16886735 4482 brcmf_dbg(CONN, "Linkup\n");
128ce3b6 4483 if (brcmf_is_ibssmode(ifp->vif)) {
6c8c4f72 4484 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4485 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4486 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4487 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4488 &ifp->vif->sme_state);
4489 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4490 &ifp->vif->sme_state);
5b435de0 4491 } else
27a68fe3 4492 brcmf_bss_connect_done(cfg, ndev, e, true);
903e0eee 4493 } else if (brcmf_is_linkdown(e)) {
16886735 4494 brcmf_dbg(CONN, "Linkdown\n");
128ce3b6 4495 if (!brcmf_is_ibssmode(ifp->vif)) {
27a68fe3 4496 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033 4497 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
903e0eee 4498 &ifp->vif->sme_state))
5b435de0 4499 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4500 GFP_KERNEL);
5b435de0 4501 }
903e0eee 4502 brcmf_link_down(ifp->vif);
6ac4f4ed 4503 brcmf_init_prof(ndev_to_prof(ndev));
5f4f9f11
AS
4504 if (ndev != cfg_to_ndev(cfg))
4505 complete(&cfg->vif_disabled);
27a68fe3 4506 } else if (brcmf_is_nonetwork(cfg, e)) {
128ce3b6 4507 if (brcmf_is_ibssmode(ifp->vif))
c1179033
AS
4508 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4509 &ifp->vif->sme_state);
5b435de0 4510 else
27a68fe3 4511 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4512 }
4513
4514 return err;
4515}
4516
4517static s32
1993732e 4518brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
4519 const struct brcmf_event_msg *e, void *data)
4520{
1993732e 4521 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0 4522 s32 err = 0;
5c36b99a
AS
4523 u32 event = e->event_code;
4524 u32 status = e->status;
5b435de0
AS
4525
4526 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4527 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 4528 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 4529 else
1993732e 4530 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
4531 }
4532
4533 return err;
4534}
4535
4536static s32
1993732e 4537brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
4538 const struct brcmf_event_msg *e, void *data)
4539{
5c36b99a 4540 u16 flags = e->flags;
5b435de0
AS
4541 enum nl80211_key_type key_type;
4542
4543 if (flags & BRCMF_EVENT_MSG_GROUP)
4544 key_type = NL80211_KEYTYPE_GROUP;
4545 else
4546 key_type = NL80211_KEYTYPE_PAIRWISE;
4547
1993732e 4548 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
4549 NULL, GFP_KERNEL);
4550
4551 return 0;
4552}
4553
d3c0b633
AS
4554static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4555 const struct brcmf_event_msg *e, void *data)
4556{
4557 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4558 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4559 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4560 struct brcmf_cfg80211_vif *vif;
4561
4562 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4563 ifevent->action, ifevent->flags, ifevent->ifidx,
4564 ifevent->bssidx);
4565
d3c0b633
AS
4566 mutex_lock(&event->vif_event_lock);
4567 event->action = ifevent->action;
4568 vif = event->vif;
4569
4570 switch (ifevent->action) {
4571 case BRCMF_E_IF_ADD:
4572 /* waiting process may have timed out */
dc4a787c
WY
4573 if (!cfg->vif_event.vif) {
4574 mutex_unlock(&event->vif_event_lock);
d3c0b633 4575 return -EBADF;
dc4a787c 4576 }
d3c0b633
AS
4577
4578 ifp->vif = vif;
4579 vif->ifp = ifp;
01b8e7db
AS
4580 if (ifp->ndev) {
4581 vif->wdev.netdev = ifp->ndev;
4582 ifp->ndev->ieee80211_ptr = &vif->wdev;
4583 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4584 }
d3c0b633
AS
4585 mutex_unlock(&event->vif_event_lock);
4586 wake_up(&event->vif_wq);
4b3a89de 4587 return 0;
d3c0b633
AS
4588
4589 case BRCMF_E_IF_DEL:
4590 ifp->vif = NULL;
d3c0b633
AS
4591 mutex_unlock(&event->vif_event_lock);
4592 /* event may not be upon user request */
4593 if (brcmf_cfg80211_vif_event_armed(cfg))
4594 wake_up(&event->vif_wq);
4595 return 0;
4596
7a5c1f64
HM
4597 case BRCMF_E_IF_CHANGE:
4598 mutex_unlock(&event->vif_event_lock);
4599 wake_up(&event->vif_wq);
4600 return 0;
4601
d3c0b633
AS
4602 default:
4603 mutex_unlock(&event->vif_event_lock);
4604 break;
4605 }
4606 return -EINVAL;
4607}
4608
5b435de0
AS
4609static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4610{
5b435de0
AS
4611 conf->frag_threshold = (u32)-1;
4612 conf->rts_threshold = (u32)-1;
4613 conf->retry_short = (u32)-1;
4614 conf->retry_long = (u32)-1;
4615 conf->tx_power = -1;
4616}
4617
5c36b99a 4618static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 4619{
5c36b99a
AS
4620 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4621 brcmf_notify_connect_status);
4622 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4623 brcmf_notify_connect_status);
4624 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4625 brcmf_notify_connect_status);
4626 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4627 brcmf_notify_connect_status);
4628 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4629 brcmf_notify_connect_status);
4630 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4631 brcmf_notify_connect_status);
4632 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4633 brcmf_notify_roaming_status);
4634 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4635 brcmf_notify_mic_status);
4636 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4637 brcmf_notify_connect_status);
4638 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4639 brcmf_notify_sched_scan_results);
d3c0b633
AS
4640 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4641 brcmf_notify_vif_event);
0de8aace 4642 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
6eda4e2c 4643 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
0de8aace
HM
4644 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4645 brcmf_p2p_notify_listen_complete);
e6da3400
HM
4646 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4647 brcmf_p2p_notify_action_frame_rx);
18e2f61d
HM
4648 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4649 brcmf_p2p_notify_action_tx_complete);
6eda4e2c
HM
4650 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4651 brcmf_p2p_notify_action_tx_complete);
5b435de0
AS
4652}
4653
27a68fe3
AS
4654static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4655{
27a68fe3
AS
4656 kfree(cfg->conf);
4657 cfg->conf = NULL;
27a68fe3
AS
4658 kfree(cfg->escan_ioctl_buf);
4659 cfg->escan_ioctl_buf = NULL;
27a68fe3
AS
4660 kfree(cfg->extra_buf);
4661 cfg->extra_buf = NULL;
27a68fe3
AS
4662 kfree(cfg->pmk_list);
4663 cfg->pmk_list = NULL;
27a68fe3
AS
4664}
4665
4666static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4667{
27a68fe3
AS
4668 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4669 if (!cfg->conf)
5b435de0 4670 goto init_priv_mem_out;
27a68fe3
AS
4671 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4672 if (!cfg->escan_ioctl_buf)
e756af5b 4673 goto init_priv_mem_out;
27a68fe3
AS
4674 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4675 if (!cfg->extra_buf)
5b435de0 4676 goto init_priv_mem_out;
27a68fe3
AS
4677 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4678 if (!cfg->pmk_list)
5b435de0
AS
4679 goto init_priv_mem_out;
4680
4681 return 0;
4682
4683init_priv_mem_out:
27a68fe3 4684 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4685
4686 return -ENOMEM;
4687}
4688
27a68fe3 4689static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4690{
4691 s32 err = 0;
4692
27a68fe3
AS
4693 cfg->scan_request = NULL;
4694 cfg->pwr_save = true;
27a68fe3 4695 cfg->roam_on = true; /* roam on & off switch.
5b435de0 4696 we enable roam per default */
27a68fe3 4697 cfg->active_scan = true; /* we do active scan for
5b435de0 4698 specific scan per default */
27a68fe3 4699 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 4700 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4701 if (err)
4702 return err;
5c36b99a 4703 brcmf_register_event_handlers(cfg);
27a68fe3 4704 mutex_init(&cfg->usr_sync);
27a68fe3
AS
4705 brcmf_init_escan(cfg);
4706 brcmf_init_conf(cfg->conf);
5f4f9f11 4707 init_completion(&cfg->vif_disabled);
5b435de0
AS
4708 return err;
4709}
4710
27a68fe3 4711static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4712{
27a68fe3 4713 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
4714 brcmf_abort_scanning(cfg);
4715 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4716}
4717
d3c0b633
AS
4718static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4719{
4720 init_waitqueue_head(&event->vif_wq);
d3c0b633
AS
4721 mutex_init(&event->vif_event_lock);
4722}
4723
d9cb2596
AS
4724struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4725 struct device *busdev)
5b435de0 4726{
1ed9baf0 4727 struct net_device *ndev = drvr->iflist[0]->ndev;
27a68fe3 4728 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4729 struct wiphy *wiphy;
4730 struct brcmf_cfg80211_vif *vif;
4731 struct brcmf_if *ifp;
5b435de0
AS
4732 s32 err = 0;
4733
4734 if (!ndev) {
57d6e91a 4735 brcmf_err("ndev is invalid\n");
5b435de0
AS
4736 return NULL;
4737 }
5b435de0 4738
3eacf866
AS
4739 ifp = netdev_priv(ndev);
4740 wiphy = brcmf_setup_wiphy(busdev);
4741 if (IS_ERR(wiphy))
5b435de0 4742 return NULL;
5b435de0 4743
3eacf866
AS
4744 cfg = wiphy_priv(wiphy);
4745 cfg->wiphy = wiphy;
27a68fe3 4746 cfg->pub = drvr;
d3c0b633 4747 init_vif_event(&cfg->vif_event);
3eacf866
AS
4748 INIT_LIST_HEAD(&cfg->vif_list);
4749
d3c0b633 4750 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
3eacf866
AS
4751 if (IS_ERR(vif)) {
4752 wiphy_free(wiphy);
4753 return NULL;
4754 }
4755
d3c0b633
AS
4756 vif->ifp = ifp;
4757 vif->wdev.netdev = ndev;
4758 ndev->ieee80211_ptr = &vif->wdev;
4759 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4760
27a68fe3 4761 err = wl_init_priv(cfg);
5b435de0 4762 if (err) {
57d6e91a 4763 brcmf_err("Failed to init iwm_priv (%d)\n", err);
5b435de0
AS
4764 goto cfg80211_attach_out;
4765 }
3eacf866 4766 ifp->vif = vif;
2fde59d9
HM
4767
4768 err = brcmf_p2p_attach(cfg);
4769 if (err) {
4770 brcmf_err("P2P initilisation failed (%d)\n", err);
4771 goto cfg80211_p2p_attach_out;
4772 }
4773
27a68fe3 4774 return cfg;
5b435de0 4775
2fde59d9
HM
4776cfg80211_p2p_attach_out:
4777 wl_deinit_priv(cfg);
4778
5b435de0 4779cfg80211_attach_out:
3eacf866 4780 brcmf_free_vif(vif);
2880b868 4781 wiphy_free(wiphy);
5b435de0
AS
4782 return NULL;
4783}
4784
27a68fe3 4785void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 4786{
3eacf866
AS
4787 struct brcmf_cfg80211_vif *vif;
4788 struct brcmf_cfg80211_vif *tmp;
4789
27a68fe3 4790 wl_deinit_priv(cfg);
3eacf866
AS
4791 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4792 brcmf_free_vif(vif);
4793 }
5b435de0
AS
4794}
4795
5b435de0 4796static s32
40a23296 4797brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
5b435de0 4798{
5b435de0 4799 s32 err = 0;
f588bc0c
AS
4800 __le32 roamtrigger[2];
4801 __le32 roam_delta[2];
5b435de0
AS
4802
4803 /*
4804 * Setup timeout if Beacons are lost and roam is
4805 * off to report link down
4806 */
4807 if (roamvar) {
ac24be6f 4808 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0 4809 if (err) {
57d6e91a 4810 brcmf_err("bcn_timeout error (%d)\n", err);
5b435de0
AS
4811 goto dongle_rom_out;
4812 }
4813 }
4814
4815 /*
4816 * Enable/Disable built-in roaming to allow supplicant
4817 * to take care of roaming
4818 */
647c9ae0 4819 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 4820 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0 4821 if (err) {
57d6e91a 4822 brcmf_err("roam_off error (%d)\n", err);
5b435de0
AS
4823 goto dongle_rom_out;
4824 }
4825
f588bc0c
AS
4826 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4827 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4828 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 4829 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0 4830 if (err) {
57d6e91a 4831 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5b435de0
AS
4832 goto dongle_rom_out;
4833 }
4834
f588bc0c
AS
4835 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4836 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4837 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 4838 (void *)roam_delta, sizeof(roam_delta));
5b435de0 4839 if (err) {
57d6e91a 4840 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
5b435de0
AS
4841 goto dongle_rom_out;
4842 }
4843
4844dongle_rom_out:
4845 return err;
4846}
4847
4848static s32
40a23296 4849brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
c68cdc0f 4850 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0
AS
4851{
4852 s32 err = 0;
4853
ac24be6f 4854 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 4855 scan_assoc_time);
5b435de0
AS
4856 if (err) {
4857 if (err == -EOPNOTSUPP)
647c9ae0 4858 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
5b435de0 4859 else
57d6e91a 4860 brcmf_err("Scan assoc time error (%d)\n", err);
5b435de0
AS
4861 goto dongle_scantime_out;
4862 }
ac24be6f 4863 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 4864 scan_unassoc_time);
5b435de0
AS
4865 if (err) {
4866 if (err == -EOPNOTSUPP)
647c9ae0 4867 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
5b435de0 4868 else
57d6e91a 4869 brcmf_err("Scan unassoc time error (%d)\n", err);
5b435de0
AS
4870 goto dongle_scantime_out;
4871 }
4872
ac24be6f 4873 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 4874 scan_passive_time);
5b435de0
AS
4875 if (err) {
4876 if (err == -EOPNOTSUPP)
647c9ae0 4877 brcmf_dbg(INFO, "Scan passive time is not supported\n");
5b435de0 4878 else
57d6e91a 4879 brcmf_err("Scan passive time error (%d)\n", err);
5b435de0
AS
4880 goto dongle_scantime_out;
4881 }
4882
4883dongle_scantime_out:
4884 return err;
4885}
4886
d48200ba
HM
4887
4888static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
4889{
4890 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
4891 struct ieee80211_channel *band_chan_arr;
4892 struct brcmf_chanspec_list *list;
4893 s32 err;
4894 u8 *pbuf;
4895 u32 i, j;
4896 u32 total;
4897 u16 chanspec;
4898 enum ieee80211_band band;
4899 u32 channel;
4900 u32 *n_cnt;
4901 bool ht40_allowed;
4902 u32 index;
4903 u32 ht40_flag;
4904 bool update;
4905 u32 array_size;
4906
4907 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4908
4909 if (pbuf == NULL)
4910 return -ENOMEM;
4911
4912 list = (struct brcmf_chanspec_list *)pbuf;
4913
4914 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
4915 BRCMF_DCMD_MEDLEN);
4916 if (err) {
4917 brcmf_err("get chanspecs error (%d)\n", err);
4918 goto exit;
4919 }
4920
4921 __wl_band_2ghz.n_channels = 0;
4922 __wl_band_5ghz_a.n_channels = 0;
4923
4924 total = le32_to_cpu(list->count);
4925 for (i = 0; i < total; i++) {
4926 chanspec = (u16)le32_to_cpu(list->element[i]);
4927 channel = CHSPEC_CHANNEL(chanspec);
4928
4929 if (CHSPEC_IS40(chanspec)) {
4930 if (CHSPEC_SB_UPPER(chanspec))
4931 channel += CH_10MHZ_APART;
4932 else
4933 channel -= CH_10MHZ_APART;
4934 } else if (CHSPEC_IS80(chanspec)) {
4935 brcmf_dbg(INFO, "HT80 center channel : %d\n",
4936 channel);
4937 continue;
4938 }
4939 if (CHSPEC_IS2G(chanspec) && (channel >= CH_MIN_2G_CHANNEL) &&
4940 (channel <= CH_MAX_2G_CHANNEL)) {
4941 band_chan_arr = __wl_2ghz_channels;
4942 array_size = ARRAY_SIZE(__wl_2ghz_channels);
4943 n_cnt = &__wl_band_2ghz.n_channels;
4944 band = IEEE80211_BAND_2GHZ;
4945 ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
4946 } else if (CHSPEC_IS5G(chanspec) &&
4947 channel >= CH_MIN_5G_CHANNEL) {
4948 band_chan_arr = __wl_5ghz_a_channels;
4949 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
4950 n_cnt = &__wl_band_5ghz_a.n_channels;
4951 band = IEEE80211_BAND_5GHZ;
4952 ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
4953 } else {
4954 brcmf_err("Invalid channel Sepc. 0x%x.\n", chanspec);
4955 continue;
4956 }
4957 if (!ht40_allowed && CHSPEC_IS40(chanspec))
4958 continue;
4959 update = false;
4960 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
4961 if (band_chan_arr[j].hw_value == channel) {
4962 update = true;
4963 break;
4964 }
4965 }
4966 if (update)
4967 index = j;
4968 else
4969 index = *n_cnt;
4970 if (index < array_size) {
4971 band_chan_arr[index].center_freq =
4972 ieee80211_channel_to_frequency(channel, band);
4973 band_chan_arr[index].hw_value = channel;
4974
4975 if (CHSPEC_IS40(chanspec) && ht40_allowed) {
4976 /* assuming the order is HT20, HT40 Upper,
4977 * HT40 lower from chanspecs
4978 */
4979 ht40_flag = band_chan_arr[index].flags &
4980 IEEE80211_CHAN_NO_HT40;
4981 if (CHSPEC_SB_UPPER(chanspec)) {
4982 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
4983 band_chan_arr[index].flags &=
4984 ~IEEE80211_CHAN_NO_HT40;
4985 band_chan_arr[index].flags |=
4986 IEEE80211_CHAN_NO_HT40PLUS;
4987 } else {
4988 /* It should be one of
4989 * IEEE80211_CHAN_NO_HT40 or
4990 * IEEE80211_CHAN_NO_HT40PLUS
4991 */
4992 band_chan_arr[index].flags &=
4993 ~IEEE80211_CHAN_NO_HT40;
4994 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
4995 band_chan_arr[index].flags |=
4996 IEEE80211_CHAN_NO_HT40MINUS;
4997 }
4998 } else {
4999 band_chan_arr[index].flags =
5000 IEEE80211_CHAN_NO_HT40;
5001 if (band == IEEE80211_BAND_2GHZ)
5002 channel |= WL_CHANSPEC_BAND_2G;
5003 else
5004 channel |= WL_CHANSPEC_BAND_5G;
5005 channel |= WL_CHANSPEC_BW_20;
5006 err = brcmf_fil_bsscfg_int_get(ifp,
5007 "per_chan_info",
5008 &channel);
5009 if (!err) {
5010 if (channel & WL_CHAN_RADAR)
5011 band_chan_arr[index].flags |=
5012 (IEEE80211_CHAN_RADAR |
5013 IEEE80211_CHAN_NO_IBSS);
5014 if (channel & WL_CHAN_PASSIVE)
5015 band_chan_arr[index].flags |=
5016 IEEE80211_CHAN_PASSIVE_SCAN;
5017 }
5018 }
5019 if (!update)
5020 (*n_cnt)++;
5021 }
5022 }
5023exit:
5024 kfree(pbuf);
5025 return err;
5026}
5027
5028
5029static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 5030{
ac24be6f 5031 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5032 struct wiphy *wiphy;
5033 s32 phy_list;
d48200ba
HM
5034 u32 band_list[3];
5035 u32 nmode;
5036 u32 bw_cap = 0;
5b435de0 5037 s8 phy;
d48200ba
HM
5038 s32 err;
5039 u32 nband;
5040 s32 i;
5041 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
5042 s32 index;
5b435de0 5043
b87e2c48 5044 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
81f5dcb8 5045 &phy_list, sizeof(phy_list));
5b435de0 5046 if (err) {
d48200ba 5047 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
5b435de0
AS
5048 return err;
5049 }
5050
3ba81376 5051 phy = ((char *)&phy_list)[0];
d48200ba
HM
5052 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5053
5054
5055 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5056 &band_list, sizeof(band_list));
5057 if (err) {
5058 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5059 return err;
5b435de0 5060 }
d48200ba
HM
5061 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5062 band_list[0], band_list[1], band_list[2]);
5063
5064 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5065 if (err) {
5066 brcmf_err("nmode error (%d)\n", err);
5067 } else {
5068 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
5069 if (err)
5070 brcmf_err("mimo_bw_cap error (%d)\n", err);
5071 }
5072 brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
5073
5074 err = brcmf_construct_reginfo(cfg, bw_cap);
5075 if (err) {
5076 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5077 return err;
5078 }
5079
5080 nband = band_list[0];
5081 memset(bands, 0, sizeof(bands));
5082
5083 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
5084 index = -1;
5085 if ((band_list[i] == WLC_BAND_5G) &&
5086 (__wl_band_5ghz_a.n_channels > 0)) {
5087 index = IEEE80211_BAND_5GHZ;
5088 bands[index] = &__wl_band_5ghz_a;
5089 if ((bw_cap == WLC_N_BW_40ALL) ||
5090 (bw_cap == WLC_N_BW_20IN2G_40IN5G))
5091 bands[index]->ht_cap.cap |=
5092 IEEE80211_HT_CAP_SGI_40;
5093 } else if ((band_list[i] == WLC_BAND_2G) &&
5094 (__wl_band_2ghz.n_channels > 0)) {
5095 index = IEEE80211_BAND_2GHZ;
5096 bands[index] = &__wl_band_2ghz;
5097 if (bw_cap == WLC_N_BW_40ALL)
5098 bands[index]->ht_cap.cap |=
5099 IEEE80211_HT_CAP_SGI_40;
5100 }
5101
5102 if ((index >= 0) && nmode) {
5103 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5104 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5105 bands[index]->ht_cap.ht_supported = true;
5106 bands[index]->ht_cap.ampdu_factor =
5107 IEEE80211_HT_MAX_AMPDU_64K;
5108 bands[index]->ht_cap.ampdu_density =
5109 IEEE80211_HT_MPDU_DENSITY_16;
5110 /* An HT shall support all EQM rates for one spatial
5111 * stream
5112 */
5113 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
5114 }
5115 }
5116
5117 wiphy = cfg_to_wiphy(cfg);
5118 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5119 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5120 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
5b435de0
AS
5121
5122 return err;
5123}
5124
d48200ba 5125
27a68fe3 5126static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 5127{
d48200ba 5128 return brcmf_update_wiphybands(cfg);
5b435de0
AS
5129}
5130
27a68fe3 5131static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5132{
5133 struct net_device *ndev;
5134 struct wireless_dev *wdev;
40a23296 5135 struct brcmf_if *ifp;
5b435de0
AS
5136 s32 power_mode;
5137 s32 err = 0;
5138
27a68fe3 5139 if (cfg->dongle_up)
5b435de0
AS
5140 return err;
5141
27a68fe3 5142 ndev = cfg_to_ndev(cfg);
5b435de0 5143 wdev = ndev->ieee80211_ptr;
40a23296
HM
5144 ifp = netdev_priv(ndev);
5145
5146 /* make sure RF is ready for work */
5147 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5b435de0 5148
40a23296
HM
5149 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5150 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5b435de0 5151
27a68fe3 5152 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
40a23296 5153 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5b435de0
AS
5154 if (err)
5155 goto default_conf_out;
647c9ae0
AS
5156 brcmf_dbg(INFO, "power save set to %s\n",
5157 (power_mode ? "enabled" : "disabled"));
5b435de0 5158
40a23296 5159 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
5b435de0
AS
5160 if (err)
5161 goto default_conf_out;
5dd161ff
FL
5162 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5163 NULL, NULL);
40a23296 5164 if (err)
5b435de0 5165 goto default_conf_out;
27a68fe3 5166 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
5167 if (err)
5168 goto default_conf_out;
5169
27a68fe3 5170 cfg->dongle_up = true;
40a23296 5171default_conf_out:
5b435de0
AS
5172
5173 return err;
5174
5175}
5176
bdf5ff51 5177static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5b435de0 5178{
c1179033 5179 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5180
bdf5ff51 5181 return brcmf_config_dongle(ifp->drvr->config);
5b435de0
AS
5182}
5183
bdf5ff51 5184static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5b435de0 5185{
bdf5ff51 5186 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
c1179033 5187
5b435de0
AS
5188 /*
5189 * While going down, if associated with AP disassociate
5190 * from AP to save power
5191 */
903e0eee
AS
5192 if (check_vif_up(ifp->vif)) {
5193 brcmf_link_down(ifp->vif);
5b435de0
AS
5194
5195 /* Make sure WPA_Supplicant receives all the event
5196 generated due to DISASSOC call to the fw to keep
5197 the state fw and WPA_Supplicant state consistent
5198 */
5199 brcmf_delay(500);
5200 }
5201
27a68fe3 5202 brcmf_abort_scanning(cfg);
c1179033 5203 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5204
5b435de0
AS
5205 return 0;
5206}
5207
bdf5ff51 5208s32 brcmf_cfg80211_up(struct net_device *ndev)
5b435de0 5209{
bdf5ff51
AS
5210 struct brcmf_if *ifp = netdev_priv(ndev);
5211 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5212 s32 err = 0;
5213
27a68fe3 5214 mutex_lock(&cfg->usr_sync);
bdf5ff51 5215 err = __brcmf_cfg80211_up(ifp);
27a68fe3 5216 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5217
5218 return err;
5219}
5220
bdf5ff51 5221s32 brcmf_cfg80211_down(struct net_device *ndev)
5b435de0 5222{
bdf5ff51
AS
5223 struct brcmf_if *ifp = netdev_priv(ndev);
5224 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5225 s32 err = 0;
5226
27a68fe3 5227 mutex_lock(&cfg->usr_sync);
bdf5ff51 5228 err = __brcmf_cfg80211_down(ifp);
27a68fe3 5229 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5230
5231 return err;
5232}
5233
9f440b7b
AS
5234u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5235{
5236 struct brcmf_cfg80211_vif *vif;
5237 bool result = 0;
5238
5239 list_for_each_entry(vif, &cfg->vif_list, list) {
5240 if (test_bit(state, &vif->sme_state))
5241 result++;
5242 }
5243 return result;
5244}
d3c0b633
AS
5245
5246static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5247 u8 action)
5248{
5249 u8 evt_action;
5250
5251 mutex_lock(&event->vif_event_lock);
5252 evt_action = event->action;
5253 mutex_unlock(&event->vif_event_lock);
5254 return evt_action == action;
5255}
5256
5257void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5258 struct brcmf_cfg80211_vif *vif)
5259{
5260 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5261
5262 mutex_lock(&event->vif_event_lock);
5263 event->vif = vif;
5264 event->action = 0;
5265 mutex_unlock(&event->vif_event_lock);
5266}
5267
5268bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5269{
5270 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5271 bool armed;
5272
5273 mutex_lock(&event->vif_event_lock);
5274 armed = event->vif != NULL;
5275 mutex_unlock(&event->vif_event_lock);
5276
5277 return armed;
5278}
5279int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5280 u8 action, ulong timeout)
5281{
5282 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5283
5284 return wait_event_timeout(event->vif_wq,
5285 vif_event_equals(event, action), timeout);
5286}
5287
This page took 0.552655 seconds and 5 git commands to generate.