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