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