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