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