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