brcmfmac: simplify if-else condition in brcmf_cfg80211_escan()
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / wl_cfg80211.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
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;
5b435de0
AS
2348 if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
2349 WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
2350 bss_list->version);
2351 return -EOPNOTSUPP;
2352 }
2353 WL_SCAN("scanned AP count (%d)\n", bss_list->count);
2354 for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
6f09be0a 2355 bi = next_bss_le(bss_list, bi);
27a68fe3 2356 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2357 if (err)
2358 break;
2359 }
2360 return err;
2361}
2362
27a68fe3 2363static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2364 struct net_device *ndev, const u8 *bssid)
2365{
27a68fe3 2366 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2367 struct ieee80211_channel *notify_channel;
d34bf64f 2368 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2369 struct ieee80211_supported_band *band;
e78946e1 2370 struct cfg80211_bss *bss;
5b435de0
AS
2371 u8 *buf = NULL;
2372 s32 err = 0;
2373 u16 channel;
2374 u32 freq;
5b435de0
AS
2375 u16 notify_capability;
2376 u16 notify_interval;
2377 u8 *notify_ie;
2378 size_t notify_ielen;
2379 s32 notify_signal;
2380
2381 WL_TRACE("Enter\n");
2382
2383 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2384 if (buf == NULL) {
2385 err = -ENOMEM;
2386 goto CleanUp;
2387 }
2388
2389 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2390
ac24be6f
AS
2391 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2392 buf, WL_BSS_INFO_MAX);
5b435de0
AS
2393 if (err) {
2394 WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
2395 goto CleanUp;
2396 }
2397
d34bf64f 2398 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0
AS
2399
2400 channel = bi->ctl_ch ? bi->ctl_ch :
2401 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2402
2403 if (channel <= CH_MAX_2G_CHANNEL)
2404 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2405 else
2406 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2407
2408 freq = ieee80211_channel_to_frequency(channel, band->band);
2409 notify_channel = ieee80211_get_channel(wiphy, freq);
2410
5b435de0
AS
2411 notify_capability = le16_to_cpu(bi->capability);
2412 notify_interval = le16_to_cpu(bi->beacon_period);
2413 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2414 notify_ielen = le32_to_cpu(bi->ie_length);
2415 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2416
2417 WL_CONN("channel: %d(%d)\n", channel, freq);
2418 WL_CONN("capability: %X\n", notify_capability);
2419 WL_CONN("beacon interval: %d\n", notify_interval);
2420 WL_CONN("signal: %d\n", notify_signal);
5b435de0 2421
e78946e1 2422 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
8e6cffb3 2423 0, notify_capability, notify_interval,
5b435de0
AS
2424 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2425
e78946e1
FL
2426 if (!bss) {
2427 err = -ENOMEM;
2428 goto CleanUp;
2429 }
2430
2431 cfg80211_put_bss(bss);
2432
5b435de0
AS
2433CleanUp:
2434
2435 kfree(buf);
2436
2437 WL_TRACE("Exit\n");
2438
2439 return err;
2440}
2441
27a68fe3 2442static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg)
5b435de0 2443{
27a68fe3 2444 return cfg->conf->mode == WL_MODE_IBSS;
5b435de0
AS
2445}
2446
f8e4b412
AB
2447/*
2448 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2449 * triples, returning a pointer to the substring whose first element
2450 * matches tag
2451 */
2452static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
2453{
2454 struct brcmf_tlv *elt;
2455 int totlen;
2456
2457 elt = (struct brcmf_tlv *) buf;
2458 totlen = buflen;
2459
2460 /* find tagged parameter */
04012895 2461 while (totlen >= TLV_HDR_LEN) {
f8e4b412
AB
2462 int len = elt->len;
2463
2464 /* validate remaining totlen */
04012895 2465 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
f8e4b412
AB
2466 return elt;
2467
04012895
HM
2468 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2469 totlen -= (len + TLV_HDR_LEN);
f8e4b412
AB
2470 }
2471
2472 return NULL;
2473}
2474
1a873342
HM
2475/* Is any of the tlvs the expected entry? If
2476 * not update the tlvs buffer pointer/length.
2477 */
2478static bool
2479brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2480 u8 *oui, u32 oui_len, u8 type)
2481{
2482 /* If the contents match the OUI and the type */
2483 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2484 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2485 type == ie[TLV_BODY_OFF + oui_len]) {
2486 return true;
f8e4b412
AB
2487 }
2488
1a873342
HM
2489 if (tlvs == NULL)
2490 return false;
2491 /* point to the next ie */
2492 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2493 /* calculate the length of the rest of the buffer */
2494 *tlvs_len -= (int)(ie - *tlvs);
2495 /* update the pointer to the start of the buffer */
2496 *tlvs = ie;
2497
2498 return false;
2499}
2500
3cb91f53 2501static struct brcmf_vs_tlv *
1a873342
HM
2502brcmf_find_wpaie(u8 *parse, u32 len)
2503{
2504 struct brcmf_tlv *ie;
2505
04b2312a 2506 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
1a873342
HM
2507 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2508 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2509 return (struct brcmf_vs_tlv *)ie;
2510 }
f8e4b412
AB
2511 return NULL;
2512}
2513
27a68fe3 2514static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
5b435de0 2515{
6ac4f4ed
AS
2516 struct net_device *ndev = cfg_to_ndev(cfg);
2517 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2518 struct brcmf_if *ifp = netdev_priv(ndev);
d34bf64f 2519 struct brcmf_bss_info_le *bi;
5b435de0 2520 struct brcmf_ssid *ssid;
f8e4b412 2521 struct brcmf_tlv *tim;
5b435de0
AS
2522 u16 beacon_interval;
2523 u8 dtim_period;
2524 size_t ie_len;
2525 u8 *ie;
2526 s32 err = 0;
2527
2528 WL_TRACE("Enter\n");
27a68fe3 2529 if (brcmf_is_ibssmode(cfg))
5b435de0
AS
2530 return err;
2531
06bb123e 2532 ssid = &profile->ssid;
5b435de0 2533
27a68fe3 2534 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2535 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2536 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0
AS
2537 if (err) {
2538 WL_ERR("Could not get bss info %d\n", err);
2539 goto update_bss_info_out;
2540 }
2541
27a68fe3
AS
2542 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2543 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2544 if (err)
2545 goto update_bss_info_out;
2546
2547 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2548 ie_len = le32_to_cpu(bi->ie_length);
2549 beacon_interval = le16_to_cpu(bi->beacon_period);
2550
f8e4b412 2551 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2552 if (tim)
2553 dtim_period = tim->data[1];
2554 else {
2555 /*
2556 * active scan was done so we could not get dtim
2557 * information out of probe response.
2558 * so we speficially query dtim information to dongle.
2559 */
2560 u32 var;
ac24be6f 2561 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0
AS
2562 if (err) {
2563 WL_ERR("wl dtim_assoc failed (%d)\n", err);
2564 goto update_bss_info_out;
2565 }
2566 dtim_period = (u8)var;
2567 }
2568
5b435de0
AS
2569update_bss_info_out:
2570 WL_TRACE("Exit");
2571 return err;
2572}
2573
27a68fe3 2574static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2575{
27a68fe3
AS
2576 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
2577 struct escan_info *escan = &cfg->escan_info;
5b435de0
AS
2578 struct brcmf_ssid ssid;
2579
c1179033 2580 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
27a68fe3 2581 if (cfg->iscan_on) {
5b435de0
AS
2582 iscan->state = WL_ISCAN_STATE_IDLE;
2583
2584 if (iscan->timer_on) {
2585 del_timer_sync(&iscan->timer);
2586 iscan->timer_on = 0;
2587 }
2588
2589 cancel_work_sync(&iscan->work);
2590
2591 /* Abort iscan running in FW */
2592 memset(&ssid, 0, sizeof(ssid));
2593 brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
108a4bee 2594
27a68fe3 2595 if (cfg->scan_request) {
108a4bee
AS
2596 /* Indidate scan abort to cfg80211 layer */
2597 WL_INFO("Terminating scan in progress\n");
27a68fe3
AS
2598 cfg80211_scan_done(cfg->scan_request, true);
2599 cfg->scan_request = NULL;
108a4bee 2600 }
5b435de0 2601 }
27a68fe3 2602 if (cfg->escan_on && cfg->scan_request) {
108a4bee 2603 escan->escan_state = WL_ESCAN_STATE_IDLE;
27a68fe3 2604 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
5b435de0 2605 }
c1179033
AS
2606 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2607 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2608}
2609
2610static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
2611 bool aborted)
2612{
27a68fe3
AS
2613 struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
2614 struct net_device *ndev = cfg_to_ndev(cfg);
5b435de0 2615
c1179033 2616 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
5b435de0
AS
2617 WL_ERR("Scan complete while device not scanning\n");
2618 return;
2619 }
27a68fe3 2620 if (cfg->scan_request) {
5b435de0
AS
2621 WL_SCAN("ISCAN Completed scan: %s\n",
2622 aborted ? "Aborted" : "Done");
27a68fe3 2623 cfg80211_scan_done(cfg->scan_request, aborted);
5b435de0 2624 brcmf_set_mpc(ndev, 1);
27a68fe3 2625 cfg->scan_request = NULL;
5b435de0 2626 }
27a68fe3 2627 cfg->iscan_kickstart = false;
5b435de0
AS
2628}
2629
2630static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
2631{
2632 if (iscan->state != WL_ISCAN_STATE_IDLE) {
2633 WL_SCAN("wake up iscan\n");
2634 schedule_work(&iscan->work);
2635 return 0;
2636 }
2637
2638 return -EIO;
2639}
2640
2641static s32
2642brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
2643 struct brcmf_scan_results **bss_list)
2644{
5b435de0
AS
2645 struct brcmf_scan_results *results;
2646 struct brcmf_scan_results_le *results_le;
2647 struct brcmf_iscan_results *list_buf;
2648 s32 err = 0;
2649
2650 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
2651 list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
2652 results = &list_buf->results;
2653 results_le = &list_buf->results_le;
81f5dcb8
HM
2654 results_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf));
2655 results_le->version = 0;
2656 results_le->count = 0;
5b435de0 2657
ac24be6f 2658 err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults",
81f5dcb8
HM
2659 iscan->scan_buf,
2660 sizeof(iscan->scan_buf));
5b435de0
AS
2661 if (err) {
2662 WL_ERR("error (%d)\n", err);
2663 return err;
2664 }
2665 results->buflen = le32_to_cpu(results_le->buflen);
2666 results->version = le32_to_cpu(results_le->version);
2667 results->count = le32_to_cpu(results_le->count);
2668 WL_SCAN("results->count = %d\n", results_le->count);
2669 WL_SCAN("results->buflen = %d\n", results_le->buflen);
2670 *status = le32_to_cpu(list_buf->status_le);
2671 WL_SCAN("status = %d\n", *status);
2672 *bss_list = results;
2673
2674 return err;
2675}
2676
27a68fe3 2677static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg)
5b435de0 2678{
27a68fe3 2679 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
5b435de0
AS
2680 s32 err = 0;
2681
2682 iscan->state = WL_ISCAN_STATE_IDLE;
27a68fe3 2683 brcmf_inform_bss(cfg);
5b435de0
AS
2684 brcmf_notify_iscan_complete(iscan, false);
2685
2686 return err;
2687}
2688
27a68fe3 2689static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg)
5b435de0 2690{
27a68fe3 2691 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
5b435de0
AS
2692 s32 err = 0;
2693
2694 /* Reschedule the timer */
2695 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2696 iscan->timer_on = 1;
2697
2698 return err;
2699}
2700
27a68fe3 2701static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg)
5b435de0 2702{
27a68fe3 2703 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
5b435de0
AS
2704 s32 err = 0;
2705
27a68fe3 2706 brcmf_inform_bss(cfg);
5b435de0
AS
2707 brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
2708 /* Reschedule the timer */
2709 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2710 iscan->timer_on = 1;
2711
2712 return err;
2713}
2714
27a68fe3 2715static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg)
5b435de0 2716{
27a68fe3 2717 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
5b435de0
AS
2718 s32 err = 0;
2719
2720 iscan->state = WL_ISCAN_STATE_IDLE;
2721 brcmf_notify_iscan_complete(iscan, true);
2722
2723 return err;
2724}
2725
2726static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
2727{
2728 struct brcmf_cfg80211_iscan_ctrl *iscan =
2729 container_of(work, struct brcmf_cfg80211_iscan_ctrl,
2730 work);
27a68fe3 2731 struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
5b435de0
AS
2732 struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
2733 u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
2734
2735 if (iscan->timer_on) {
2736 del_timer_sync(&iscan->timer);
2737 iscan->timer_on = 0;
2738 }
2739
27a68fe3 2740 if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) {
5b435de0
AS
2741 status = BRCMF_SCAN_RESULTS_ABORTED;
2742 WL_ERR("Abort iscan\n");
2743 }
2744
27a68fe3 2745 el->handler[status](cfg);
5b435de0
AS
2746}
2747
2748static void brcmf_iscan_timer(unsigned long data)
2749{
2750 struct brcmf_cfg80211_iscan_ctrl *iscan =
2751 (struct brcmf_cfg80211_iscan_ctrl *)data;
2752
2753 if (iscan) {
2754 iscan->timer_on = 0;
2755 WL_SCAN("timer expired\n");
2756 brcmf_wakeup_iscan(iscan);
2757 }
2758}
2759
27a68fe3 2760static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg)
5b435de0 2761{
27a68fe3 2762 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
5b435de0 2763
27a68fe3 2764 if (cfg->iscan_on) {
5b435de0
AS
2765 iscan->state = WL_ISCAN_STATE_IDLE;
2766 INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
2767 }
2768
2769 return 0;
2770}
2771
2772static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
2773{
2774 memset(el, 0, sizeof(*el));
2775 el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
2776 el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
2777 el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
2778 el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
2779 el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
2780}
2781
27a68fe3 2782static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg)
5b435de0 2783{
27a68fe3 2784 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
5b435de0
AS
2785 int err = 0;
2786
27a68fe3
AS
2787 if (cfg->iscan_on) {
2788 iscan->ndev = cfg_to_ndev(cfg);
5b435de0
AS
2789 brcmf_init_iscan_eloop(&iscan->el);
2790 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
2791 init_timer(&iscan->timer);
2792 iscan->timer.data = (unsigned long) iscan;
2793 iscan->timer.function = brcmf_iscan_timer;
27a68fe3 2794 err = brcmf_invoke_iscan(cfg);
5b435de0 2795 if (!err)
27a68fe3 2796 iscan->data = cfg;
5b435de0
AS
2797 }
2798
2799 return err;
2800}
2801
e756af5b
HM
2802static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2803{
27a68fe3
AS
2804 struct brcmf_cfg80211_info *cfg =
2805 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2806 escan_timeout_work);
2807
27a68fe3
AS
2808 brcmf_notify_escan_complete(cfg,
2809 cfg->escan_info.ndev, true, true);
e756af5b
HM
2810}
2811
2812static void brcmf_escan_timeout(unsigned long data)
2813{
27a68fe3
AS
2814 struct brcmf_cfg80211_info *cfg =
2815 (struct brcmf_cfg80211_info *)data;
e756af5b 2816
27a68fe3 2817 if (cfg->scan_request) {
e756af5b 2818 WL_ERR("timer expired\n");
27a68fe3
AS
2819 if (cfg->escan_on)
2820 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2821 }
2822}
2823
2824static s32
2825brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2826 struct brcmf_bss_info_le *bss_info_le)
2827{
2828 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2829 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2830 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2831 bss_info_le->SSID_len == bss->SSID_len &&
2832 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2833 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2834 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2835 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2836 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2837
e756af5b
HM
2838 /* preserve max RSSI if the measurements are
2839 * both on-channel or both off-channel
2840 */
029591f3 2841 if (bss_info_rssi > bss_rssi)
e756af5b
HM
2842 bss->RSSI = bss_info_le->RSSI;
2843 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2844 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2845 /* preserve the on-channel rssi measurement
2846 * if the new measurement is off channel
2847 */
2848 bss->RSSI = bss_info_le->RSSI;
2849 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2850 }
2851 return 1;
2852 }
2853 return 0;
2854}
2855
2856static s32
27a68fe3 2857brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,
e756af5b
HM
2858 struct net_device *ndev,
2859 const struct brcmf_event_msg *e, void *data)
2860{
2861 s32 status;
2862 s32 err = 0;
2863 struct brcmf_escan_result_le *escan_result_le;
2864 struct brcmf_bss_info_le *bss_info_le;
2865 struct brcmf_bss_info_le *bss = NULL;
2866 u32 bi_length;
2867 struct brcmf_scan_results *list;
2868 u32 i;
97ed15c7 2869 bool aborted;
e756af5b
HM
2870
2871 status = be32_to_cpu(e->status);
2872
27a68fe3 2873 if (!ndev || !cfg->escan_on ||
c1179033 2874 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e756af5b 2875 WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
27a68fe3 2876 ndev, cfg->escan_on,
c1179033 2877 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
e756af5b
HM
2878 return -EPERM;
2879 }
2880
2881 if (status == BRCMF_E_STATUS_PARTIAL) {
2882 WL_SCAN("ESCAN Partial result\n");
2883 escan_result_le = (struct brcmf_escan_result_le *) data;
2884 if (!escan_result_le) {
2885 WL_ERR("Invalid escan result (NULL pointer)\n");
2886 goto exit;
2887 }
27a68fe3 2888 if (!cfg->scan_request) {
e756af5b
HM
2889 WL_SCAN("result without cfg80211 request\n");
2890 goto exit;
2891 }
2892
2893 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2894 WL_ERR("Invalid bss_count %d: ignoring\n",
2895 escan_result_le->bss_count);
2896 goto exit;
2897 }
2898 bss_info_le = &escan_result_le->bss_info_le;
2899
2900 bi_length = le32_to_cpu(bss_info_le->length);
2901 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2902 WL_ESCAN_RESULTS_FIXED_SIZE)) {
2903 WL_ERR("Invalid bss_info length %d: ignoring\n",
2904 bi_length);
2905 goto exit;
2906 }
2907
27a68fe3 2908 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2909 BIT(NL80211_IFTYPE_ADHOC))) {
2910 if (le16_to_cpu(bss_info_le->capability) &
2911 WLAN_CAPABILITY_IBSS) {
2912 WL_ERR("Ignoring IBSS result\n");
2913 goto exit;
2914 }
2915 }
2916
2917 list = (struct brcmf_scan_results *)
27a68fe3 2918 cfg->escan_info.escan_buf;
e756af5b
HM
2919 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2920 WL_ERR("Buffer is too small: ignoring\n");
2921 goto exit;
2922 }
2923
2924 for (i = 0; i < list->count; i++) {
2925 bss = bss ? (struct brcmf_bss_info_le *)
2926 ((unsigned char *)bss +
2927 le32_to_cpu(bss->length)) : list->bss_info_le;
2928 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2929 goto exit;
2930 }
27a68fe3 2931 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2932 bss_info_le, bi_length);
2933 list->version = le32_to_cpu(bss_info_le->version);
2934 list->buflen += bi_length;
2935 list->count++;
2936 } else {
27a68fe3
AS
2937 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2938 if (cfg->scan_request) {
2939 cfg->bss_list = (struct brcmf_scan_results *)
2940 cfg->escan_info.escan_buf;
2941 brcmf_inform_bss(cfg);
97ed15c7 2942 aborted = status != BRCMF_E_STATUS_SUCCESS;
27a68fe3 2943 brcmf_notify_escan_complete(cfg, ndev, aborted,
97ed15c7 2944 false);
e756af5b
HM
2945 } else
2946 WL_ERR("Unexpected scan result 0x%x\n", status);
2947 }
2948exit:
2949 return err;
2950}
2951
27a68fe3 2952static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b
HM
2953{
2954
27a68fe3
AS
2955 if (cfg->escan_on) {
2956 cfg->el.handler[BRCMF_E_ESCAN_RESULT] =
e756af5b 2957 brcmf_cfg80211_escan_handler;
27a68fe3 2958 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
e756af5b 2959 /* Init scan_timeout timer */
27a68fe3
AS
2960 init_timer(&cfg->escan_timeout);
2961 cfg->escan_timeout.data = (unsigned long) cfg;
2962 cfg->escan_timeout.function = brcmf_escan_timeout;
2963 INIT_WORK(&cfg->escan_timeout_work,
e756af5b
HM
2964 brcmf_cfg80211_escan_timeout_worker);
2965 }
2966}
2967
5addc0de 2968static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2969{
2970 if (ms < 1000 / HZ) {
2971 cond_resched();
2972 mdelay(ms);
2973 } else {
2974 msleep(ms);
2975 }
2976}
2977
2978static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2979{
27a68fe3 2980 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2981 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
2982
2983 /*
c1179033 2984 * Check for BRCMF_VIF_STATUS_READY before any function call which
5b435de0
AS
2985 * could result is bus access. Don't block the resume for
2986 * any driver error conditions
2987 */
2988 WL_TRACE("Enter\n");
2989
ce81e317 2990 if (check_vif_up(ifp->vif))
823e1c81 2991 brcmf_invoke_iscan(cfg);
5b435de0
AS
2992
2993 WL_TRACE("Exit\n");
2994 return 0;
2995}
2996
2997static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2998 struct cfg80211_wowlan *wow)
2999{
27a68fe3
AS
3000 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3001 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 3002 struct brcmf_cfg80211_vif *vif;
5b435de0
AS
3003
3004 WL_TRACE("Enter\n");
3005
3006 /*
7d641072
AS
3007 * if the primary net_device is not READY there is nothing
3008 * we can do but pray resume goes smoothly.
5b435de0 3009 */
7d641072
AS
3010 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
3011 if (!check_vif_up(vif))
3012 goto exit;
5b435de0 3013
7d641072
AS
3014 list_for_each_entry(vif, &cfg->vif_list, list) {
3015 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3016 continue;
5b435de0 3017 /*
7d641072
AS
3018 * While going to suspend if associated with AP disassociate
3019 * from AP to save power while system is in suspended state
5b435de0 3020 */
7d641072
AS
3021 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
3022 test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
3023 WL_INFO("Disassociating from AP before suspend\n");
3024 brcmf_link_down(cfg);
3025
3026 /* Make sure WPA_Supplicant receives all the event
3027 * generated due to DISASSOC call to the fw to keep
3028 * the state fw and WPA_Supplicant state consistent
3029 */
3030 brcmf_delay(500);
3031 }
5b435de0
AS
3032 }
3033
7d641072
AS
3034 /* end any scanning */
3035 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 3036 brcmf_abort_scanning(cfg);
5b435de0
AS
3037
3038 /* Turn off watchdog timer */
7d641072 3039 brcmf_set_mpc(ndev, 1);
5b435de0 3040
7d641072 3041exit:
5b435de0 3042 WL_TRACE("Exit\n");
7d641072
AS
3043 /* clear any scanning activity */
3044 cfg->scan_status = 0;
5b435de0
AS
3045 return 0;
3046}
3047
5b435de0
AS
3048static __used s32
3049brcmf_update_pmklist(struct net_device *ndev,
3050 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
3051{
3052 int i, j;
40c8e95a 3053 int pmkid_len;
5b435de0 3054
40c8e95a
AS
3055 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
3056
3057 WL_CONN("No of elements %d\n", pmkid_len);
3058 for (i = 0; i < pmkid_len; i++) {
5b435de0
AS
3059 WL_CONN("PMKID[%d]: %pM =\n", i,
3060 &pmk_list->pmkids.pmkid[i].BSSID);
3061 for (j = 0; j < WLAN_PMKID_LEN; j++)
3062 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
3063 }
3064
3065 if (!err)
ac24be6f
AS
3066 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
3067 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
3068
3069 return err;
3070}
3071
3072static s32
3073brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3074 struct cfg80211_pmksa *pmksa)
3075{
27a68fe3 3076 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3077 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3078 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
3079 s32 err = 0;
3080 int i;
40c8e95a 3081 int pmkid_len;
5b435de0
AS
3082
3083 WL_TRACE("Enter\n");
ce81e317 3084 if (!check_vif_up(ifp->vif))
5b435de0
AS
3085 return -EIO;
3086
40c8e95a
AS
3087 pmkid_len = le32_to_cpu(pmkids->npmkid);
3088 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
3089 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
3090 break;
3091 if (i < WL_NUM_PMKIDS_MAX) {
3092 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
3093 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
3094 if (i == pmkid_len) {
3095 pmkid_len++;
3096 pmkids->npmkid = cpu_to_le32(pmkid_len);
3097 }
5b435de0
AS
3098 } else
3099 err = -EINVAL;
3100
3101 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
40c8e95a 3102 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 3103 for (i = 0; i < WLAN_PMKID_LEN; i++)
40c8e95a 3104 WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 3105
27a68fe3 3106 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3107
3108 WL_TRACE("Exit\n");
3109 return err;
3110}
3111
3112static s32
3113brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3114 struct cfg80211_pmksa *pmksa)
3115{
27a68fe3 3116 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3117 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3118 struct pmkid_list pmkid;
3119 s32 err = 0;
40c8e95a 3120 int i, pmkid_len;
5b435de0
AS
3121
3122 WL_TRACE("Enter\n");
ce81e317 3123 if (!check_vif_up(ifp->vif))
5b435de0
AS
3124 return -EIO;
3125
3126 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
3127 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
3128
3129 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3130 &pmkid.pmkid[0].BSSID);
3131 for (i = 0; i < WLAN_PMKID_LEN; i++)
3132 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
3133
27a68fe3 3134 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 3135 for (i = 0; i < pmkid_len; i++)
5b435de0 3136 if (!memcmp
27a68fe3 3137 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
3138 ETH_ALEN))
3139 break;
3140
40c8e95a
AS
3141 if ((pmkid_len > 0)
3142 && (i < pmkid_len)) {
27a68fe3 3143 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 3144 sizeof(struct pmkid));
40c8e95a 3145 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
3146 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
3147 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 3148 ETH_ALEN);
27a68fe3
AS
3149 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
3150 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
3151 WLAN_PMKID_LEN);
3152 }
27a68fe3 3153 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
3154 } else
3155 err = -EINVAL;
3156
27a68fe3 3157 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3158
3159 WL_TRACE("Exit\n");
3160 return err;
3161
3162}
3163
3164static s32
3165brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3166{
27a68fe3 3167 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3168 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3169 s32 err = 0;
3170
3171 WL_TRACE("Enter\n");
ce81e317 3172 if (!check_vif_up(ifp->vif))
5b435de0
AS
3173 return -EIO;
3174
27a68fe3
AS
3175 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
3176 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3177
3178 WL_TRACE("Exit\n");
3179 return err;
3180
3181}
3182
e5806072
AS
3183/*
3184 * PFN result doesn't have all the info which are
3185 * required by the supplicant
3186 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3187 * via wl_inform_single_bss in the required format. Escan does require the
3188 * scan request in the form of cfg80211_scan_request. For timebeing, create
3189 * cfg80211_scan_request one out of the received PNO event.
3190 */
3191static s32
27a68fe3 3192brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
e5806072
AS
3193 struct net_device *ndev,
3194 const struct brcmf_event_msg *e, void *data)
3195{
3196 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3197 struct cfg80211_scan_request *request = NULL;
3198 struct cfg80211_ssid *ssid = NULL;
3199 struct ieee80211_channel *channel = NULL;
27a68fe3 3200 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
3201 int err = 0;
3202 int channel_req = 0;
3203 int band = 0;
3204 struct brcmf_pno_scanresults_le *pfn_result;
3205 u32 result_count;
3206 u32 status;
3207
3208 WL_SCAN("Enter\n");
3209
3210 if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
3211 WL_SCAN("PFN NET LOST event. Do Nothing\n");
3212 return 0;
3213 }
3214
3215 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3216 result_count = le32_to_cpu(pfn_result->count);
3217 status = le32_to_cpu(pfn_result->status);
3218
3219 /*
3220 * PFN event is limited to fit 512 bytes so we may get
3221 * multiple NET_FOUND events. For now place a warning here.
3222 */
3223 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3224 WL_SCAN("PFN NET FOUND event. count: %d\n", result_count);
3225 if (result_count > 0) {
3226 int i;
3227
3228 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
3229 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3230 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
3231 if (!request || !ssid || !channel) {
3232 err = -ENOMEM;
3233 goto out_err;
3234 }
3235
3236 request->wiphy = wiphy;
3237 data += sizeof(struct brcmf_pno_scanresults_le);
3238 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3239
3240 for (i = 0; i < result_count; i++) {
3241 netinfo = &netinfo_start[i];
3242 if (!netinfo) {
3243 WL_ERR("Invalid netinfo ptr. index: %d\n", i);
3244 err = -EINVAL;
3245 goto out_err;
3246 }
3247
3248 WL_SCAN("SSID:%s Channel:%d\n",
3249 netinfo->SSID, netinfo->channel);
3250 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3251 ssid[i].ssid_len = netinfo->SSID_len;
3252 request->n_ssids++;
3253
3254 channel_req = netinfo->channel;
3255 if (channel_req <= CH_MAX_2G_CHANNEL)
3256 band = NL80211_BAND_2GHZ;
3257 else
3258 band = NL80211_BAND_5GHZ;
3259 channel[i].center_freq =
3260 ieee80211_channel_to_frequency(channel_req,
3261 band);
3262 channel[i].band = band;
3263 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3264 request->channels[i] = &channel[i];
3265 request->n_channels++;
3266 }
3267
3268 /* assign parsed ssid array */
3269 if (request->n_ssids)
3270 request->ssids = &ssid[0];
3271
c1179033 3272 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 3273 /* Abort any on-going scan */
27a68fe3 3274 brcmf_abort_scanning(cfg);
e5806072
AS
3275 }
3276
c1179033 3277 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 3278 err = brcmf_do_escan(cfg, wiphy, ndev, request);
e5806072 3279 if (err) {
c1179033 3280 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
3281 goto out_err;
3282 }
27a68fe3
AS
3283 cfg->sched_escan = true;
3284 cfg->scan_request = request;
e5806072
AS
3285 } else {
3286 WL_ERR("FALSE PNO Event. (pfn_count == 0)\n");
3287 goto out_err;
3288 }
3289
3290 kfree(ssid);
3291 kfree(channel);
3292 kfree(request);
3293 return 0;
3294
3295out_err:
3296 kfree(ssid);
3297 kfree(channel);
3298 kfree(request);
3299 cfg80211_sched_scan_stopped(wiphy);
3300 return err;
3301}
3302
3303#ifndef CONFIG_BRCMISCAN
3304static int brcmf_dev_pno_clean(struct net_device *ndev)
3305{
e5806072
AS
3306 int ret;
3307
3308 /* Disable pfn */
ac24be6f 3309 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3310 if (ret == 0) {
3311 /* clear pfn */
ac24be6f
AS
3312 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3313 NULL, 0);
e5806072
AS
3314 }
3315 if (ret < 0)
3316 WL_ERR("failed code %d\n", ret);
3317
3318 return ret;
3319}
3320
3321static int brcmf_dev_pno_config(struct net_device *ndev)
3322{
3323 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3324
3325 memset(&pfn_param, 0, sizeof(pfn_param));
3326 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3327
3328 /* set extra pno params */
3329 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3330 pfn_param.repeat = BRCMF_PNO_REPEAT;
3331 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3332
3333 /* set up pno scan fr */
3334 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3335
ac24be6f
AS
3336 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3337 &pfn_param, sizeof(pfn_param));
e5806072
AS
3338}
3339
3340static int
3341brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3342 struct net_device *ndev,
3343 struct cfg80211_sched_scan_request *request)
3344{
c1179033 3345 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3346 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3347 struct brcmf_pno_net_param_le pfn;
3348 int i;
3349 int ret = 0;
3350
3351 WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n",
3352 request->n_match_sets, request->n_ssids);
c1179033
AS
3353 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3354 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3355 return -EAGAIN;
3356 }
3357
3358 if (!request || !request->n_ssids || !request->n_match_sets) {
3359 WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
9495b31a 3360 request ? request->n_ssids : 0);
e5806072
AS
3361 return -EINVAL;
3362 }
3363
3364 if (request->n_ssids > 0) {
3365 for (i = 0; i < request->n_ssids; i++) {
3366 /* Active scan req for ssids */
3367 WL_SCAN(">>> Active scan req for ssid (%s)\n",
3368 request->ssids[i].ssid);
3369
3370 /*
3371 * match_set ssids is a supert set of n_ssid list,
3372 * so we need not add these set seperately.
3373 */
3374 }
3375 }
3376
3377 if (request->n_match_sets > 0) {
3378 /* clean up everything */
3379 ret = brcmf_dev_pno_clean(ndev);
3380 if (ret < 0) {
3381 WL_ERR("failed error=%d\n", ret);
3382 return ret;
3383 }
3384
3385 /* configure pno */
3386 ret = brcmf_dev_pno_config(ndev);
3387 if (ret < 0) {
3388 WL_ERR("PNO setup failed!! ret=%d\n", ret);
3389 return -EINVAL;
3390 }
3391
3392 /* configure each match set */
3393 for (i = 0; i < request->n_match_sets; i++) {
3394 struct cfg80211_ssid *ssid;
3395 u32 ssid_len;
3396
3397 ssid = &request->match_sets[i].ssid;
3398 ssid_len = ssid->ssid_len;
3399
3400 if (!ssid_len) {
3401 WL_ERR("skip broadcast ssid\n");
3402 continue;
3403 }
3404 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3405 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3406 pfn.wsec = cpu_to_le32(0);
3407 pfn.infra = cpu_to_le32(1);
3408 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3409 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3410 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3411 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3412 sizeof(pfn));
e5806072
AS
3413 WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
3414 ret == 0 ? "set" : "failed",
3415 ssid->ssid);
3416 }
3417 /* Enable the PNO */
c1179033 3418 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
e5806072
AS
3419 WL_ERR("PNO enable failed!! ret=%d\n", ret);
3420 return -EINVAL;
3421 }
3422 } else {
3423 return -EINVAL;
3424 }
3425
3426 return 0;
3427}
3428
3429static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3430 struct net_device *ndev)
3431{
27a68fe3 3432 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072
AS
3433
3434 WL_SCAN("enter\n");
3435 brcmf_dev_pno_clean(ndev);
27a68fe3
AS
3436 if (cfg->sched_escan)
3437 brcmf_notify_escan_complete(cfg, ndev, true, true);
e5806072
AS
3438 return 0;
3439}
3440#endif /* CONFIG_BRCMISCAN */
3441
cbaa177d
AS
3442#ifdef CONFIG_NL80211_TESTMODE
3443static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3444{
27a68fe3 3445 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3446 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3447 struct brcmf_dcmd *dcmd = data;
3448 struct sk_buff *reply;
3449 int ret;
3450
f368a5b6
HM
3451 WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3452 dcmd->buf, dcmd->len);
3453
3454 if (dcmd->set)
ac24be6f
AS
3455 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3456 dcmd->buf, dcmd->len);
f368a5b6 3457 else
ac24be6f
AS
3458 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3459 dcmd->buf, dcmd->len);
cbaa177d
AS
3460 if (ret == 0) {
3461 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3462 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3463 ret = cfg80211_testmode_reply(reply);
3464 }
3465 return ret;
3466}
3467#endif
3468
1a873342
HM
3469static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
3470{
ac24be6f 3471 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3472 s32 err;
3473
3474 /* set auth */
ac24be6f 3475 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342
HM
3476 if (err < 0) {
3477 WL_ERR("auth error %d\n", err);
3478 return err;
3479 }
3480 /* set wsec */
ac24be6f 3481 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342
HM
3482 if (err < 0) {
3483 WL_ERR("wsec error %d\n", err);
3484 return err;
3485 }
3486 /* set upper-layer auth */
ac24be6f 3487 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342
HM
3488 if (err < 0) {
3489 WL_ERR("wpa_auth error %d\n", err);
3490 return err;
3491 }
3492
3493 return 0;
3494}
3495
3496static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3497{
3498 if (is_rsn_ie)
3499 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3500
3501 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3502}
3503
3504static s32
3505brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
3506 bool is_rsn_ie, s32 bssidx)
3507{
ac24be6f 3508 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3509 u32 auth = 0; /* d11 open authentication */
3510 u16 count;
3511 s32 err = 0;
3512 s32 len = 0;
3513 u32 i;
3514 u32 wsec;
3515 u32 pval = 0;
3516 u32 gval = 0;
3517 u32 wpa_auth = 0;
3518 u32 offset;
3519 u8 *data;
3520 u16 rsn_cap;
3521 u32 wme_bss_disable;
3522
3523 WL_TRACE("Enter\n");
3524 if (wpa_ie == NULL)
3525 goto exit;
3526
3527 len = wpa_ie->len + TLV_HDR_LEN;
3528 data = (u8 *)wpa_ie;
3529 offset = 0;
3530 if (!is_rsn_ie)
3531 offset += VS_IE_FIXED_HDR_LEN;
3532 offset += WPA_IE_VERSION_LEN;
3533
3534 /* check for multicast cipher suite */
3535 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3536 err = -EINVAL;
3537 WL_ERR("no multicast cipher suite\n");
3538 goto exit;
3539 }
3540
3541 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3542 err = -EINVAL;
3543 WL_ERR("ivalid OUI\n");
3544 goto exit;
3545 }
3546 offset += TLV_OUI_LEN;
3547
3548 /* pick up multicast cipher */
3549 switch (data[offset]) {
3550 case WPA_CIPHER_NONE:
3551 gval = 0;
3552 break;
3553 case WPA_CIPHER_WEP_40:
3554 case WPA_CIPHER_WEP_104:
3555 gval = WEP_ENABLED;
3556 break;
3557 case WPA_CIPHER_TKIP:
3558 gval = TKIP_ENABLED;
3559 break;
3560 case WPA_CIPHER_AES_CCM:
3561 gval = AES_ENABLED;
3562 break;
3563 default:
3564 err = -EINVAL;
3565 WL_ERR("Invalid multi cast cipher info\n");
3566 goto exit;
3567 }
3568
3569 offset++;
3570 /* walk thru unicast cipher list and pick up what we recognize */
3571 count = data[offset] + (data[offset + 1] << 8);
3572 offset += WPA_IE_SUITE_COUNT_LEN;
3573 /* Check for unicast suite(s) */
3574 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3575 err = -EINVAL;
3576 WL_ERR("no unicast cipher suite\n");
3577 goto exit;
3578 }
3579 for (i = 0; i < count; i++) {
3580 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3581 err = -EINVAL;
3582 WL_ERR("ivalid OUI\n");
3583 goto exit;
3584 }
3585 offset += TLV_OUI_LEN;
3586 switch (data[offset]) {
3587 case WPA_CIPHER_NONE:
3588 break;
3589 case WPA_CIPHER_WEP_40:
3590 case WPA_CIPHER_WEP_104:
3591 pval |= WEP_ENABLED;
3592 break;
3593 case WPA_CIPHER_TKIP:
3594 pval |= TKIP_ENABLED;
3595 break;
3596 case WPA_CIPHER_AES_CCM:
3597 pval |= AES_ENABLED;
3598 break;
3599 default:
3600 WL_ERR("Ivalid unicast security info\n");
3601 }
3602 offset++;
3603 }
3604 /* walk thru auth management suite list and pick up what we recognize */
3605 count = data[offset] + (data[offset + 1] << 8);
3606 offset += WPA_IE_SUITE_COUNT_LEN;
3607 /* Check for auth key management suite(s) */
3608 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3609 err = -EINVAL;
3610 WL_ERR("no auth key mgmt suite\n");
3611 goto exit;
3612 }
3613 for (i = 0; i < count; i++) {
3614 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3615 err = -EINVAL;
3616 WL_ERR("ivalid OUI\n");
3617 goto exit;
3618 }
3619 offset += TLV_OUI_LEN;
3620 switch (data[offset]) {
3621 case RSN_AKM_NONE:
3622 WL_TRACE("RSN_AKM_NONE\n");
3623 wpa_auth |= WPA_AUTH_NONE;
3624 break;
3625 case RSN_AKM_UNSPECIFIED:
3626 WL_TRACE("RSN_AKM_UNSPECIFIED\n");
3627 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3628 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3629 break;
3630 case RSN_AKM_PSK:
3631 WL_TRACE("RSN_AKM_PSK\n");
3632 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3633 (wpa_auth |= WPA_AUTH_PSK);
3634 break;
3635 default:
3636 WL_ERR("Ivalid key mgmt info\n");
3637 }
3638 offset++;
3639 }
3640
3641 if (is_rsn_ie) {
3642 wme_bss_disable = 1;
3643 if ((offset + RSN_CAP_LEN) <= len) {
3644 rsn_cap = data[offset] + (data[offset + 1] << 8);
3645 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3646 wme_bss_disable = 0;
3647 }
3648 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3649 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3650 wme_bss_disable);
1a873342
HM
3651 if (err < 0) {
3652 WL_ERR("wme_bss_disable error %d\n", err);
3653 goto exit;
3654 }
3655 }
3656 /* FOR WPS , set SES_OW_ENABLED */
3657 wsec = (pval | gval | SES_OW_ENABLED);
3658
3659 /* set auth */
ac24be6f 3660 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342
HM
3661 if (err < 0) {
3662 WL_ERR("auth error %d\n", err);
3663 goto exit;
3664 }
3665 /* set wsec */
ac24be6f 3666 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342
HM
3667 if (err < 0) {
3668 WL_ERR("wsec error %d\n", err);
3669 goto exit;
3670 }
3671 /* set upper-layer auth */
ac24be6f 3672 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342
HM
3673 if (err < 0) {
3674 WL_ERR("wpa_auth error %d\n", err);
3675 goto exit;
3676 }
3677
3678exit:
3679 return err;
3680}
3681
3682static s32
3683brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len,
3684 struct parsed_vndr_ies *vndr_ies)
3685{
3686 s32 err = 0;
3687 struct brcmf_vs_tlv *vndrie;
3688 struct brcmf_tlv *ie;
3689 struct parsed_vndr_ie_info *parsed_info;
3690 s32 remaining_len;
3691
3692 remaining_len = (s32)vndr_ie_len;
3693 memset(vndr_ies, 0, sizeof(*vndr_ies));
3694
3695 ie = (struct brcmf_tlv *)vndr_ie_buf;
3696 while (ie) {
3697 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3698 goto next;
3699 vndrie = (struct brcmf_vs_tlv *)ie;
3700 /* len should be bigger than OUI length + one */
3701 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
3702 WL_ERR("invalid vndr ie. length is too small %d\n",
3703 vndrie->len);
3704 goto next;
3705 }
3706 /* if wpa or wme ie, do not add ie */
3707 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3708 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3709 (vndrie->oui_type == WME_OUI_TYPE))) {
3710 WL_TRACE("Found WPA/WME oui. Do not add it\n");
3711 goto next;
3712 }
3713
3714 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3715
3716 /* save vndr ie information */
3717 parsed_info->ie_ptr = (char *)vndrie;
3718 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3719 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3720
3721 vndr_ies->count++;
3722
3723 WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n",
3724 parsed_info->vndrie.oui[0],
3725 parsed_info->vndrie.oui[1],
3726 parsed_info->vndrie.oui[2],
3727 parsed_info->vndrie.oui_type);
3728
3729 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3730 break;
3731next:
3732 remaining_len -= ie->len;
3733 if (remaining_len <= 2)
3734 ie = NULL;
3735 else
3736 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len);
3737 }
3738 return err;
3739}
3740
3741static u32
3742brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3743{
3744
3745 __le32 iecount_le;
3746 __le32 pktflag_le;
3747
3748 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3749 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3750
3751 iecount_le = cpu_to_le32(1);
3752 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3753
3754 pktflag_le = cpu_to_le32(pktflag);
3755 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3756
3757 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3758
3759 return ie_len + VNDR_IE_HDR_SIZE;
3760}
3761
3cb91f53 3762static s32
27a68fe3 3763brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
1d4fd8d7 3764 struct net_device *ndev, s32 pktflag,
1a873342
HM
3765 u8 *vndr_ie_buf, u32 vndr_ie_len)
3766{
c1179033 3767 struct brcmf_if *ifp = netdev_priv(ndev);
8ff5dc92 3768 struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
1a873342
HM
3769 s32 err = 0;
3770 u8 *iovar_ie_buf;
3771 u8 *curr_ie_buf;
3772 u8 *mgmt_ie_buf = NULL;
3e4f319d 3773 int mgmt_ie_buf_len;
81118d16 3774 u32 *mgmt_ie_len;
1a873342
HM
3775 u32 del_add_ie_buf_len = 0;
3776 u32 total_ie_buf_len = 0;
3777 u32 parsed_ie_buf_len = 0;
3778 struct parsed_vndr_ies old_vndr_ies;
3779 struct parsed_vndr_ies new_vndr_ies;
3780 struct parsed_vndr_ie_info *vndrie_info;
3781 s32 i;
3782 u8 *ptr;
3e4f319d 3783 int remained_buf_len;
1a873342 3784
6ac4f4ed
AS
3785 WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
3786 brcmf_ndev_bssidx(ndev), pktflag);
1a873342
HM
3787 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3788 if (!iovar_ie_buf)
3789 return -ENOMEM;
3790 curr_ie_buf = iovar_ie_buf;
8ff5dc92 3791 if (ifp->vif->mode == WL_MODE_AP) {
1a873342
HM
3792 switch (pktflag) {
3793 case VNDR_IE_PRBRSP_FLAG:
8ff5dc92
AS
3794 mgmt_ie_buf = saved_ie->probe_res_ie;
3795 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3796 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
1a873342
HM
3797 break;
3798 case VNDR_IE_BEACON_FLAG:
8ff5dc92
AS
3799 mgmt_ie_buf = saved_ie->beacon_ie;
3800 mgmt_ie_len = &saved_ie->beacon_ie_len;
3801 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
1a873342
HM
3802 break;
3803 default:
3804 err = -EPERM;
3805 WL_ERR("not suitable type\n");
3806 goto exit;
3807 }
1a873342
HM
3808 } else {
3809 err = -EPERM;
3810 WL_ERR("not suitable type\n");
3811 goto exit;
3812 }
3813
3814 if (vndr_ie_len > mgmt_ie_buf_len) {
3815 err = -ENOMEM;
3816 WL_ERR("extra IE size too big\n");
3817 goto exit;
3818 }
3819
3820 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3821 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3822 ptr = curr_ie_buf;
3823 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3824 for (i = 0; i < new_vndr_ies.count; i++) {
3825 vndrie_info = &new_vndr_ies.ie_info[i];
3826 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3827 vndrie_info->ie_len);
3828 parsed_ie_buf_len += vndrie_info->ie_len;
3829 }
3830 }
3831
3832 if (mgmt_ie_buf != NULL) {
3833 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3834 (memcmp(mgmt_ie_buf, curr_ie_buf,
3835 parsed_ie_buf_len) == 0)) {
3836 WL_TRACE("Previous mgmt IE is equals to current IE");
3837 goto exit;
3838 }
3839
3840 /* parse old vndr_ie */
3841 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3842
3843 /* make a command to delete old ie */
3844 for (i = 0; i < old_vndr_ies.count; i++) {
3845 vndrie_info = &old_vndr_ies.ie_info[i];
3846
3847 WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3848 vndrie_info->vndrie.id,
3849 vndrie_info->vndrie.len,
3850 vndrie_info->vndrie.oui[0],
3851 vndrie_info->vndrie.oui[1],
3852 vndrie_info->vndrie.oui[2]);
3853
3854 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3855 vndrie_info->ie_ptr,
3856 vndrie_info->ie_len,
3857 "del");
3858 curr_ie_buf += del_add_ie_buf_len;
3859 total_ie_buf_len += del_add_ie_buf_len;
3860 }
3861 }
3862
3863 *mgmt_ie_len = 0;
3864 /* Add if there is any extra IE */
3865 if (mgmt_ie_buf && parsed_ie_buf_len) {
3866 ptr = mgmt_ie_buf;
3867
3868 remained_buf_len = mgmt_ie_buf_len;
3869
3870 /* make a command to add new ie */
3871 for (i = 0; i < new_vndr_ies.count; i++) {
3872 vndrie_info = &new_vndr_ies.ie_info[i];
3873
3874 WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3875 vndrie_info->vndrie.id,
3876 vndrie_info->vndrie.len,
3877 vndrie_info->vndrie.oui[0],
3878 vndrie_info->vndrie.oui[1],
3879 vndrie_info->vndrie.oui[2]);
3880
3881 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3882 vndrie_info->ie_ptr,
3883 vndrie_info->ie_len,
3884 "add");
3885 /* verify remained buf size before copy data */
3886 remained_buf_len -= vndrie_info->ie_len;
3887 if (remained_buf_len < 0) {
3888 WL_ERR("no space in mgmt_ie_buf: len left %d",
3889 remained_buf_len);
3890 break;
3891 }
3892
3893 /* save the parsed IE in wl struct */
3894 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3895 vndrie_info->ie_len);
3896 *mgmt_ie_len += vndrie_info->ie_len;
3897
3898 curr_ie_buf += del_add_ie_buf_len;
3899 total_ie_buf_len += del_add_ie_buf_len;
3900 }
3901 }
3902 if (total_ie_buf_len) {
c1179033 3903 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3904 total_ie_buf_len);
1a873342
HM
3905 if (err)
3906 WL_ERR("vndr ie set error : %d\n", err);
3907 }
3908
3909exit:
3910 kfree(iovar_ie_buf);
3911 return err;
3912}
3913
3914static s32
3915brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3916 struct cfg80211_ap_settings *settings)
3917{
3918 s32 ie_offset;
ac24be6f 3919 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3920 struct brcmf_tlv *ssid_ie;
3921 struct brcmf_ssid_le ssid_le;
1a873342
HM
3922 s32 err = -EPERM;
3923 struct brcmf_tlv *rsn_ie;
3924 struct brcmf_vs_tlv *wpa_ie;
3925 struct brcmf_join_params join_params;
27a68fe3 3926 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342
HM
3927 s32 bssidx = 0;
3928
3929 WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3930 settings->channel_type, settings->beacon_interval,
3931 settings->dtim_period);
3932 WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n",
3933 settings->ssid, settings->ssid_len, settings->auth_type,
3934 settings->inactivity_timeout);
3935
c1179033 3936 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
1a873342
HM
3937 WL_ERR("Not in AP creation mode\n");
3938 return -EPERM;
3939 }
3940
3941 memset(&ssid_le, 0, sizeof(ssid_le));
3942 if (settings->ssid == NULL || settings->ssid_len == 0) {
3943 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3944 ssid_ie = brcmf_parse_tlvs(
3945 (u8 *)&settings->beacon.head[ie_offset],
3946 settings->beacon.head_len - ie_offset,
3947 WLAN_EID_SSID);
3948 if (!ssid_ie)
3949 return -EINVAL;
3950
3951 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3952 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
3953 WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID);
3954 } else {
3955 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3956 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3957 }
3958
3959 brcmf_set_mpc(ndev, 0);
ac24be6f 3960 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
1a873342
HM
3961 if (err < 0) {
3962 WL_ERR("BRCMF_C_DOWN error %d\n", err);
3963 goto exit;
3964 }
ac24be6f 3965 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342
HM
3966 if (err < 0) {
3967 WL_ERR("SET INFRA error %d\n", err);
3968 goto exit;
3969 }
ac24be6f 3970 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
1a873342
HM
3971 if (err < 0) {
3972 WL_ERR("setting AP mode failed %d\n", err);
3973 goto exit;
3974 }
3975
3976 /* find the RSN_IE */
3977 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3978 settings->beacon.tail_len, WLAN_EID_RSN);
3979
3980 /* find the WPA_IE */
3981 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3982 settings->beacon.tail_len);
3983
1a873342
HM
3984 if ((wpa_ie != NULL || rsn_ie != NULL)) {
3985 WL_TRACE("WPA(2) IE is found\n");
3986 if (wpa_ie != NULL) {
3987 /* WPA IE */
3988 err = brcmf_configure_wpaie(ndev, wpa_ie, false,
3989 bssidx);
3990 if (err < 0)
3991 goto exit;
1a873342
HM
3992 } else {
3993 /* RSN IE */
3994 err = brcmf_configure_wpaie(ndev,
3995 (struct brcmf_vs_tlv *)rsn_ie, true, bssidx);
3996 if (err < 0)
3997 goto exit;
1a873342 3998 }
1a873342
HM
3999 } else {
4000 WL_TRACE("No WPA(2) IEs found\n");
4001 brcmf_configure_opensecurity(ndev, bssidx);
1a873342
HM
4002 }
4003 /* Set Beacon IEs to FW */
1d4fd8d7 4004 err = brcmf_set_management_ie(cfg, ndev,
1a873342
HM
4005 VNDR_IE_BEACON_FLAG,
4006 (u8 *)settings->beacon.tail,
4007 settings->beacon.tail_len);
4008 if (err)
4009 WL_ERR("Set Beacon IE Failed\n");
4010 else
4011 WL_TRACE("Applied Vndr IEs for Beacon\n");
4012
4013 /* Set Probe Response IEs to FW */
1d4fd8d7 4014 err = brcmf_set_management_ie(cfg, ndev,
1a873342
HM
4015 VNDR_IE_PRBRSP_FLAG,
4016 (u8 *)settings->beacon.proberesp_ies,
4017 settings->beacon.proberesp_ies_len);
4018 if (err)
4019 WL_ERR("Set Probe Resp IE Failed\n");
4020 else
4021 WL_TRACE("Applied Vndr IEs for Probe Resp\n");
4022
4023 if (settings->beacon_interval) {
ac24be6f 4024 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 4025 settings->beacon_interval);
1a873342
HM
4026 if (err < 0) {
4027 WL_ERR("Beacon Interval Set Error, %d\n", err);
4028 goto exit;
4029 }
4030 }
4031 if (settings->dtim_period) {
ac24be6f 4032 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 4033 settings->dtim_period);
1a873342
HM
4034 if (err < 0) {
4035 WL_ERR("DTIM Interval Set Error, %d\n", err);
4036 goto exit;
4037 }
4038 }
ac24be6f 4039 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
1a873342
HM
4040 if (err < 0) {
4041 WL_ERR("BRCMF_C_UP error (%d)\n", err);
4042 goto exit;
4043 }
4044
4045 memset(&join_params, 0, sizeof(join_params));
4046 /* join parameters starts with ssid */
4047 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4048 /* create softap */
ac24be6f
AS
4049 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4050 &join_params, sizeof(join_params));
1a873342
HM
4051 if (err < 0) {
4052 WL_ERR("SET SSID error (%d)\n", err);
4053 goto exit;
4054 }
c1179033
AS
4055 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4056 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
4057
4058exit:
4059 if (err)
4060 brcmf_set_mpc(ndev, 1);
4061 return err;
4062}
4063
4064static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4065{
c1179033 4066 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 4067 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342
HM
4068 s32 err = -EPERM;
4069
4070 WL_TRACE("Enter\n");
4071
27a68fe3 4072 if (cfg->conf->mode == WL_MODE_AP) {
1a873342
HM
4073 /* Due to most likely deauths outstanding we sleep */
4074 /* first to make sure they get processed by fw. */
4075 msleep(400);
ac24be6f
AS
4076 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
4077 BRCMF_C_SET_AP, 0);
1a873342
HM
4078 if (err < 0) {
4079 WL_ERR("setting AP mode failed %d\n", err);
4080 goto exit;
4081 }
ac24be6f 4082 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
1a873342
HM
4083 if (err < 0) {
4084 WL_ERR("BRCMF_C_UP error %d\n", err);
4085 goto exit;
4086 }
4087 brcmf_set_mpc(ndev, 1);
c1179033
AS
4088 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4089 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
4090 }
4091exit:
4092 return err;
4093}
4094
4095static int
4096brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
4097 u8 *mac)
4098{
4099 struct brcmf_scb_val_le scbval;
0abb5f21 4100 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
4101 s32 err;
4102
4103 if (!mac)
4104 return -EFAULT;
4105
4106 WL_TRACE("Enter %pM\n", mac);
4107
ce81e317 4108 if (!check_vif_up(ifp->vif))
1a873342
HM
4109 return -EIO;
4110
4111 memcpy(&scbval.ea, mac, ETH_ALEN);
4112 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 4113 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 4114 &scbval, sizeof(scbval));
1a873342
HM
4115 if (err)
4116 WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
4117
4118 WL_TRACE("Exit\n");
4119 return err;
4120}
4121
5b435de0
AS
4122static struct cfg80211_ops wl_cfg80211_ops = {
4123 .change_virtual_intf = brcmf_cfg80211_change_iface,
4124 .scan = brcmf_cfg80211_scan,
4125 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4126 .join_ibss = brcmf_cfg80211_join_ibss,
4127 .leave_ibss = brcmf_cfg80211_leave_ibss,
4128 .get_station = brcmf_cfg80211_get_station,
4129 .set_tx_power = brcmf_cfg80211_set_tx_power,
4130 .get_tx_power = brcmf_cfg80211_get_tx_power,
4131 .add_key = brcmf_cfg80211_add_key,
4132 .del_key = brcmf_cfg80211_del_key,
4133 .get_key = brcmf_cfg80211_get_key,
4134 .set_default_key = brcmf_cfg80211_config_default_key,
4135 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4136 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
4137 .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
4138 .connect = brcmf_cfg80211_connect,
4139 .disconnect = brcmf_cfg80211_disconnect,
4140 .suspend = brcmf_cfg80211_suspend,
4141 .resume = brcmf_cfg80211_resume,
4142 .set_pmksa = brcmf_cfg80211_set_pmksa,
4143 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4144 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4145 .start_ap = brcmf_cfg80211_start_ap,
4146 .stop_ap = brcmf_cfg80211_stop_ap,
4147 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
4148#ifndef CONFIG_BRCMISCAN
4149 /* scheduled scan need e-scan, which is mutual exclusive with i-scan */
4150 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4151 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
4152#endif
cbaa177d
AS
4153#ifdef CONFIG_NL80211_TESTMODE
4154 .testmode_cmd = brcmf_cfg80211_testmode
4155#endif
5b435de0
AS
4156};
4157
4158static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
4159{
4160 s32 err = 0;
4161
4162 switch (mode) {
4163 case WL_MODE_BSS:
4164 return NL80211_IFTYPE_STATION;
4165 case WL_MODE_IBSS:
4166 return NL80211_IFTYPE_ADHOC;
4167 default:
4168 return NL80211_IFTYPE_UNSPECIFIED;
4169 }
4170
4171 return err;
4172}
4173
e5806072
AS
4174static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4175{
4176#ifndef CONFIG_BRCMFISCAN
4177 /* scheduled scan settings */
4178 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4179 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4180 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4181 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
4182#endif
4183}
4184
3eacf866 4185static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 4186{
3eacf866 4187 struct wiphy *wiphy;
5b435de0
AS
4188 s32 err = 0;
4189
3eacf866
AS
4190 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4191 if (!wiphy) {
bfeb4dbc 4192 WL_ERR("Could not allocate wiphy device\n");
3eacf866
AS
4193 return ERR_PTR(-ENOMEM);
4194 }
4195 set_wiphy_dev(wiphy, phydev);
4196 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
4197 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4198 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4199 BIT(NL80211_IFTYPE_ADHOC) |
4200 BIT(NL80211_IFTYPE_AP);
4201 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4202 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
5b435de0
AS
4203 * it as 11a by default.
4204 * This will be updated with
4205 * 11n phy tables in
4206 * "ifconfig up"
4207 * if phy has 11n capability
4208 */
3eacf866
AS
4209 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4210 wiphy->cipher_suites = __wl_cipher_suites;
4211 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
4212 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
5b435de0
AS
4213 * save mode
4214 * by default
4215 */
3eacf866
AS
4216 brcmf_wiphy_pno_params(wiphy);
4217 err = wiphy_register(wiphy);
5b435de0 4218 if (err < 0) {
bfeb4dbc 4219 WL_ERR("Could not register wiphy device (%d)\n", err);
3eacf866
AS
4220 wiphy_free(wiphy);
4221 return ERR_PTR(err);
5b435de0 4222 }
3eacf866
AS
4223 return wiphy;
4224}
4225
4226static
4227struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
4228 struct net_device *netdev,
4229 s32 mode, bool pm_block)
4230{
4231 struct brcmf_cfg80211_vif *vif;
5b435de0 4232
3eacf866
AS
4233 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4234 return ERR_PTR(-ENOSPC);
5b435de0 4235
3eacf866
AS
4236 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4237 if (!vif)
4238 return ERR_PTR(-ENOMEM);
4239
4240 vif->wdev.wiphy = cfg->wiphy;
4241 vif->wdev.netdev = netdev;
4242 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
5b435de0 4243
3eacf866
AS
4244 if (netdev) {
4245 vif->ifp = netdev_priv(netdev);
4246 netdev->ieee80211_ptr = &vif->wdev;
4247 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
4248 }
4249
4250 vif->mode = mode;
4251 vif->pm_block = pm_block;
4252 vif->roam_off = -1;
4253
6ac4f4ed
AS
4254 brcmf_init_prof(&vif->profile);
4255
3eacf866
AS
4256 list_add_tail(&vif->list, &cfg->vif_list);
4257 cfg->vif_cnt++;
4258 return vif;
5b435de0
AS
4259}
4260
3eacf866 4261static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4262{
3eacf866
AS
4263 struct brcmf_cfg80211_info *cfg;
4264 struct wiphy *wiphy;
5b435de0 4265
3eacf866
AS
4266 wiphy = vif->wdev.wiphy;
4267 cfg = wiphy_priv(wiphy);
4268 list_del(&vif->list);
4269 cfg->vif_cnt--;
4270
4271 kfree(vif);
4272 if (!cfg->vif_cnt) {
4273 wiphy_unregister(wiphy);
4274 wiphy_free(wiphy);
5b435de0 4275 }
5b435de0
AS
4276}
4277
27a68fe3 4278static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4279 const struct brcmf_event_msg *e)
4280{
4281 u32 event = be32_to_cpu(e->event_type);
4282 u32 status = be32_to_cpu(e->status);
4283
4284 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
4285 WL_CONN("Processing set ssid\n");
27a68fe3 4286 cfg->link_up = true;
5b435de0
AS
4287 return true;
4288 }
4289
4290 return false;
4291}
4292
27a68fe3 4293static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4294 const struct brcmf_event_msg *e)
4295{
4296 u32 event = be32_to_cpu(e->event_type);
4297 u16 flags = be16_to_cpu(e->flags);
4298
4299 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
4300 WL_CONN("Processing link down\n");
4301 return true;
4302 }
4303 return false;
4304}
4305
27a68fe3 4306static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4307 const struct brcmf_event_msg *e)
4308{
4309 u32 event = be32_to_cpu(e->event_type);
4310 u32 status = be32_to_cpu(e->status);
4311
4312 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
4313 WL_CONN("Processing Link %s & no network found\n",
4314 be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
4315 "up" : "down");
4316 return true;
4317 }
4318
4319 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
4320 WL_CONN("Processing connecting & no network found\n");
4321 return true;
4322 }
4323
4324 return false;
4325}
4326
27a68fe3 4327static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4328{
27a68fe3 4329 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4330
4331 kfree(conn_info->req_ie);
4332 conn_info->req_ie = NULL;
4333 conn_info->req_ie_len = 0;
4334 kfree(conn_info->resp_ie);
4335 conn_info->resp_ie = NULL;
4336 conn_info->resp_ie_len = 0;
4337}
4338
27a68fe3 4339static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4340{
ac24be6f 4341 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
c4e382d2 4342 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4343 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4344 u32 req_len;
4345 u32 resp_len;
4346 s32 err = 0;
4347
27a68fe3 4348 brcmf_clear_assoc_ies(cfg);
5b435de0 4349
ac24be6f
AS
4350 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4351 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0
AS
4352 if (err) {
4353 WL_ERR("could not get assoc info (%d)\n", err);
4354 return err;
4355 }
c4e382d2 4356 assoc_info =
27a68fe3 4357 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4358 req_len = le32_to_cpu(assoc_info->req_len);
4359 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4360 if (req_len) {
ac24be6f 4361 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4362 cfg->extra_buf,
4363 WL_ASSOC_INFO_MAX);
5b435de0
AS
4364 if (err) {
4365 WL_ERR("could not get assoc req (%d)\n", err);
4366 return err;
4367 }
4368 conn_info->req_ie_len = req_len;
4369 conn_info->req_ie =
27a68fe3 4370 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4371 GFP_KERNEL);
4372 } else {
4373 conn_info->req_ie_len = 0;
4374 conn_info->req_ie = NULL;
4375 }
4376 if (resp_len) {
ac24be6f 4377 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4378 cfg->extra_buf,
4379 WL_ASSOC_INFO_MAX);
5b435de0
AS
4380 if (err) {
4381 WL_ERR("could not get assoc resp (%d)\n", err);
4382 return err;
4383 }
4384 conn_info->resp_ie_len = resp_len;
4385 conn_info->resp_ie =
27a68fe3 4386 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4387 GFP_KERNEL);
4388 } else {
4389 conn_info->resp_ie_len = 0;
4390 conn_info->resp_ie = NULL;
4391 }
4392 WL_CONN("req len (%d) resp len (%d)\n",
4393 conn_info->req_ie_len, conn_info->resp_ie_len);
4394
4395 return err;
4396}
4397
4398static s32
27a68fe3 4399brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4400 struct net_device *ndev,
4401 const struct brcmf_event_msg *e)
4402{
c1179033
AS
4403 struct brcmf_if *ifp = netdev_priv(ndev);
4404 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4405 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4406 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4407 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4408 struct ieee80211_supported_band *band;
a180b83b 4409 struct brcmf_bss_info_le *bi;
5b435de0
AS
4410 u32 freq;
4411 s32 err = 0;
4412 u32 target_channel;
a180b83b 4413 u8 *buf;
5b435de0
AS
4414
4415 WL_TRACE("Enter\n");
4416
27a68fe3 4417 brcmf_get_assoc_ies(cfg);
6c8c4f72 4418 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4419 brcmf_update_bss_info(cfg);
5b435de0 4420
a180b83b
FL
4421 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4422 if (buf == NULL) {
4423 err = -ENOMEM;
4424 goto done;
4425 }
4426
4427 /* data sent to dongle has to be little endian */
4428 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4429 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4430 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4431
4432 if (err)
4433 goto done;
5b435de0 4434
a180b83b
FL
4435 bi = (struct brcmf_bss_info_le *)(buf + 4);
4436 target_channel = bi->ctl_ch ? bi->ctl_ch :
4437 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
5b435de0
AS
4438
4439 if (target_channel <= CH_MAX_2G_CHANNEL)
4440 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4441 else
4442 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4443
4444 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4445 notify_channel = ieee80211_get_channel(wiphy, freq);
4446
a180b83b
FL
4447done:
4448 kfree(buf);
06bb123e 4449 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4450 conn_info->req_ie, conn_info->req_ie_len,
4451 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4452 WL_CONN("Report roaming result\n");
4453
c1179033 4454 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
5b435de0
AS
4455 WL_TRACE("Exit\n");
4456 return err;
4457}
4458
4459static s32
27a68fe3 4460brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4461 struct net_device *ndev, const struct brcmf_event_msg *e,
4462 bool completed)
4463{
c1179033
AS
4464 struct brcmf_if *ifp = netdev_priv(ndev);
4465 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4466 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4467 s32 err = 0;
4468
4469 WL_TRACE("Enter\n");
4470
c1179033
AS
4471 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4472 &ifp->vif->sme_state)) {
5b435de0 4473 if (completed) {
27a68fe3 4474 brcmf_get_assoc_ies(cfg);
6c8c4f72 4475 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4476 brcmf_update_bss_info(cfg);
5b435de0
AS
4477 }
4478 cfg80211_connect_result(ndev,
06bb123e 4479 (u8 *)profile->bssid,
5b435de0
AS
4480 conn_info->req_ie,
4481 conn_info->req_ie_len,
4482 conn_info->resp_ie,
4483 conn_info->resp_ie_len,
4484 completed ? WLAN_STATUS_SUCCESS :
4485 WLAN_STATUS_AUTH_TIMEOUT,
4486 GFP_KERNEL);
4487 if (completed)
c1179033
AS
4488 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4489 &ifp->vif->sme_state);
5b435de0
AS
4490 WL_CONN("Report connect result - connection %s\n",
4491 completed ? "succeeded" : "failed");
4492 }
4493 WL_TRACE("Exit\n");
4494 return err;
4495}
4496
4497static s32
27a68fe3 4498brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4499 struct net_device *ndev,
4500 const struct brcmf_event_msg *e, void *data)
4501{
4502 s32 err = 0;
4503 u32 event = be32_to_cpu(e->event_type);
4504 u32 reason = be32_to_cpu(e->reason);
4505 u32 len = be32_to_cpu(e->datalen);
4506 static int generation;
4507
4508 struct station_info sinfo;
4509
4510 WL_CONN("event %d, reason %d\n", event, reason);
4511 memset(&sinfo, 0, sizeof(sinfo));
4512
4513 sinfo.filled = 0;
4514 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4515 reason == BRCMF_E_STATUS_SUCCESS) {
4516 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4517 if (!data) {
4518 WL_ERR("No IEs present in ASSOC/REASSOC_IND");
4519 return -EINVAL;
4520 }
4521 sinfo.assoc_req_ies = data;
4522 sinfo.assoc_req_ies_len = len;
4523 generation++;
4524 sinfo.generation = generation;
4525 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
4526 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4527 (event == BRCMF_E_DEAUTH_IND) ||
4528 (event == BRCMF_E_DEAUTH)) {
4529 generation++;
4530 sinfo.generation = generation;
4531 cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
4532 }
4533 return err;
4534}
4535
5b435de0 4536static s32
27a68fe3 4537brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4538 struct net_device *ndev,
4539 const struct brcmf_event_msg *e, void *data)
4540{
c1179033
AS
4541 struct brcmf_if *ifp = netdev_priv(ndev);
4542 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4543 s32 err = 0;
4544
27a68fe3
AS
4545 if (cfg->conf->mode == WL_MODE_AP) {
4546 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4547 } else if (brcmf_is_linkup(cfg, e)) {
5b435de0 4548 WL_CONN("Linkup\n");
27a68fe3 4549 if (brcmf_is_ibssmode(cfg)) {
6c8c4f72 4550 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4551 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4552 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4553 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4554 &ifp->vif->sme_state);
4555 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4556 &ifp->vif->sme_state);
5b435de0 4557 } else
27a68fe3
AS
4558 brcmf_bss_connect_done(cfg, ndev, e, true);
4559 } else if (brcmf_is_linkdown(cfg, e)) {
5b435de0 4560 WL_CONN("Linkdown\n");
27a68fe3 4561 if (brcmf_is_ibssmode(cfg)) {
c1179033
AS
4562 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4563 &ifp->vif->sme_state);
4564 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4565 &ifp->vif->sme_state))
27a68fe3 4566 brcmf_link_down(cfg);
5b435de0 4567 } else {
27a68fe3 4568 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033
AS
4569 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4570 &ifp->vif->sme_state)) {
5b435de0 4571 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4572 GFP_KERNEL);
27a68fe3 4573 brcmf_link_down(cfg);
5b435de0
AS
4574 }
4575 }
6ac4f4ed 4576 brcmf_init_prof(ndev_to_prof(ndev));
27a68fe3
AS
4577 } else if (brcmf_is_nonetwork(cfg, e)) {
4578 if (brcmf_is_ibssmode(cfg))
c1179033
AS
4579 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4580 &ifp->vif->sme_state);
5b435de0 4581 else
27a68fe3 4582 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4583 }
4584
4585 return err;
4586}
4587
4588static s32
27a68fe3 4589brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4590 struct net_device *ndev,
4591 const struct brcmf_event_msg *e, void *data)
4592{
c1179033 4593 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
4594 s32 err = 0;
4595 u32 event = be32_to_cpu(e->event_type);
4596 u32 status = be32_to_cpu(e->status);
4597
4598 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4599 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
27a68fe3 4600 brcmf_bss_roaming_done(cfg, ndev, e);
5b435de0 4601 else
27a68fe3 4602 brcmf_bss_connect_done(cfg, ndev, e, true);
5b435de0
AS
4603 }
4604
4605 return err;
4606}
4607
4608static s32
27a68fe3 4609brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4610 struct net_device *ndev,
4611 const struct brcmf_event_msg *e, void *data)
4612{
4613 u16 flags = be16_to_cpu(e->flags);
4614 enum nl80211_key_type key_type;
4615
4616 if (flags & BRCMF_EVENT_MSG_GROUP)
4617 key_type = NL80211_KEYTYPE_GROUP;
4618 else
4619 key_type = NL80211_KEYTYPE_PAIRWISE;
4620
4621 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
4622 NULL, GFP_KERNEL);
4623
4624 return 0;
4625}
4626
4627static s32
27a68fe3 4628brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4629 struct net_device *ndev,
4630 const struct brcmf_event_msg *e, void *data)
4631{
c1179033 4632 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
4633 struct brcmf_channel_info_le channel_inform_le;
4634 struct brcmf_scan_results_le *bss_list_le;
4635 u32 len = WL_SCAN_BUF_MAX;
4636 s32 err = 0;
4637 bool scan_abort = false;
4638 u32 scan_channel;
4639
4640 WL_TRACE("Enter\n");
4641
27a68fe3 4642 if (cfg->iscan_on && cfg->iscan_kickstart) {
5b435de0 4643 WL_TRACE("Exit\n");
27a68fe3 4644 return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
5b435de0
AS
4645 }
4646
c1179033 4647 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
5b435de0
AS
4648 WL_ERR("Scan complete while device not scanning\n");
4649 scan_abort = true;
4650 err = -EINVAL;
4651 goto scan_done_out;
4652 }
4653
c1179033 4654 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
81f5dcb8
HM
4655 &channel_inform_le,
4656 sizeof(channel_inform_le));
5b435de0
AS
4657 if (err) {
4658 WL_ERR("scan busy (%d)\n", err);
4659 scan_abort = true;
4660 goto scan_done_out;
4661 }
4662 scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
4663 if (scan_channel)
4664 WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
27a68fe3
AS
4665 cfg->bss_list = cfg->scan_results;
4666 bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list;
5b435de0 4667
27a68fe3 4668 memset(cfg->scan_results, 0, len);
5b435de0 4669 bss_list_le->buflen = cpu_to_le32(len);
c1179033 4670 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
81f5dcb8 4671 cfg->scan_results, len);
5b435de0
AS
4672 if (err) {
4673 WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
4674 err = -EINVAL;
4675 scan_abort = true;
4676 goto scan_done_out;
4677 }
27a68fe3
AS
4678 cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
4679 cfg->scan_results->version = le32_to_cpu(bss_list_le->version);
4680 cfg->scan_results->count = le32_to_cpu(bss_list_le->count);
5b435de0 4681
27a68fe3 4682 err = brcmf_inform_bss(cfg);
35aafa9d 4683 if (err)
5b435de0 4684 scan_abort = true;
5b435de0
AS
4685
4686scan_done_out:
27a68fe3 4687 if (cfg->scan_request) {
5b435de0 4688 WL_SCAN("calling cfg80211_scan_done\n");
27a68fe3 4689 cfg80211_scan_done(cfg->scan_request, scan_abort);
5b435de0 4690 brcmf_set_mpc(ndev, 1);
27a68fe3 4691 cfg->scan_request = NULL;
5b435de0
AS
4692 }
4693
4694 WL_TRACE("Exit\n");
4695
4696 return err;
4697}
4698
4699static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4700{
4701 conf->mode = (u32)-1;
4702 conf->frag_threshold = (u32)-1;
4703 conf->rts_threshold = (u32)-1;
4704 conf->retry_short = (u32)-1;
4705 conf->retry_long = (u32)-1;
4706 conf->tx_power = -1;
4707}
4708
4709static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
4710{
4711 memset(el, 0, sizeof(*el));
4712 el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
4713 el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
1a873342
HM
4714 el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;
4715 el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status;
4716 el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status;
4717 el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status;
4718 el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status;
5b435de0
AS
4719 el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
4720 el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
4721 el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
e5806072 4722 el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
5b435de0
AS
4723}
4724
27a68fe3
AS
4725static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4726{
4727 kfree(cfg->scan_results);
4728 cfg->scan_results = NULL;
4729 kfree(cfg->bss_info);
4730 cfg->bss_info = NULL;
4731 kfree(cfg->conf);
4732 cfg->conf = NULL;
27a68fe3
AS
4733 kfree(cfg->scan_req_int);
4734 cfg->scan_req_int = NULL;
4735 kfree(cfg->escan_ioctl_buf);
4736 cfg->escan_ioctl_buf = NULL;
4737 kfree(cfg->dcmd_buf);
4738 cfg->dcmd_buf = NULL;
4739 kfree(cfg->extra_buf);
4740 cfg->extra_buf = NULL;
4741 kfree(cfg->iscan);
4742 cfg->iscan = NULL;
4743 kfree(cfg->pmk_list);
4744 cfg->pmk_list = NULL;
27a68fe3
AS
4745}
4746
4747static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4748{
4749 cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
4750 if (!cfg->scan_results)
5b435de0 4751 goto init_priv_mem_out;
27a68fe3
AS
4752 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4753 if (!cfg->conf)
5b435de0 4754 goto init_priv_mem_out;
27a68fe3
AS
4755 cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4756 if (!cfg->bss_info)
5b435de0 4757 goto init_priv_mem_out;
27a68fe3 4758 cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int),
5b435de0 4759 GFP_KERNEL);
27a68fe3 4760 if (!cfg->scan_req_int)
5b435de0 4761 goto init_priv_mem_out;
27a68fe3
AS
4762 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4763 if (!cfg->escan_ioctl_buf)
e756af5b 4764 goto init_priv_mem_out;
27a68fe3
AS
4765 cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
4766 if (!cfg->dcmd_buf)
5b435de0 4767 goto init_priv_mem_out;
27a68fe3
AS
4768 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4769 if (!cfg->extra_buf)
5b435de0 4770 goto init_priv_mem_out;
27a68fe3
AS
4771 cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL);
4772 if (!cfg->iscan)
5b435de0 4773 goto init_priv_mem_out;
27a68fe3
AS
4774 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4775 if (!cfg->pmk_list)
5b435de0
AS
4776 goto init_priv_mem_out;
4777
4778 return 0;
4779
4780init_priv_mem_out:
27a68fe3 4781 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4782
4783 return -ENOMEM;
4784}
4785
4786/*
4787* retrieve first queued event from head
4788*/
4789
4790static struct brcmf_cfg80211_event_q *brcmf_deq_event(
27a68fe3 4791 struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4792{
4793 struct brcmf_cfg80211_event_q *e = NULL;
4794
27a68fe3
AS
4795 spin_lock_irq(&cfg->evt_q_lock);
4796 if (!list_empty(&cfg->evt_q_list)) {
4797 e = list_first_entry(&cfg->evt_q_list,
5b435de0
AS
4798 struct brcmf_cfg80211_event_q, evt_q_list);
4799 list_del(&e->evt_q_list);
4800 }
27a68fe3 4801 spin_unlock_irq(&cfg->evt_q_lock);
5b435de0
AS
4802
4803 return e;
4804}
4805
4806/*
bcbec9e7
AS
4807* push event to tail of the queue
4808*
4809* remark: this function may not sleep as it is called in atomic context.
5b435de0
AS
4810*/
4811
4812static s32
27a68fe3 4813brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event,
c4fdb056 4814 const struct brcmf_event_msg *msg, void *data)
5b435de0
AS
4815{
4816 struct brcmf_cfg80211_event_q *e;
4817 s32 err = 0;
cf44066a 4818 ulong flags;
c4fdb056
HM
4819 u32 data_len;
4820 u32 total_len;
5b435de0 4821
c4fdb056
HM
4822 total_len = sizeof(struct brcmf_cfg80211_event_q);
4823 if (data)
4824 data_len = be32_to_cpu(msg->datalen);
4825 else
4826 data_len = 0;
4827 total_len += data_len;
4828 e = kzalloc(total_len, GFP_ATOMIC);
5b435de0
AS
4829 if (!e)
4830 return -ENOMEM;
4831
4832 e->etype = event;
4833 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
c4fdb056
HM
4834 if (data)
4835 memcpy(&e->edata, data, data_len);
5b435de0 4836
27a68fe3
AS
4837 spin_lock_irqsave(&cfg->evt_q_lock, flags);
4838 list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
4839 spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
5b435de0
AS
4840
4841 return err;
4842}
4843
4844static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
4845{
4846 kfree(e);
4847}
4848
4849static void brcmf_cfg80211_event_handler(struct work_struct *work)
4850{
27a68fe3
AS
4851 struct brcmf_cfg80211_info *cfg =
4852 container_of(work, struct brcmf_cfg80211_info,
5b435de0
AS
4853 event_work);
4854 struct brcmf_cfg80211_event_q *e;
4855
27a68fe3 4856 e = brcmf_deq_event(cfg);
5b435de0
AS
4857 if (unlikely(!e)) {
4858 WL_ERR("event queue empty...\n");
4859 return;
4860 }
4861
4862 do {
4863 WL_INFO("event type (%d)\n", e->etype);
27a68fe3
AS
4864 if (cfg->el.handler[e->etype])
4865 cfg->el.handler[e->etype](cfg,
4866 cfg_to_ndev(cfg),
5b435de0
AS
4867 &e->emsg, e->edata);
4868 else
4869 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
4870 brcmf_put_event(e);
27a68fe3 4871 } while ((e = brcmf_deq_event(cfg)));
5b435de0
AS
4872
4873}
4874
27a68fe3 4875static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
5b435de0 4876{
27a68fe3
AS
4877 spin_lock_init(&cfg->evt_q_lock);
4878 INIT_LIST_HEAD(&cfg->evt_q_list);
5b435de0
AS
4879}
4880
27a68fe3 4881static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4882{
4883 struct brcmf_cfg80211_event_q *e;
4884
27a68fe3
AS
4885 spin_lock_irq(&cfg->evt_q_lock);
4886 while (!list_empty(&cfg->evt_q_list)) {
4887 e = list_first_entry(&cfg->evt_q_list,
5b435de0
AS
4888 struct brcmf_cfg80211_event_q, evt_q_list);
4889 list_del(&e->evt_q_list);
4890 kfree(e);
4891 }
27a68fe3 4892 spin_unlock_irq(&cfg->evt_q_lock);
5b435de0
AS
4893}
4894
27a68fe3 4895static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4896{
4897 s32 err = 0;
4898
27a68fe3
AS
4899 cfg->scan_request = NULL;
4900 cfg->pwr_save = true;
e756af5b 4901#ifdef CONFIG_BRCMISCAN
27a68fe3 4902 cfg->iscan_on = true; /* iscan on & off switch.
5b435de0 4903 we enable iscan per default */
27a68fe3 4904 cfg->escan_on = false; /* escan on & off switch.
e756af5b
HM
4905 we disable escan per default */
4906#else
27a68fe3 4907 cfg->iscan_on = false; /* iscan on & off switch.
e756af5b 4908 we disable iscan per default */
27a68fe3 4909 cfg->escan_on = true; /* escan on & off switch.
e756af5b
HM
4910 we enable escan per default */
4911#endif
27a68fe3 4912 cfg->roam_on = true; /* roam on & off switch.
5b435de0
AS
4913 we enable roam per default */
4914
27a68fe3
AS
4915 cfg->iscan_kickstart = false;
4916 cfg->active_scan = true; /* we do active scan for
5b435de0 4917 specific scan per default */
27a68fe3
AS
4918 cfg->dongle_up = false; /* dongle is not up yet */
4919 brcmf_init_eq(cfg);
4920 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4921 if (err)
4922 return err;
27a68fe3
AS
4923 INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);
4924 brcmf_init_eloop_handler(&cfg->el);
4925 mutex_init(&cfg->usr_sync);
4926 err = brcmf_init_iscan(cfg);
5b435de0
AS
4927 if (err)
4928 return err;
27a68fe3
AS
4929 brcmf_init_escan(cfg);
4930 brcmf_init_conf(cfg->conf);
27a68fe3 4931 brcmf_link_down(cfg);
5b435de0
AS
4932
4933 return err;
4934}
4935
27a68fe3 4936static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4937{
27a68fe3
AS
4938 cancel_work_sync(&cfg->event_work);
4939 cfg->dongle_up = false; /* dongle down */
4940 brcmf_flush_eq(cfg);
4941 brcmf_link_down(cfg);
4942 brcmf_abort_scanning(cfg);
4943 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4944}
4945
1ed9baf0 4946struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
5b435de0 4947{
1ed9baf0
AS
4948 struct net_device *ndev = drvr->iflist[0]->ndev;
4949 struct device *busdev = drvr->dev;
27a68fe3 4950 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4951 struct wiphy *wiphy;
4952 struct brcmf_cfg80211_vif *vif;
4953 struct brcmf_if *ifp;
5b435de0
AS
4954 s32 err = 0;
4955
4956 if (!ndev) {
4957 WL_ERR("ndev is invalid\n");
4958 return NULL;
4959 }
5b435de0 4960
3eacf866
AS
4961 ifp = netdev_priv(ndev);
4962 wiphy = brcmf_setup_wiphy(busdev);
4963 if (IS_ERR(wiphy))
5b435de0 4964 return NULL;
5b435de0 4965
3eacf866
AS
4966 cfg = wiphy_priv(wiphy);
4967 cfg->wiphy = wiphy;
27a68fe3 4968 cfg->pub = drvr;
3eacf866
AS
4969 INIT_LIST_HEAD(&cfg->vif_list);
4970
4971 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
4972 if (IS_ERR(vif)) {
4973 wiphy_free(wiphy);
4974 return NULL;
4975 }
4976
27a68fe3 4977 err = wl_init_priv(cfg);
5b435de0
AS
4978 if (err) {
4979 WL_ERR("Failed to init iwm_priv (%d)\n", err);
4980 goto cfg80211_attach_out;
4981 }
5b435de0 4982
3eacf866 4983 ifp->vif = vif;
27a68fe3 4984 return cfg;
5b435de0
AS
4985
4986cfg80211_attach_out:
3eacf866 4987 brcmf_free_vif(vif);
5b435de0
AS
4988 return NULL;
4989}
4990
27a68fe3 4991void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 4992{
3eacf866
AS
4993 struct brcmf_cfg80211_vif *vif;
4994 struct brcmf_cfg80211_vif *tmp;
4995
27a68fe3 4996 wl_deinit_priv(cfg);
3eacf866
AS
4997 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4998 brcmf_free_vif(vif);
4999 }
5b435de0
AS
5000}
5001
5002void
5003brcmf_cfg80211_event(struct net_device *ndev,
5004 const struct brcmf_event_msg *e, void *data)
5005{
5006 u32 event_type = be32_to_cpu(e->event_type);
27a68fe3 5007 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
5b435de0 5008
27a68fe3
AS
5009 if (!brcmf_enq_event(cfg, event_type, e, data))
5010 schedule_work(&cfg->event_work);
5b435de0
AS
5011}
5012
5b435de0
AS
5013static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
5014{
5b435de0
AS
5015 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
5016 s32 err = 0;
5017
5018 WL_TRACE("Enter\n");
5019
5020 /* Setup event_msgs */
ac24be6f
AS
5021 err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
5022 eventmask, BRCMF_EVENTING_MASK_LEN);
5b435de0
AS
5023 if (err) {
5024 WL_ERR("Get event_msgs error (%d)\n", err);
5025 goto dongle_eventmsg_out;
5026 }
5b435de0
AS
5027
5028 setbit(eventmask, BRCMF_E_SET_SSID);
5029 setbit(eventmask, BRCMF_E_ROAM);
5030 setbit(eventmask, BRCMF_E_PRUNE);
5031 setbit(eventmask, BRCMF_E_AUTH);
5032 setbit(eventmask, BRCMF_E_REASSOC);
5033 setbit(eventmask, BRCMF_E_REASSOC_IND);
5034 setbit(eventmask, BRCMF_E_DEAUTH_IND);
5035 setbit(eventmask, BRCMF_E_DISASSOC_IND);
5036 setbit(eventmask, BRCMF_E_DISASSOC);
5037 setbit(eventmask, BRCMF_E_JOIN);
5038 setbit(eventmask, BRCMF_E_ASSOC_IND);
5039 setbit(eventmask, BRCMF_E_PSK_SUP);
5040 setbit(eventmask, BRCMF_E_LINK);
5041 setbit(eventmask, BRCMF_E_NDIS_LINK);
5042 setbit(eventmask, BRCMF_E_MIC_ERROR);
5043 setbit(eventmask, BRCMF_E_PMKID_CACHE);
5044 setbit(eventmask, BRCMF_E_TXFAIL);
5045 setbit(eventmask, BRCMF_E_JOIN_START);
5046 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
e756af5b 5047 setbit(eventmask, BRCMF_E_ESCAN_RESULT);
e5806072 5048 setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
5b435de0 5049
ac24be6f
AS
5050 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
5051 eventmask, BRCMF_EVENTING_MASK_LEN);
5b435de0
AS
5052 if (err) {
5053 WL_ERR("Set event_msgs error (%d)\n", err);
5054 goto dongle_eventmsg_out;
5055 }
5056
5057dongle_eventmsg_out:
5058 WL_TRACE("Exit\n");
5059 return err;
5060}
5061
5062static s32
5063brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
5064{
ac24be6f 5065 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 5066 s32 err = 0;
f588bc0c
AS
5067 __le32 roamtrigger[2];
5068 __le32 roam_delta[2];
5b435de0
AS
5069
5070 /*
5071 * Setup timeout if Beacons are lost and roam is
5072 * off to report link down
5073 */
5074 if (roamvar) {
ac24be6f 5075 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0
AS
5076 if (err) {
5077 WL_ERR("bcn_timeout error (%d)\n", err);
5078 goto dongle_rom_out;
5079 }
5080 }
5081
5082 /*
5083 * Enable/Disable built-in roaming to allow supplicant
5084 * to take care of roaming
5085 */
5086 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 5087 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0
AS
5088 if (err) {
5089 WL_ERR("roam_off error (%d)\n", err);
5090 goto dongle_rom_out;
5091 }
5092
f588bc0c
AS
5093 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5094 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5095 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 5096 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0
AS
5097 if (err) {
5098 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5099 goto dongle_rom_out;
5100 }
5101
f588bc0c
AS
5102 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5103 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5104 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 5105 (void *)roam_delta, sizeof(roam_delta));
5b435de0
AS
5106 if (err) {
5107 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
5108 goto dongle_rom_out;
5109 }
5110
5111dongle_rom_out:
5112 return err;
5113}
5114
5115static s32
5116brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
c68cdc0f 5117 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0 5118{
ac24be6f 5119 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
5120 s32 err = 0;
5121
ac24be6f 5122 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 5123 scan_assoc_time);
5b435de0
AS
5124 if (err) {
5125 if (err == -EOPNOTSUPP)
5126 WL_INFO("Scan assoc time is not supported\n");
5127 else
5128 WL_ERR("Scan assoc time error (%d)\n", err);
5129 goto dongle_scantime_out;
5130 }
ac24be6f 5131 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 5132 scan_unassoc_time);
5b435de0
AS
5133 if (err) {
5134 if (err == -EOPNOTSUPP)
5135 WL_INFO("Scan unassoc time is not supported\n");
5136 else
5137 WL_ERR("Scan unassoc time error (%d)\n", err);
5138 goto dongle_scantime_out;
5139 }
5140
ac24be6f 5141 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 5142 scan_passive_time);
5b435de0
AS
5143 if (err) {
5144 if (err == -EOPNOTSUPP)
5145 WL_INFO("Scan passive time is not supported\n");
5146 else
5147 WL_ERR("Scan passive time error (%d)\n", err);
5148 goto dongle_scantime_out;
5149 }
5150
5151dongle_scantime_out:
5152 return err;
5153}
5154
27a68fe3 5155static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 5156{
ac24be6f 5157 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5158 struct wiphy *wiphy;
5159 s32 phy_list;
5160 s8 phy;
5161 s32 err = 0;
5162
ac24be6f 5163 err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
81f5dcb8 5164 &phy_list, sizeof(phy_list));
5b435de0
AS
5165 if (err) {
5166 WL_ERR("error (%d)\n", err);
5167 return err;
5168 }
5169
3ba81376 5170 phy = ((char *)&phy_list)[0];
5b435de0
AS
5171 WL_INFO("%c phy\n", phy);
5172 if (phy == 'n' || phy == 'a') {
27a68fe3 5173 wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
5174 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
5175 }
5176
5177 return err;
5178}
5179
27a68fe3 5180static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 5181{
27a68fe3 5182 return wl_update_wiphybands(cfg);
5b435de0
AS
5183}
5184
27a68fe3 5185static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5186{
5187 struct net_device *ndev;
5188 struct wireless_dev *wdev;
5189 s32 power_mode;
5190 s32 err = 0;
5191
27a68fe3 5192 if (cfg->dongle_up)
5b435de0
AS
5193 return err;
5194
27a68fe3 5195 ndev = cfg_to_ndev(cfg);
5b435de0
AS
5196 wdev = ndev->ieee80211_ptr;
5197
5198 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
5199 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5200
5201 err = brcmf_dongle_eventmsg(ndev);
5202 if (err)
5203 goto default_conf_out;
5204
27a68fe3 5205 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
ac24be6f
AS
5206 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
5207 power_mode);
5b435de0
AS
5208 if (err)
5209 goto default_conf_out;
5210 WL_INFO("power save set to %s\n",
5211 (power_mode ? "enabled" : "disabled"));
5212
27a68fe3 5213 err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
5b435de0
AS
5214 WL_BEACON_TIMEOUT);
5215 if (err)
5216 goto default_conf_out;
5dd161ff
FL
5217 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5218 NULL, NULL);
5b435de0
AS
5219 if (err && err != -EINPROGRESS)
5220 goto default_conf_out;
27a68fe3 5221 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
5222 if (err)
5223 goto default_conf_out;
5224
5225 /* -EINPROGRESS: Call commit handler */
5226
5227default_conf_out:
5228
27a68fe3 5229 cfg->dongle_up = true;
5b435de0
AS
5230
5231 return err;
5232
5233}
5234
27a68fe3 5235static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 5236{
c1179033 5237 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5238 s32 err = 0;
5239
c1179033 5240 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5241
27a68fe3 5242 err = brcmf_config_dongle(cfg);
5b435de0
AS
5243 if (err)
5244 return err;
5245
27a68fe3 5246 brcmf_invoke_iscan(cfg);
5b435de0
AS
5247
5248 return err;
5249}
5250
27a68fe3 5251static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 5252{
c1179033
AS
5253 struct net_device *ndev = cfg_to_ndev(cfg);
5254 struct brcmf_if *ifp = netdev_priv(ndev);
5255
5b435de0
AS
5256 /*
5257 * While going down, if associated with AP disassociate
5258 * from AP to save power
5259 */
c1179033
AS
5260 if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
5261 test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
ce81e317 5262 check_vif_up(ifp->vif)) {
5b435de0 5263 WL_INFO("Disassociating from AP");
27a68fe3 5264 brcmf_link_down(cfg);
5b435de0
AS
5265
5266 /* Make sure WPA_Supplicant receives all the event
5267 generated due to DISASSOC call to the fw to keep
5268 the state fw and WPA_Supplicant state consistent
5269 */
5270 brcmf_delay(500);
5271 }
5272
27a68fe3 5273 brcmf_abort_scanning(cfg);
c1179033 5274 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5275
5b435de0
AS
5276 return 0;
5277}
5278
27a68fe3 5279s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 5280{
5b435de0
AS
5281 s32 err = 0;
5282
27a68fe3
AS
5283 mutex_lock(&cfg->usr_sync);
5284 err = __brcmf_cfg80211_up(cfg);
5285 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5286
5287 return err;
5288}
5289
27a68fe3 5290s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 5291{
5b435de0
AS
5292 s32 err = 0;
5293
27a68fe3
AS
5294 mutex_lock(&cfg->usr_sync);
5295 err = __brcmf_cfg80211_down(cfg);
5296 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5297
5298 return err;
5299}
5300
This page took 0.394986 seconds and 5 git commands to generate.