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