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