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