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