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