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