nl80211: add documentation for channel type
[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
5b435de0
AS
97static u32 brcmf_dbg_level = WL_DBG_ERR;
98
ce81e317 99static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
5b435de0 100{
c1179033
AS
101 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
102 WL_INFO("device is not ready : status (%lu)\n",
103 vif->sme_state);
5b435de0
AS
104 return false;
105 }
106 return true;
107}
108
109#define CHAN2G(_channel, _freq, _flags) { \
110 .band = IEEE80211_BAND_2GHZ, \
111 .center_freq = (_freq), \
112 .hw_value = (_channel), \
113 .flags = (_flags), \
114 .max_antenna_gain = 0, \
115 .max_power = 30, \
116}
117
118#define CHAN5G(_channel, _flags) { \
119 .band = IEEE80211_BAND_5GHZ, \
120 .center_freq = 5000 + (5 * (_channel)), \
121 .hw_value = (_channel), \
122 .flags = (_flags), \
123 .max_antenna_gain = 0, \
124 .max_power = 30, \
125}
126
127#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
128#define RATETAB_ENT(_rateid, _flags) \
129 { \
130 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
131 .hw_value = (_rateid), \
132 .flags = (_flags), \
133 }
134
135static struct ieee80211_rate __wl_rates[] = {
136 RATETAB_ENT(BRCM_RATE_1M, 0),
137 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
138 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
139 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
140 RATETAB_ENT(BRCM_RATE_6M, 0),
141 RATETAB_ENT(BRCM_RATE_9M, 0),
142 RATETAB_ENT(BRCM_RATE_12M, 0),
143 RATETAB_ENT(BRCM_RATE_18M, 0),
144 RATETAB_ENT(BRCM_RATE_24M, 0),
145 RATETAB_ENT(BRCM_RATE_36M, 0),
146 RATETAB_ENT(BRCM_RATE_48M, 0),
147 RATETAB_ENT(BRCM_RATE_54M, 0),
148};
149
150#define wl_a_rates (__wl_rates + 4)
151#define wl_a_rates_size 8
152#define wl_g_rates (__wl_rates + 0)
153#define wl_g_rates_size 12
154
155static struct ieee80211_channel __wl_2ghz_channels[] = {
156 CHAN2G(1, 2412, 0),
157 CHAN2G(2, 2417, 0),
158 CHAN2G(3, 2422, 0),
159 CHAN2G(4, 2427, 0),
160 CHAN2G(5, 2432, 0),
161 CHAN2G(6, 2437, 0),
162 CHAN2G(7, 2442, 0),
163 CHAN2G(8, 2447, 0),
164 CHAN2G(9, 2452, 0),
165 CHAN2G(10, 2457, 0),
166 CHAN2G(11, 2462, 0),
167 CHAN2G(12, 2467, 0),
168 CHAN2G(13, 2472, 0),
169 CHAN2G(14, 2484, 0),
170};
171
172static struct ieee80211_channel __wl_5ghz_a_channels[] = {
173 CHAN5G(34, 0), CHAN5G(36, 0),
174 CHAN5G(38, 0), CHAN5G(40, 0),
175 CHAN5G(42, 0), CHAN5G(44, 0),
176 CHAN5G(46, 0), CHAN5G(48, 0),
177 CHAN5G(52, 0), CHAN5G(56, 0),
178 CHAN5G(60, 0), CHAN5G(64, 0),
179 CHAN5G(100, 0), CHAN5G(104, 0),
180 CHAN5G(108, 0), CHAN5G(112, 0),
181 CHAN5G(116, 0), CHAN5G(120, 0),
182 CHAN5G(124, 0), CHAN5G(128, 0),
183 CHAN5G(132, 0), CHAN5G(136, 0),
184 CHAN5G(140, 0), CHAN5G(149, 0),
185 CHAN5G(153, 0), CHAN5G(157, 0),
186 CHAN5G(161, 0), CHAN5G(165, 0),
187 CHAN5G(184, 0), CHAN5G(188, 0),
188 CHAN5G(192, 0), CHAN5G(196, 0),
189 CHAN5G(200, 0), CHAN5G(204, 0),
190 CHAN5G(208, 0), CHAN5G(212, 0),
191 CHAN5G(216, 0),
192};
193
194static struct ieee80211_channel __wl_5ghz_n_channels[] = {
195 CHAN5G(32, 0), CHAN5G(34, 0),
196 CHAN5G(36, 0), CHAN5G(38, 0),
197 CHAN5G(40, 0), CHAN5G(42, 0),
198 CHAN5G(44, 0), CHAN5G(46, 0),
199 CHAN5G(48, 0), CHAN5G(50, 0),
200 CHAN5G(52, 0), CHAN5G(54, 0),
201 CHAN5G(56, 0), CHAN5G(58, 0),
202 CHAN5G(60, 0), CHAN5G(62, 0),
203 CHAN5G(64, 0), CHAN5G(66, 0),
204 CHAN5G(68, 0), CHAN5G(70, 0),
205 CHAN5G(72, 0), CHAN5G(74, 0),
206 CHAN5G(76, 0), CHAN5G(78, 0),
207 CHAN5G(80, 0), CHAN5G(82, 0),
208 CHAN5G(84, 0), CHAN5G(86, 0),
209 CHAN5G(88, 0), CHAN5G(90, 0),
210 CHAN5G(92, 0), CHAN5G(94, 0),
211 CHAN5G(96, 0), CHAN5G(98, 0),
212 CHAN5G(100, 0), CHAN5G(102, 0),
213 CHAN5G(104, 0), CHAN5G(106, 0),
214 CHAN5G(108, 0), CHAN5G(110, 0),
215 CHAN5G(112, 0), CHAN5G(114, 0),
216 CHAN5G(116, 0), CHAN5G(118, 0),
217 CHAN5G(120, 0), CHAN5G(122, 0),
218 CHAN5G(124, 0), CHAN5G(126, 0),
219 CHAN5G(128, 0), CHAN5G(130, 0),
220 CHAN5G(132, 0), CHAN5G(134, 0),
221 CHAN5G(136, 0), CHAN5G(138, 0),
222 CHAN5G(140, 0), CHAN5G(142, 0),
223 CHAN5G(144, 0), CHAN5G(145, 0),
224 CHAN5G(146, 0), CHAN5G(147, 0),
225 CHAN5G(148, 0), CHAN5G(149, 0),
226 CHAN5G(150, 0), CHAN5G(151, 0),
227 CHAN5G(152, 0), CHAN5G(153, 0),
228 CHAN5G(154, 0), CHAN5G(155, 0),
229 CHAN5G(156, 0), CHAN5G(157, 0),
230 CHAN5G(158, 0), CHAN5G(159, 0),
231 CHAN5G(160, 0), CHAN5G(161, 0),
232 CHAN5G(162, 0), CHAN5G(163, 0),
233 CHAN5G(164, 0), CHAN5G(165, 0),
234 CHAN5G(166, 0), CHAN5G(168, 0),
235 CHAN5G(170, 0), CHAN5G(172, 0),
236 CHAN5G(174, 0), CHAN5G(176, 0),
237 CHAN5G(178, 0), CHAN5G(180, 0),
238 CHAN5G(182, 0), CHAN5G(184, 0),
239 CHAN5G(186, 0), CHAN5G(188, 0),
240 CHAN5G(190, 0), CHAN5G(192, 0),
241 CHAN5G(194, 0), CHAN5G(196, 0),
242 CHAN5G(198, 0), CHAN5G(200, 0),
243 CHAN5G(202, 0), CHAN5G(204, 0),
244 CHAN5G(206, 0), CHAN5G(208, 0),
245 CHAN5G(210, 0), CHAN5G(212, 0),
246 CHAN5G(214, 0), CHAN5G(216, 0),
247 CHAN5G(218, 0), CHAN5G(220, 0),
248 CHAN5G(222, 0), CHAN5G(224, 0),
249 CHAN5G(226, 0), CHAN5G(228, 0),
250};
251
252static struct ieee80211_supported_band __wl_band_2ghz = {
253 .band = IEEE80211_BAND_2GHZ,
254 .channels = __wl_2ghz_channels,
255 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
256 .bitrates = wl_g_rates,
257 .n_bitrates = wl_g_rates_size,
258};
259
260static struct ieee80211_supported_band __wl_band_5ghz_a = {
261 .band = IEEE80211_BAND_5GHZ,
262 .channels = __wl_5ghz_a_channels,
263 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
264 .bitrates = wl_a_rates,
265 .n_bitrates = wl_a_rates_size,
266};
267
268static struct ieee80211_supported_band __wl_band_5ghz_n = {
269 .band = IEEE80211_BAND_5GHZ,
270 .channels = __wl_5ghz_n_channels,
271 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
272 .bitrates = wl_a_rates,
273 .n_bitrates = wl_a_rates_size,
274};
275
276static const u32 __wl_cipher_suites[] = {
277 WLAN_CIPHER_SUITE_WEP40,
278 WLAN_CIPHER_SUITE_WEP104,
279 WLAN_CIPHER_SUITE_TKIP,
280 WLAN_CIPHER_SUITE_CCMP,
281 WLAN_CIPHER_SUITE_AES_CMAC,
282};
283
f8e4b412
AB
284/* tag_ID/length/value_buffer tuple */
285struct brcmf_tlv {
286 u8 id;
287 u8 len;
288 u8 data[1];
289};
290
1a873342
HM
291/* Vendor specific ie. id = 221, oui and type defines exact ie */
292struct brcmf_vs_tlv {
293 u8 id;
294 u8 len;
295 u8 oui[3];
296 u8 oui_type;
297};
298
299struct parsed_vndr_ie_info {
300 u8 *ie_ptr;
301 u32 ie_len; /* total length including id & length field */
302 struct brcmf_vs_tlv vndrie;
303};
304
305struct parsed_vndr_ies {
306 u32 count;
307 struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
308};
309
ef6ac17a
AB
310/* Quarter dBm units to mW
311 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
312 * Table is offset so the last entry is largest mW value that fits in
313 * a u16.
314 */
315
316#define QDBM_OFFSET 153 /* Offset for first entry */
317#define QDBM_TABLE_LEN 40 /* Table size */
318
319/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
320 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
321 */
322#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
323
324/* Largest mW value that will round down to the last table entry,
325 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
326 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
327 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
328 */
329#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
330
331static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
332/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
333/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
334/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
335/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
336/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
337/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
338};
339
340static u16 brcmf_qdbm_to_mw(u8 qdbm)
341{
342 uint factor = 1;
343 int idx = qdbm - QDBM_OFFSET;
344
345 if (idx >= QDBM_TABLE_LEN)
346 /* clamp to max u16 mW value */
347 return 0xFFFF;
348
349 /* scale the qdBm index up to the range of the table 0-40
350 * where an offset of 40 qdBm equals a factor of 10 mW.
351 */
352 while (idx < 0) {
353 idx += 40;
354 factor *= 10;
355 }
356
357 /* return the mW value scaled down to the correct factor of 10,
358 * adding in factor/2 to get proper rounding.
359 */
360 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
361}
362
363static u8 brcmf_mw_to_qdbm(u16 mw)
364{
365 u8 qdbm;
366 int offset;
367 uint mw_uint = mw;
368 uint boundary;
369
370 /* handle boundary case */
371 if (mw_uint <= 1)
372 return 0;
373
374 offset = QDBM_OFFSET;
375
376 /* move mw into the range of the table */
377 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
378 mw_uint *= 10;
379 offset -= 40;
380 }
381
382 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
383 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
384 nqdBm_to_mW_map[qdbm]) / 2;
385 if (mw_uint < boundary)
386 break;
387 }
388
389 qdbm += (u8) offset;
390
391 return qdbm;
392}
393
6e186166
AS
394static u16 channel_to_chanspec(struct ieee80211_channel *ch)
395{
396 u16 chanspec;
397
398 chanspec = ieee80211_frequency_to_channel(ch->center_freq);
399 chanspec &= WL_CHANSPEC_CHAN_MASK;
400
401 if (ch->band == IEEE80211_BAND_2GHZ)
402 chanspec |= WL_CHANSPEC_BAND_2G;
403 else
404 chanspec |= WL_CHANSPEC_BAND_5G;
405
406 if (ch->flags & IEEE80211_CHAN_NO_HT40) {
407 chanspec |= WL_CHANSPEC_BW_20;
408 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
409 } else {
410 chanspec |= WL_CHANSPEC_BW_40;
411 if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
412 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
413 else
414 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
415 }
416 return chanspec;
417}
418
5b435de0
AS
419static void convert_key_from_CPU(struct brcmf_wsec_key *key,
420 struct brcmf_wsec_key_le *key_le)
421{
422 key_le->index = cpu_to_le32(key->index);
423 key_le->len = cpu_to_le32(key->len);
424 key_le->algo = cpu_to_le32(key->algo);
425 key_le->flags = cpu_to_le32(key->flags);
426 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
427 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
428 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
429 memcpy(key_le->data, key->data, sizeof(key->data));
430 memcpy(key_le->ea, key->ea, sizeof(key->ea));
431}
432
f09d0c02 433static int
2eaba7e8 434send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
5b435de0
AS
435{
436 int err;
437 struct brcmf_wsec_key_le key_le;
438
439 convert_key_from_CPU(key, &key_le);
f09d0c02 440
81f5dcb8
HM
441 brcmf_netdev_wait_pend8021x(ndev);
442
ac24be6f 443 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
81f5dcb8 444 sizeof(key_le));
f09d0c02 445
5b435de0 446 if (err)
f09d0c02 447 WL_ERR("wsec_key error (%d)\n", err);
5b435de0
AS
448 return err;
449}
450
451static s32
452brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
453 enum nl80211_iftype type, u32 *flags,
454 struct vif_params *params)
455{
c1179033 456 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 457 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5b435de0 458 s32 infra = 0;
1a873342 459 s32 ap = 0;
5b435de0
AS
460 s32 err = 0;
461
1a873342 462 WL_TRACE("Enter, ndev=%p, type=%d\n", ndev, type);
5b435de0
AS
463
464 switch (type) {
465 case NL80211_IFTYPE_MONITOR:
466 case NL80211_IFTYPE_WDS:
467 WL_ERR("type (%d) : currently we do not support this type\n",
468 type);
469 return -EOPNOTSUPP;
470 case NL80211_IFTYPE_ADHOC:
27a68fe3 471 cfg->conf->mode = WL_MODE_IBSS;
5b435de0
AS
472 infra = 0;
473 break;
474 case NL80211_IFTYPE_STATION:
27a68fe3 475 cfg->conf->mode = WL_MODE_BSS;
5b435de0
AS
476 infra = 1;
477 break;
1a873342 478 case NL80211_IFTYPE_AP:
27a68fe3 479 cfg->conf->mode = WL_MODE_AP;
1a873342
HM
480 ap = 1;
481 break;
5b435de0
AS
482 default:
483 err = -EINVAL;
484 goto done;
485 }
486
1a873342 487 if (ap) {
c1179033 488 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
27a68fe3
AS
489 if (!cfg->ap_info)
490 cfg->ap_info = kzalloc(sizeof(*cfg->ap_info),
491 GFP_KERNEL);
492 if (!cfg->ap_info) {
1a873342
HM
493 err = -ENOMEM;
494 goto done;
495 }
496 WL_INFO("IF Type = AP\n");
5b435de0 497 } else {
ac24be6f
AS
498 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
499 BRCMF_C_SET_INFRA, infra);
1a873342
HM
500 if (err) {
501 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
502 err = -EAGAIN;
503 goto done;
504 }
505 WL_INFO("IF Type = %s\n",
27a68fe3 506 (cfg->conf->mode == WL_MODE_IBSS) ?
1a873342 507 "Adhoc" : "Infra");
5b435de0 508 }
1a873342 509 ndev->ieee80211_ptr->iftype = type;
5b435de0
AS
510
511done:
512 WL_TRACE("Exit\n");
513
514 return err;
515}
516
5b435de0
AS
517static void brcmf_set_mpc(struct net_device *ndev, int mpc)
518{
c1179033 519 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 520 s32 err = 0;
5b435de0 521
ce81e317 522 if (check_vif_up(ifp->vif)) {
c1179033 523 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
5b435de0
AS
524 if (err) {
525 WL_ERR("fail to set mpc\n");
526 return;
527 }
528 WL_INFO("MPC : %d\n", mpc);
529 }
530}
531
35aafa9d
HM
532static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
533 struct brcmf_ssid *ssid)
5b435de0 534{
ba40d166 535 memset(params_le->bssid, 0xFF, ETH_ALEN);
5b435de0
AS
536 params_le->bss_type = DOT11_BSSTYPE_ANY;
537 params_le->scan_type = 0;
538 params_le->channel_num = 0;
539 params_le->nprobes = cpu_to_le32(-1);
540 params_le->active_time = cpu_to_le32(-1);
541 params_le->passive_time = cpu_to_le32(-1);
542 params_le->home_time = cpu_to_le32(-1);
ed205b36
HM
543 if (ssid && ssid->SSID_len) {
544 params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len);
545 memcpy(&params_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len);
546 }
5b435de0
AS
547}
548
5b435de0
AS
549static s32
550brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
551 struct brcmf_ssid *ssid, u16 action)
552{
553 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
554 offsetof(struct brcmf_iscan_params_le, params_le);
555 struct brcmf_iscan_params_le *params;
556 s32 err = 0;
557
558 if (ssid && ssid->SSID_len)
559 params_size += sizeof(struct brcmf_ssid);
560 params = kzalloc(params_size, GFP_KERNEL);
561 if (!params)
562 return -ENOMEM;
563 BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
564
35aafa9d 565 brcmf_iscan_prep(&params->params_le, ssid);
5b435de0
AS
566
567 params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
568 params->action = cpu_to_le16(action);
569 params->scan_duration = cpu_to_le16(0);
570
ac24be6f
AS
571 err = brcmf_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan",
572 params, params_size);
5b435de0
AS
573 if (err) {
574 if (err == -EBUSY)
575 WL_INFO("system busy : iscan canceled\n");
576 else
577 WL_ERR("error (%d)\n", err);
578 }
579
580 kfree(params);
581 return err;
582}
583
27a68fe3 584static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg)
5b435de0 585{
27a68fe3
AS
586 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
587 struct net_device *ndev = cfg_to_ndev(cfg);
5b435de0 588 struct brcmf_ssid ssid;
81f5dcb8 589 u32 passive_scan;
5b435de0
AS
590 s32 err = 0;
591
592 /* Broadcast scan by default */
593 memset(&ssid, 0, sizeof(ssid));
594
595 iscan->state = WL_ISCAN_STATE_SCANING;
596
81f5dcb8 597 passive_scan = cfg->active_scan ? 0 : 1;
ac24be6f 598 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
81f5dcb8 599 BRCMF_C_SET_PASSIVE_SCAN, passive_scan);
5b435de0
AS
600 if (err) {
601 WL_ERR("error (%d)\n", err);
602 return err;
603 }
604 brcmf_set_mpc(ndev, 0);
27a68fe3 605 cfg->iscan_kickstart = true;
5b435de0
AS
606 err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
607 if (err) {
608 brcmf_set_mpc(ndev, 1);
27a68fe3 609 cfg->iscan_kickstart = false;
5b435de0
AS
610 return err;
611 }
612 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
613 iscan->timer_on = 1;
614 return err;
615}
616
617static s32
35aafa9d
HM
618brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
619 struct cfg80211_scan_request *request,
620 struct cfg80211_ssid *this_ssid)
5b435de0 621{
c1179033 622 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 623 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
5b435de0 624 struct cfg80211_ssid *ssids;
27a68fe3 625 struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
81f5dcb8 626 u32 passive_scan;
5b435de0
AS
627 bool iscan_req;
628 bool spec_scan;
629 s32 err = 0;
630 u32 SSID_len;
631
c1179033
AS
632 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
633 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
5b435de0
AS
634 return -EAGAIN;
635 }
c1179033
AS
636 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
637 WL_ERR("Scanning being aborted: status (%lu)\n",
638 cfg->scan_status);
5b435de0
AS
639 return -EAGAIN;
640 }
c1179033
AS
641 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
642 WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
5b435de0
AS
643 return -EAGAIN;
644 }
645
646 iscan_req = false;
647 spec_scan = false;
648 if (request) {
649 /* scan bss */
650 ssids = request->ssids;
27a68fe3 651 if (cfg->iscan_on && (!ssids || !ssids->ssid_len))
5b435de0
AS
652 iscan_req = true;
653 } else {
654 /* scan in ibss */
655 /* we don't do iscan in ibss */
656 ssids = this_ssid;
657 }
658
27a68fe3 659 cfg->scan_request = request;
c1179033 660 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
5b435de0 661 if (iscan_req) {
27a68fe3 662 err = brcmf_do_iscan(cfg);
5b435de0
AS
663 if (!err)
664 return err;
665 else
666 goto scan_out;
667 } else {
668 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
669 ssids->ssid, ssids->ssid_len);
670 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
671 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
672 sr->ssid_le.SSID_len = cpu_to_le32(0);
673 if (SSID_len) {
674 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
675 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
676 spec_scan = true;
677 } else {
678 WL_SCAN("Broadcast scan\n");
679 }
680
81f5dcb8 681 passive_scan = cfg->active_scan ? 0 : 1;
c1179033 682 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 683 passive_scan);
5b435de0
AS
684 if (err) {
685 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
686 goto scan_out;
687 }
688 brcmf_set_mpc(ndev, 0);
c1179033 689 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
ac24be6f 690 &sr->ssid_le, sizeof(sr->ssid_le));
5b435de0
AS
691 if (err) {
692 if (err == -EBUSY)
693 WL_INFO("system busy : scan for \"%s\" "
694 "canceled\n", sr->ssid_le.SSID);
695 else
696 WL_ERR("WLC_SCAN error (%d)\n", err);
697
698 brcmf_set_mpc(ndev, 1);
699 goto scan_out;
700 }
701 }
702
703 return 0;
704
705scan_out:
c1179033 706 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 707 cfg->scan_request = NULL;
5b435de0
AS
708 return err;
709}
710
e756af5b
HM
711static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
712 struct cfg80211_scan_request *request)
713{
714 u32 n_ssids;
715 u32 n_channels;
716 s32 i;
717 s32 offset;
029591f3 718 u16 chanspec;
e756af5b 719 char *ptr;
029591f3 720 struct brcmf_ssid_le ssid_le;
e756af5b 721
ba40d166 722 memset(params_le->bssid, 0xFF, ETH_ALEN);
e756af5b
HM
723 params_le->bss_type = DOT11_BSSTYPE_ANY;
724 params_le->scan_type = 0;
725 params_le->channel_num = 0;
726 params_le->nprobes = cpu_to_le32(-1);
727 params_le->active_time = cpu_to_le32(-1);
728 params_le->passive_time = cpu_to_le32(-1);
729 params_le->home_time = cpu_to_le32(-1);
730 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
731
732 /* if request is null exit so it will be all channel broadcast scan */
733 if (!request)
734 return;
735
736 n_ssids = request->n_ssids;
737 n_channels = request->n_channels;
738 /* Copy channel array if applicable */
739 WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);
740 if (n_channels > 0) {
741 for (i = 0; i < n_channels; i++) {
6e186166 742 chanspec = channel_to_chanspec(request->channels[i]);
e756af5b 743 WL_SCAN("Chan : %d, Channel spec: %x\n",
6e186166 744 request->channels[i]->hw_value, chanspec);
029591f3 745 params_le->channel_list[i] = cpu_to_le16(chanspec);
e756af5b
HM
746 }
747 } else {
748 WL_SCAN("Scanning all channels\n");
749 }
750 /* Copy ssid array if applicable */
751 WL_SCAN("### List of SSIDs to scan ### %d\n", n_ssids);
752 if (n_ssids > 0) {
753 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
754 n_channels * sizeof(u16);
755 offset = roundup(offset, sizeof(u32));
756 ptr = (char *)params_le + offset;
757 for (i = 0; i < n_ssids; i++) {
029591f3
AS
758 memset(&ssid_le, 0, sizeof(ssid_le));
759 ssid_le.SSID_len =
760 cpu_to_le32(request->ssids[i].ssid_len);
761 memcpy(ssid_le.SSID, request->ssids[i].ssid,
762 request->ssids[i].ssid_len);
763 if (!ssid_le.SSID_len)
e756af5b
HM
764 WL_SCAN("%d: Broadcast scan\n", i);
765 else
766 WL_SCAN("%d: scan for %s size =%d\n", i,
029591f3
AS
767 ssid_le.SSID, ssid_le.SSID_len);
768 memcpy(ptr, &ssid_le, sizeof(ssid_le));
769 ptr += sizeof(ssid_le);
e756af5b
HM
770 }
771 } else {
772 WL_SCAN("Broadcast scan %p\n", request->ssids);
773 if ((request->ssids) && request->ssids->ssid_len) {
774 WL_SCAN("SSID %s len=%d\n", params_le->ssid_le.SSID,
775 request->ssids->ssid_len);
776 params_le->ssid_le.SSID_len =
777 cpu_to_le32(request->ssids->ssid_len);
778 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
779 request->ssids->ssid_len);
780 }
781 }
782 /* Adding mask to channel numbers */
783 params_le->channel_num =
784 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
785 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
786}
787
788static s32
27a68fe3 789brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
e756af5b
HM
790 struct net_device *ndev,
791 bool aborted, bool fw_abort)
792{
793 struct brcmf_scan_params_le params_le;
794 struct cfg80211_scan_request *scan_request;
795 s32 err = 0;
796
797 WL_SCAN("Enter\n");
798
799 /* clear scan request, because the FW abort can cause a second call */
800 /* to this functon and might cause a double cfg80211_scan_done */
27a68fe3
AS
801 scan_request = cfg->scan_request;
802 cfg->scan_request = NULL;
e756af5b 803
27a68fe3
AS
804 if (timer_pending(&cfg->escan_timeout))
805 del_timer_sync(&cfg->escan_timeout);
e756af5b
HM
806
807 if (fw_abort) {
808 /* Do a scan abort to stop the driver's scan engine */
809 WL_SCAN("ABORT scan in firmware\n");
810 memset(&params_le, 0, sizeof(params_le));
ba40d166 811 memset(params_le.bssid, 0xFF, ETH_ALEN);
e756af5b
HM
812 params_le.bss_type = DOT11_BSSTYPE_ANY;
813 params_le.scan_type = 0;
814 params_le.channel_num = cpu_to_le32(1);
815 params_le.nprobes = cpu_to_le32(1);
816 params_le.active_time = cpu_to_le32(-1);
817 params_le.passive_time = cpu_to_le32(-1);
818 params_le.home_time = cpu_to_le32(-1);
819 /* Scan is aborted by setting channel_list[0] to -1 */
820 params_le.channel_list[0] = cpu_to_le16(-1);
821 /* E-Scan (or anyother type) can be aborted by SCAN */
ac24be6f
AS
822 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
823 &params_le, sizeof(params_le));
e756af5b
HM
824 if (err)
825 WL_ERR("Scan abort failed\n");
826 }
e5806072
AS
827 /*
828 * e-scan can be initiated by scheduled scan
829 * which takes precedence.
830 */
27a68fe3 831 if (cfg->sched_escan) {
e5806072 832 WL_SCAN("scheduled scan completed\n");
27a68fe3 833 cfg->sched_escan = false;
e5806072 834 if (!aborted)
27a68fe3 835 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
e5806072
AS
836 brcmf_set_mpc(ndev, 1);
837 } else if (scan_request) {
e756af5b
HM
838 WL_SCAN("ESCAN Completed scan: %s\n",
839 aborted ? "Aborted" : "Done");
840 cfg80211_scan_done(scan_request, aborted);
841 brcmf_set_mpc(ndev, 1);
842 }
c1179033 843 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e756af5b
HM
844 WL_ERR("Scan complete while device not scanning\n");
845 return -EPERM;
846 }
847
848 return err;
849}
850
851static s32
27a68fe3 852brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
e756af5b
HM
853 struct cfg80211_scan_request *request, u16 action)
854{
855 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
856 offsetof(struct brcmf_escan_params_le, params_le);
857 struct brcmf_escan_params_le *params;
858 s32 err = 0;
859
860 WL_SCAN("E-SCAN START\n");
861
862 if (request != NULL) {
863 /* Allocate space for populating ssids in struct */
864 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
865
866 /* Allocate space for populating ssids in struct */
867 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
868 }
869
870 params = kzalloc(params_size, GFP_KERNEL);
871 if (!params) {
872 err = -ENOMEM;
873 goto exit;
874 }
875 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
876 brcmf_escan_prep(&params->params_le, request);
877 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
878 params->action = cpu_to_le16(action);
879 params->sync_id = cpu_to_le16(0x1234);
880
ac24be6f
AS
881 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
882 params, params_size);
e756af5b
HM
883 if (err) {
884 if (err == -EBUSY)
885 WL_INFO("system busy : escan canceled\n");
886 else
887 WL_ERR("error (%d)\n", err);
888 }
889
890 kfree(params);
891exit:
892 return err;
893}
894
895static s32
27a68fe3 896brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
e756af5b
HM
897 struct net_device *ndev, struct cfg80211_scan_request *request)
898{
899 s32 err;
81f5dcb8 900 u32 passive_scan;
e756af5b
HM
901 struct brcmf_scan_results *results;
902
903 WL_SCAN("Enter\n");
27a68fe3
AS
904 cfg->escan_info.ndev = ndev;
905 cfg->escan_info.wiphy = wiphy;
906 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
81f5dcb8 907 passive_scan = cfg->active_scan ? 0 : 1;
ac24be6f 908 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 909 passive_scan);
e756af5b
HM
910 if (err) {
911 WL_ERR("error (%d)\n", err);
912 return err;
913 }
914 brcmf_set_mpc(ndev, 0);
27a68fe3 915 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
e756af5b
HM
916 results->version = 0;
917 results->count = 0;
918 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
919
27a68fe3 920 err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
e756af5b
HM
921 if (err)
922 brcmf_set_mpc(ndev, 1);
923 return err;
924}
925
926static s32
927brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
928 struct cfg80211_scan_request *request,
929 struct cfg80211_ssid *this_ssid)
930{
c1179033 931 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 932 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
e756af5b 933 struct cfg80211_ssid *ssids;
27a68fe3 934 struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
81f5dcb8 935 u32 passive_scan;
e756af5b
HM
936 bool escan_req;
937 bool spec_scan;
938 s32 err;
939 u32 SSID_len;
940
941 WL_SCAN("START ESCAN\n");
942
c1179033
AS
943 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
944 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
e756af5b
HM
945 return -EAGAIN;
946 }
c1179033
AS
947 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
948 WL_ERR("Scanning being aborted: status (%lu)\n",
949 cfg->scan_status);
e756af5b
HM
950 return -EAGAIN;
951 }
c1179033
AS
952 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
953 WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
e756af5b
HM
954 return -EAGAIN;
955 }
956
957 /* Arm scan timeout timer */
27a68fe3 958 mod_timer(&cfg->escan_timeout, jiffies +
e756af5b
HM
959 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
960
961 escan_req = false;
962 if (request) {
963 /* scan bss */
964 ssids = request->ssids;
965 escan_req = true;
966 } else {
967 /* scan in ibss */
968 /* we don't do escan in ibss */
969 ssids = this_ssid;
970 }
971
27a68fe3 972 cfg->scan_request = request;
c1179033 973 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e756af5b 974 if (escan_req) {
27a68fe3 975 err = brcmf_do_escan(cfg, wiphy, ndev, request);
e756af5b
HM
976 if (!err)
977 return err;
978 else
979 goto scan_out;
980 } else {
981 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
982 ssids->ssid, ssids->ssid_len);
983 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
984 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
985 sr->ssid_le.SSID_len = cpu_to_le32(0);
986 spec_scan = false;
987 if (SSID_len) {
988 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
989 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
990 spec_scan = true;
991 } else
992 WL_SCAN("Broadcast scan\n");
993
81f5dcb8 994 passive_scan = cfg->active_scan ? 0 : 1;
c1179033 995 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
81f5dcb8 996 passive_scan);
e756af5b
HM
997 if (err) {
998 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
999 goto scan_out;
1000 }
1001 brcmf_set_mpc(ndev, 0);
c1179033 1002 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
ac24be6f 1003 &sr->ssid_le, sizeof(sr->ssid_le));
e756af5b
HM
1004 if (err) {
1005 if (err == -EBUSY)
1006 WL_INFO("BUSY: scan for \"%s\" canceled\n",
1007 sr->ssid_le.SSID);
1008 else
1009 WL_ERR("WLC_SCAN error (%d)\n", err);
1010
1011 brcmf_set_mpc(ndev, 1);
1012 goto scan_out;
1013 }
1014 }
1015
1016 return 0;
1017
1018scan_out:
c1179033 1019 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3
AS
1020 if (timer_pending(&cfg->escan_timeout))
1021 del_timer_sync(&cfg->escan_timeout);
1022 cfg->scan_request = NULL;
e756af5b
HM
1023 return err;
1024}
1025
5b435de0 1026static s32
0abb5f21 1027brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
5b435de0 1028{
fd014284 1029 struct net_device *ndev = request->wdev->netdev;
27a68fe3 1030 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
5b435de0
AS
1031 s32 err = 0;
1032
1033 WL_TRACE("Enter\n");
1034
ce81e317 1035 if (!check_vif_up(container_of(request->wdev,
0abb5f21 1036 struct brcmf_cfg80211_vif, wdev)))
5b435de0
AS
1037 return -EIO;
1038
27a68fe3 1039 if (cfg->iscan_on)
e756af5b 1040 err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL);
27a68fe3 1041 else if (cfg->escan_on)
e756af5b
HM
1042 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
1043
5b435de0
AS
1044 if (err)
1045 WL_ERR("scan error (%d)\n", err);
1046
1047 WL_TRACE("Exit\n");
1048 return err;
1049}
1050
1051static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1052{
1053 s32 err = 0;
1054
ac24be6f
AS
1055 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1056 rts_threshold);
5b435de0
AS
1057 if (err)
1058 WL_ERR("Error (%d)\n", err);
1059
1060 return err;
1061}
1062
1063static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1064{
1065 s32 err = 0;
1066
ac24be6f
AS
1067 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1068 frag_threshold);
5b435de0
AS
1069 if (err)
1070 WL_ERR("Error (%d)\n", err);
1071
1072 return err;
1073}
1074
1075static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1076{
1077 s32 err = 0;
1078 u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
1079
ac24be6f 1080 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
5b435de0
AS
1081 if (err) {
1082 WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
1083 return err;
1084 }
1085 return err;
1086}
1087
1088static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1089{
27a68fe3
AS
1090 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1091 struct net_device *ndev = cfg_to_ndev(cfg);
0abb5f21 1092 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1093 s32 err = 0;
1094
1095 WL_TRACE("Enter\n");
ce81e317 1096 if (!check_vif_up(ifp->vif))
5b435de0
AS
1097 return -EIO;
1098
1099 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
27a68fe3
AS
1100 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1101 cfg->conf->rts_threshold = wiphy->rts_threshold;
1102 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
5b435de0
AS
1103 if (!err)
1104 goto done;
1105 }
1106 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
27a68fe3
AS
1107 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1108 cfg->conf->frag_threshold = wiphy->frag_threshold;
1109 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
5b435de0
AS
1110 if (!err)
1111 goto done;
1112 }
1113 if (changed & WIPHY_PARAM_RETRY_LONG
27a68fe3
AS
1114 && (cfg->conf->retry_long != wiphy->retry_long)) {
1115 cfg->conf->retry_long = wiphy->retry_long;
1116 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
5b435de0
AS
1117 if (!err)
1118 goto done;
1119 }
1120 if (changed & WIPHY_PARAM_RETRY_SHORT
27a68fe3
AS
1121 && (cfg->conf->retry_short != wiphy->retry_short)) {
1122 cfg->conf->retry_short = wiphy->retry_short;
1123 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
5b435de0
AS
1124 if (!err)
1125 goto done;
1126 }
1127
1128done:
1129 WL_TRACE("Exit\n");
1130 return err;
1131}
1132
5b435de0
AS
1133static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1134{
1135 memset(prof, 0, sizeof(*prof));
1136}
1137
1138static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
1139 size_t *join_params_size)
1140{
1141 u16 chanspec = 0;
1142
1143 if (ch != 0) {
1144 if (ch <= CH_MAX_2G_CHANNEL)
1145 chanspec |= WL_CHANSPEC_BAND_2G;
1146 else
1147 chanspec |= WL_CHANSPEC_BAND_5G;
1148
1149 chanspec |= WL_CHANSPEC_BW_20;
1150 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1151
1152 *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
1153 sizeof(u16);
1154
1155 chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
1156 join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1157 join_params->params_le.chanspec_num = cpu_to_le32(1);
1158
1159 WL_CONN("join_params->params.chanspec_list[0]= %#X,"
1160 "channel %d, chanspec %#X\n",
1161 chanspec, ch, chanspec);
1162 }
1163}
1164
27a68fe3 1165static void brcmf_link_down(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
1166{
1167 struct net_device *ndev = NULL;
1168 s32 err = 0;
1169
1170 WL_TRACE("Enter\n");
1171
27a68fe3
AS
1172 if (cfg->link_up) {
1173 ndev = cfg_to_ndev(cfg);
5b435de0 1174 WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
ac24be6f
AS
1175 err = brcmf_fil_cmd_data_set(netdev_priv(ndev),
1176 BRCMF_C_DISASSOC, NULL, 0);
5b435de0
AS
1177 if (err)
1178 WL_ERR("WLC_DISASSOC failed (%d)\n", err);
27a68fe3 1179 cfg->link_up = false;
5b435de0
AS
1180 }
1181 WL_TRACE("Exit\n");
1182}
1183
1184static s32
1185brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1186 struct cfg80211_ibss_params *params)
1187{
27a68fe3 1188 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1189 struct brcmf_if *ifp = netdev_priv(ndev);
1190 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1191 struct brcmf_join_params join_params;
1192 size_t join_params_size = 0;
1193 s32 err = 0;
1194 s32 wsec = 0;
1195 s32 bcnprd;
5b435de0
AS
1196
1197 WL_TRACE("Enter\n");
ce81e317 1198 if (!check_vif_up(ifp->vif))
5b435de0
AS
1199 return -EIO;
1200
1201 if (params->ssid)
1202 WL_CONN("SSID: %s\n", params->ssid);
1203 else {
1204 WL_CONN("SSID: NULL, Not supported\n");
1205 return -EOPNOTSUPP;
1206 }
1207
c1179033 1208 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1209
1210 if (params->bssid)
040a7831 1211 WL_CONN("BSSID: %pM\n", params->bssid);
5b435de0
AS
1212 else
1213 WL_CONN("No BSSID specified\n");
1214
1215 if (params->channel)
1216 WL_CONN("channel: %d\n", params->channel->center_freq);
1217 else
1218 WL_CONN("no channel specified\n");
1219
1220 if (params->channel_fixed)
1221 WL_CONN("fixed channel required\n");
1222 else
1223 WL_CONN("no fixed channel required\n");
1224
1225 if (params->ie && params->ie_len)
1226 WL_CONN("ie len: %d\n", params->ie_len);
1227 else
1228 WL_CONN("no ie specified\n");
1229
1230 if (params->beacon_interval)
1231 WL_CONN("beacon interval: %d\n", params->beacon_interval);
1232 else
1233 WL_CONN("no beacon interval specified\n");
1234
1235 if (params->basic_rates)
1236 WL_CONN("basic rates: %08X\n", params->basic_rates);
1237 else
1238 WL_CONN("no basic rates specified\n");
1239
1240 if (params->privacy)
1241 WL_CONN("privacy required\n");
1242 else
1243 WL_CONN("no privacy required\n");
1244
1245 /* Configure Privacy for starter */
1246 if (params->privacy)
1247 wsec |= WEP_ENABLED;
1248
c1179033 1249 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
5b435de0
AS
1250 if (err) {
1251 WL_ERR("wsec failed (%d)\n", err);
1252 goto done;
1253 }
1254
1255 /* Configure Beacon Interval for starter */
1256 if (params->beacon_interval)
1257 bcnprd = params->beacon_interval;
1258 else
1259 bcnprd = 100;
1260
c1179033 1261 err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);
5b435de0
AS
1262 if (err) {
1263 WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
1264 goto done;
1265 }
1266
1267 /* Configure required join parameter */
1268 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1269
1270 /* SSID */
6c8c4f72
AS
1271 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1272 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1273 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1274 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
5b435de0 1275 join_params_size = sizeof(join_params.ssid_le);
5b435de0
AS
1276
1277 /* BSSID */
1278 if (params->bssid) {
1279 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1280 join_params_size = sizeof(join_params.ssid_le) +
1281 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
6c8c4f72 1282 memcpy(profile->bssid, params->bssid, ETH_ALEN);
5b435de0 1283 } else {
ba40d166 1284 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
6c8c4f72 1285 memset(profile->bssid, 0, ETH_ALEN);
5b435de0
AS
1286 }
1287
5b435de0
AS
1288 /* Channel */
1289 if (params->channel) {
1290 u32 target_channel;
1291
27a68fe3 1292 cfg->channel =
5b435de0
AS
1293 ieee80211_frequency_to_channel(
1294 params->channel->center_freq);
1295 if (params->channel_fixed) {
1296 /* adding chanspec */
27a68fe3 1297 brcmf_ch_to_chanspec(cfg->channel,
5b435de0
AS
1298 &join_params, &join_params_size);
1299 }
1300
1301 /* set channel for starter */
27a68fe3 1302 target_channel = cfg->channel;
c1179033 1303 err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL,
81f5dcb8 1304 target_channel);
5b435de0
AS
1305 if (err) {
1306 WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
1307 goto done;
1308 }
1309 } else
27a68fe3 1310 cfg->channel = 0;
5b435de0 1311
27a68fe3 1312 cfg->ibss_starter = false;
5b435de0
AS
1313
1314
c1179033 1315 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1316 &join_params, join_params_size);
5b435de0
AS
1317 if (err) {
1318 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1319 goto done;
1320 }
1321
1322done:
1323 if (err)
c1179033 1324 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1325 WL_TRACE("Exit\n");
1326 return err;
1327}
1328
1329static s32
1330brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1331{
27a68fe3 1332 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 1333 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1334 s32 err = 0;
1335
1336 WL_TRACE("Enter\n");
ce81e317 1337 if (!check_vif_up(ifp->vif))
5b435de0
AS
1338 return -EIO;
1339
27a68fe3 1340 brcmf_link_down(cfg);
5b435de0
AS
1341
1342 WL_TRACE("Exit\n");
1343
1344 return err;
1345}
1346
1347static s32 brcmf_set_wpa_version(struct net_device *ndev,
1348 struct cfg80211_connect_params *sme)
1349{
6ac4f4ed 1350 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1351 struct brcmf_cfg80211_security *sec;
1352 s32 val = 0;
1353 s32 err = 0;
1354
1355 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1356 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1357 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1358 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1359 else
1360 val = WPA_AUTH_DISABLED;
1361 WL_CONN("setting wpa_auth to 0x%0x\n", val);
ac24be6f 1362 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
5b435de0
AS
1363 if (err) {
1364 WL_ERR("set wpa_auth failed (%d)\n", err);
1365 return err;
1366 }
06bb123e 1367 sec = &profile->sec;
5b435de0
AS
1368 sec->wpa_versions = sme->crypto.wpa_versions;
1369 return err;
1370}
1371
1372static s32 brcmf_set_auth_type(struct net_device *ndev,
1373 struct cfg80211_connect_params *sme)
1374{
6ac4f4ed 1375 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1376 struct brcmf_cfg80211_security *sec;
1377 s32 val = 0;
1378 s32 err = 0;
1379
1380 switch (sme->auth_type) {
1381 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1382 val = 0;
1383 WL_CONN("open system\n");
1384 break;
1385 case NL80211_AUTHTYPE_SHARED_KEY:
1386 val = 1;
1387 WL_CONN("shared key\n");
1388 break;
1389 case NL80211_AUTHTYPE_AUTOMATIC:
1390 val = 2;
1391 WL_CONN("automatic\n");
1392 break;
1393 case NL80211_AUTHTYPE_NETWORK_EAP:
1394 WL_CONN("network eap\n");
1395 default:
1396 val = 2;
1397 WL_ERR("invalid auth type (%d)\n", sme->auth_type);
1398 break;
1399 }
1400
ac24be6f 1401 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
5b435de0
AS
1402 if (err) {
1403 WL_ERR("set auth failed (%d)\n", err);
1404 return err;
1405 }
06bb123e 1406 sec = &profile->sec;
5b435de0
AS
1407 sec->auth_type = sme->auth_type;
1408 return err;
1409}
1410
1411static s32
1412brcmf_set_set_cipher(struct net_device *ndev,
1413 struct cfg80211_connect_params *sme)
1414{
6ac4f4ed 1415 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1416 struct brcmf_cfg80211_security *sec;
1417 s32 pval = 0;
1418 s32 gval = 0;
1419 s32 err = 0;
1420
1421 if (sme->crypto.n_ciphers_pairwise) {
1422 switch (sme->crypto.ciphers_pairwise[0]) {
1423 case WLAN_CIPHER_SUITE_WEP40:
1424 case WLAN_CIPHER_SUITE_WEP104:
1425 pval = WEP_ENABLED;
1426 break;
1427 case WLAN_CIPHER_SUITE_TKIP:
1428 pval = TKIP_ENABLED;
1429 break;
1430 case WLAN_CIPHER_SUITE_CCMP:
1431 pval = AES_ENABLED;
1432 break;
1433 case WLAN_CIPHER_SUITE_AES_CMAC:
1434 pval = AES_ENABLED;
1435 break;
1436 default:
1437 WL_ERR("invalid cipher pairwise (%d)\n",
1438 sme->crypto.ciphers_pairwise[0]);
1439 return -EINVAL;
1440 }
1441 }
1442 if (sme->crypto.cipher_group) {
1443 switch (sme->crypto.cipher_group) {
1444 case WLAN_CIPHER_SUITE_WEP40:
1445 case WLAN_CIPHER_SUITE_WEP104:
1446 gval = WEP_ENABLED;
1447 break;
1448 case WLAN_CIPHER_SUITE_TKIP:
1449 gval = TKIP_ENABLED;
1450 break;
1451 case WLAN_CIPHER_SUITE_CCMP:
1452 gval = AES_ENABLED;
1453 break;
1454 case WLAN_CIPHER_SUITE_AES_CMAC:
1455 gval = AES_ENABLED;
1456 break;
1457 default:
1458 WL_ERR("invalid cipher group (%d)\n",
1459 sme->crypto.cipher_group);
1460 return -EINVAL;
1461 }
1462 }
1463
1464 WL_CONN("pval (%d) gval (%d)\n", pval, gval);
ac24be6f 1465 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
5b435de0
AS
1466 if (err) {
1467 WL_ERR("error (%d)\n", err);
1468 return err;
1469 }
1470
06bb123e 1471 sec = &profile->sec;
5b435de0
AS
1472 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1473 sec->cipher_group = sme->crypto.cipher_group;
1474
1475 return err;
1476}
1477
1478static s32
1479brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1480{
6ac4f4ed 1481 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1482 struct brcmf_cfg80211_security *sec;
1483 s32 val = 0;
1484 s32 err = 0;
1485
1486 if (sme->crypto.n_akm_suites) {
ac24be6f
AS
1487 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1488 "wpa_auth", &val);
5b435de0
AS
1489 if (err) {
1490 WL_ERR("could not get wpa_auth (%d)\n", err);
1491 return err;
1492 }
1493 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1494 switch (sme->crypto.akm_suites[0]) {
1495 case WLAN_AKM_SUITE_8021X:
1496 val = WPA_AUTH_UNSPECIFIED;
1497 break;
1498 case WLAN_AKM_SUITE_PSK:
1499 val = WPA_AUTH_PSK;
1500 break;
1501 default:
1502 WL_ERR("invalid cipher group (%d)\n",
1503 sme->crypto.cipher_group);
1504 return -EINVAL;
1505 }
1506 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1507 switch (sme->crypto.akm_suites[0]) {
1508 case WLAN_AKM_SUITE_8021X:
1509 val = WPA2_AUTH_UNSPECIFIED;
1510 break;
1511 case WLAN_AKM_SUITE_PSK:
1512 val = WPA2_AUTH_PSK;
1513 break;
1514 default:
1515 WL_ERR("invalid cipher group (%d)\n",
1516 sme->crypto.cipher_group);
1517 return -EINVAL;
1518 }
1519 }
1520
1521 WL_CONN("setting wpa_auth to %d\n", val);
ac24be6f
AS
1522 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1523 "wpa_auth", val);
5b435de0
AS
1524 if (err) {
1525 WL_ERR("could not set wpa_auth (%d)\n", err);
1526 return err;
1527 }
1528 }
06bb123e 1529 sec = &profile->sec;
5b435de0
AS
1530 sec->wpa_auth = sme->crypto.akm_suites[0];
1531
1532 return err;
1533}
1534
1535static s32
f09d0c02
HM
1536brcmf_set_sharedkey(struct net_device *ndev,
1537 struct cfg80211_connect_params *sme)
5b435de0 1538{
6ac4f4ed 1539 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
5b435de0
AS
1540 struct brcmf_cfg80211_security *sec;
1541 struct brcmf_wsec_key key;
1542 s32 val;
1543 s32 err = 0;
1544
1545 WL_CONN("key len (%d)\n", sme->key_len);
5b435de0 1546
a718e2fe
RV
1547 if (sme->key_len == 0)
1548 return 0;
1549
06bb123e 1550 sec = &profile->sec;
a718e2fe
RV
1551 WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
1552 sec->wpa_versions, sec->cipher_pairwise);
1553
1554 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1555 return 0;
1556
f09d0c02
HM
1557 if (!(sec->cipher_pairwise &
1558 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1559 return 0;
a718e2fe 1560
f09d0c02
HM
1561 memset(&key, 0, sizeof(key));
1562 key.len = (u32) sme->key_len;
1563 key.index = (u32) sme->key_idx;
1564 if (key.len > sizeof(key.data)) {
1565 WL_ERR("Too long key length (%u)\n", key.len);
1566 return -EINVAL;
1567 }
1568 memcpy(key.data, sme->key, key.len);
1569 key.flags = BRCMF_PRIMARY_KEY;
1570 switch (sec->cipher_pairwise) {
1571 case WLAN_CIPHER_SUITE_WEP40:
1572 key.algo = CRYPTO_ALGO_WEP1;
1573 break;
1574 case WLAN_CIPHER_SUITE_WEP104:
1575 key.algo = CRYPTO_ALGO_WEP128;
1576 break;
1577 default:
1578 WL_ERR("Invalid algorithm (%d)\n",
1579 sme->crypto.ciphers_pairwise[0]);
1580 return -EINVAL;
1581 }
1582 /* Set the new key/index */
1583 WL_CONN("key length (%d) key index (%d) algo (%d)\n",
1584 key.len, key.index, key.algo);
1585 WL_CONN("key \"%s\"\n", key.data);
2eaba7e8 1586 err = send_key_to_dongle(ndev, &key);
f09d0c02
HM
1587 if (err)
1588 return err;
1589
1590 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
1591 WL_CONN("set auth_type to shared key\n");
1592 val = WL_AUTH_SHARED_KEY; /* shared key */
ac24be6f 1593 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
f09d0c02
HM
1594 if (err)
1595 WL_ERR("set auth failed (%d)\n", err);
5b435de0
AS
1596 }
1597 return err;
1598}
1599
1600static s32
1601brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1602 struct cfg80211_connect_params *sme)
1603{
27a68fe3 1604 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1605 struct brcmf_if *ifp = netdev_priv(ndev);
1606 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1607 struct ieee80211_channel *chan = sme->channel;
1608 struct brcmf_join_params join_params;
1609 size_t join_params_size;
1610 struct brcmf_ssid ssid;
1611
1612 s32 err = 0;
1613
1614 WL_TRACE("Enter\n");
ce81e317 1615 if (!check_vif_up(ifp->vif))
5b435de0
AS
1616 return -EIO;
1617
1618 if (!sme->ssid) {
1619 WL_ERR("Invalid ssid\n");
1620 return -EOPNOTSUPP;
1621 }
1622
c1179033 1623 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1624
1625 if (chan) {
27a68fe3 1626 cfg->channel =
5b435de0
AS
1627 ieee80211_frequency_to_channel(chan->center_freq);
1628 WL_CONN("channel (%d), center_req (%d)\n",
27a68fe3 1629 cfg->channel, chan->center_freq);
5b435de0 1630 } else
27a68fe3 1631 cfg->channel = 0;
5b435de0
AS
1632
1633 WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1634
1635 err = brcmf_set_wpa_version(ndev, sme);
1636 if (err) {
1637 WL_ERR("wl_set_wpa_version failed (%d)\n", err);
1638 goto done;
1639 }
1640
1641 err = brcmf_set_auth_type(ndev, sme);
1642 if (err) {
1643 WL_ERR("wl_set_auth_type failed (%d)\n", err);
1644 goto done;
1645 }
1646
1647 err = brcmf_set_set_cipher(ndev, sme);
1648 if (err) {
1649 WL_ERR("wl_set_set_cipher failed (%d)\n", err);
1650 goto done;
1651 }
1652
1653 err = brcmf_set_key_mgmt(ndev, sme);
1654 if (err) {
1655 WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
1656 goto done;
1657 }
1658
f09d0c02 1659 err = brcmf_set_sharedkey(ndev, sme);
5b435de0 1660 if (err) {
f09d0c02 1661 WL_ERR("brcmf_set_sharedkey failed (%d)\n", err);
5b435de0
AS
1662 goto done;
1663 }
1664
1665 memset(&join_params, 0, sizeof(join_params));
1666 join_params_size = sizeof(join_params.ssid_le);
1667
6c8c4f72
AS
1668 profile->ssid.SSID_len = min_t(u32,
1669 sizeof(ssid.SSID), (u32)sme->ssid_len);
1670 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1671 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1672 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
5b435de0 1673
ba40d166 1674 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
5b435de0
AS
1675
1676 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
1677 WL_CONN("ssid \"%s\", len (%d)\n",
1678 ssid.SSID, ssid.SSID_len);
1679
27a68fe3 1680 brcmf_ch_to_chanspec(cfg->channel,
5b435de0 1681 &join_params, &join_params_size);
c1179033 1682 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
81f5dcb8 1683 &join_params, join_params_size);
5b435de0
AS
1684 if (err)
1685 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1686
1687done:
1688 if (err)
c1179033 1689 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
5b435de0
AS
1690 WL_TRACE("Exit\n");
1691 return err;
1692}
1693
1694static s32
1695brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1696 u16 reason_code)
1697{
27a68fe3 1698 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1699 struct brcmf_if *ifp = netdev_priv(ndev);
1700 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
1701 struct brcmf_scb_val_le scbval;
1702 s32 err = 0;
1703
1704 WL_TRACE("Enter. Reason code = %d\n", reason_code);
ce81e317 1705 if (!check_vif_up(ifp->vif))
5b435de0
AS
1706 return -EIO;
1707
c1179033 1708 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
5b435de0 1709
06bb123e 1710 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
5b435de0 1711 scbval.val = cpu_to_le32(reason_code);
c1179033 1712 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
ac24be6f 1713 &scbval, sizeof(scbval));
5b435de0
AS
1714 if (err)
1715 WL_ERR("error (%d)\n", err);
1716
27a68fe3 1717 cfg->link_up = false;
5b435de0
AS
1718
1719 WL_TRACE("Exit\n");
1720 return err;
1721}
1722
1723static s32
c8442118 1724brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
d3f31134 1725 enum nl80211_tx_power_setting type, s32 mbm)
5b435de0
AS
1726{
1727
27a68fe3 1728 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21
AS
1729 struct net_device *ndev = cfg_to_ndev(cfg);
1730 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
1731 u16 txpwrmw;
1732 s32 err = 0;
1733 s32 disable = 0;
d3f31134 1734 s32 dbm = MBM_TO_DBM(mbm);
5b435de0
AS
1735
1736 WL_TRACE("Enter\n");
ce81e317 1737 if (!check_vif_up(ifp->vif))
5b435de0
AS
1738 return -EIO;
1739
1740 switch (type) {
1741 case NL80211_TX_POWER_AUTOMATIC:
1742 break;
1743 case NL80211_TX_POWER_LIMITED:
5b435de0
AS
1744 case NL80211_TX_POWER_FIXED:
1745 if (dbm < 0) {
1746 WL_ERR("TX_POWER_FIXED - dbm is negative\n");
1747 err = -EINVAL;
1748 goto done;
1749 }
1750 break;
1751 }
1752 /* Make sure radio is off or on as far as software is concerned */
1753 disable = WL_RADIO_SW_DISABLE << 16;
ac24be6f 1754 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
5b435de0
AS
1755 if (err)
1756 WL_ERR("WLC_SET_RADIO error (%d)\n", err);
1757
1758 if (dbm > 0xffff)
1759 txpwrmw = 0xffff;
1760 else
1761 txpwrmw = (u16) dbm;
ac24be6f
AS
1762 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1763 (s32)brcmf_mw_to_qdbm(txpwrmw));
5b435de0
AS
1764 if (err)
1765 WL_ERR("qtxpower error (%d)\n", err);
27a68fe3 1766 cfg->conf->tx_power = dbm;
5b435de0
AS
1767
1768done:
1769 WL_TRACE("Exit\n");
1770 return err;
1771}
1772
c8442118
JB
1773static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1774 struct wireless_dev *wdev,
1775 s32 *dbm)
5b435de0 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");
ce81e317 1784 if (!check_vif_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);
ce81e317 1812 if (!check_vif_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);
ce81e317 1928 if (!check_vif_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");
ce81e317 2016 if (!check_vif_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);
ce81e317 2057 if (!check_vif_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);
ce81e317 2124 if (!check_vif_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;
ce81e317 2203 if (!check_vif_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");
ce81e317 2239 if (!check_vif_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
ce81e317 3001 if (check_vif_up(ifp->vif))
823e1c81 3002 brcmf_invoke_iscan(cfg);
5b435de0
AS
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);
7d641072 3013 struct brcmf_cfg80211_vif *vif;
5b435de0
AS
3014
3015 WL_TRACE("Enter\n");
3016
3017 /*
7d641072
AS
3018 * if the primary net_device is not READY there is nothing
3019 * we can do but pray resume goes smoothly.
5b435de0 3020 */
7d641072
AS
3021 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
3022 if (!check_vif_up(vif))
3023 goto exit;
5b435de0 3024
7d641072
AS
3025 list_for_each_entry(vif, &cfg->vif_list, list) {
3026 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3027 continue;
5b435de0 3028 /*
7d641072
AS
3029 * While going to suspend if associated with AP disassociate
3030 * from AP to save power while system is in suspended state
5b435de0 3031 */
7d641072
AS
3032 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
3033 test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
3034 WL_INFO("Disassociating from AP before suspend\n");
3035 brcmf_link_down(cfg);
3036
3037 /* Make sure WPA_Supplicant receives all the event
3038 * generated due to DISASSOC call to the fw to keep
3039 * the state fw and WPA_Supplicant state consistent
3040 */
3041 brcmf_delay(500);
3042 }
5b435de0
AS
3043 }
3044
7d641072
AS
3045 /* end any scanning */
3046 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 3047 brcmf_abort_scanning(cfg);
5b435de0
AS
3048
3049 /* Turn off watchdog timer */
7d641072 3050 brcmf_set_mpc(ndev, 1);
5b435de0 3051
7d641072 3052exit:
5b435de0 3053 WL_TRACE("Exit\n");
7d641072
AS
3054 /* clear any scanning activity */
3055 cfg->scan_status = 0;
5b435de0
AS
3056 return 0;
3057}
3058
5b435de0
AS
3059static __used s32
3060brcmf_update_pmklist(struct net_device *ndev,
3061 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
3062{
3063 int i, j;
40c8e95a 3064 int pmkid_len;
5b435de0 3065
40c8e95a
AS
3066 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
3067
3068 WL_CONN("No of elements %d\n", pmkid_len);
3069 for (i = 0; i < pmkid_len; i++) {
5b435de0
AS
3070 WL_CONN("PMKID[%d]: %pM =\n", i,
3071 &pmk_list->pmkids.pmkid[i].BSSID);
3072 for (j = 0; j < WLAN_PMKID_LEN; j++)
3073 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
3074 }
3075
3076 if (!err)
ac24be6f
AS
3077 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
3078 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
3079
3080 return err;
3081}
3082
3083static s32
3084brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3085 struct cfg80211_pmksa *pmksa)
3086{
27a68fe3 3087 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3088 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3089 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
3090 s32 err = 0;
3091 int i;
40c8e95a 3092 int pmkid_len;
5b435de0
AS
3093
3094 WL_TRACE("Enter\n");
ce81e317 3095 if (!check_vif_up(ifp->vif))
5b435de0
AS
3096 return -EIO;
3097
40c8e95a
AS
3098 pmkid_len = le32_to_cpu(pmkids->npmkid);
3099 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
3100 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
3101 break;
3102 if (i < WL_NUM_PMKIDS_MAX) {
3103 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
3104 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
3105 if (i == pmkid_len) {
3106 pmkid_len++;
3107 pmkids->npmkid = cpu_to_le32(pmkid_len);
3108 }
5b435de0
AS
3109 } else
3110 err = -EINVAL;
3111
3112 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
40c8e95a 3113 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 3114 for (i = 0; i < WLAN_PMKID_LEN; i++)
40c8e95a 3115 WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 3116
27a68fe3 3117 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3118
3119 WL_TRACE("Exit\n");
3120 return err;
3121}
3122
3123static s32
3124brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3125 struct cfg80211_pmksa *pmksa)
3126{
27a68fe3 3127 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3128 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3129 struct pmkid_list pmkid;
3130 s32 err = 0;
40c8e95a 3131 int i, pmkid_len;
5b435de0
AS
3132
3133 WL_TRACE("Enter\n");
ce81e317 3134 if (!check_vif_up(ifp->vif))
5b435de0
AS
3135 return -EIO;
3136
3137 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
3138 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
3139
3140 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3141 &pmkid.pmkid[0].BSSID);
3142 for (i = 0; i < WLAN_PMKID_LEN; i++)
3143 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
3144
27a68fe3 3145 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 3146 for (i = 0; i < pmkid_len; i++)
5b435de0 3147 if (!memcmp
27a68fe3 3148 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
3149 ETH_ALEN))
3150 break;
3151
40c8e95a
AS
3152 if ((pmkid_len > 0)
3153 && (i < pmkid_len)) {
27a68fe3 3154 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 3155 sizeof(struct pmkid));
40c8e95a 3156 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
3157 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
3158 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 3159 ETH_ALEN);
27a68fe3
AS
3160 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
3161 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
3162 WLAN_PMKID_LEN);
3163 }
27a68fe3 3164 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
3165 } else
3166 err = -EINVAL;
3167
27a68fe3 3168 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3169
3170 WL_TRACE("Exit\n");
3171 return err;
3172
3173}
3174
3175static s32
3176brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3177{
27a68fe3 3178 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 3179 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
3180 s32 err = 0;
3181
3182 WL_TRACE("Enter\n");
ce81e317 3183 if (!check_vif_up(ifp->vif))
5b435de0
AS
3184 return -EIO;
3185
27a68fe3
AS
3186 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
3187 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
3188
3189 WL_TRACE("Exit\n");
3190 return err;
3191
3192}
3193
e5806072
AS
3194/*
3195 * PFN result doesn't have all the info which are
3196 * required by the supplicant
3197 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3198 * via wl_inform_single_bss in the required format. Escan does require the
3199 * scan request in the form of cfg80211_scan_request. For timebeing, create
3200 * cfg80211_scan_request one out of the received PNO event.
3201 */
3202static s32
27a68fe3 3203brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
e5806072
AS
3204 struct net_device *ndev,
3205 const struct brcmf_event_msg *e, void *data)
3206{
3207 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3208 struct cfg80211_scan_request *request = NULL;
3209 struct cfg80211_ssid *ssid = NULL;
3210 struct ieee80211_channel *channel = NULL;
27a68fe3 3211 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
3212 int err = 0;
3213 int channel_req = 0;
3214 int band = 0;
3215 struct brcmf_pno_scanresults_le *pfn_result;
3216 u32 result_count;
3217 u32 status;
3218
3219 WL_SCAN("Enter\n");
3220
3221 if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
3222 WL_SCAN("PFN NET LOST event. Do Nothing\n");
3223 return 0;
3224 }
3225
3226 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3227 result_count = le32_to_cpu(pfn_result->count);
3228 status = le32_to_cpu(pfn_result->status);
3229
3230 /*
3231 * PFN event is limited to fit 512 bytes so we may get
3232 * multiple NET_FOUND events. For now place a warning here.
3233 */
3234 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3235 WL_SCAN("PFN NET FOUND event. count: %d\n", result_count);
3236 if (result_count > 0) {
3237 int i;
3238
3239 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
3240 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3241 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
3242 if (!request || !ssid || !channel) {
3243 err = -ENOMEM;
3244 goto out_err;
3245 }
3246
3247 request->wiphy = wiphy;
3248 data += sizeof(struct brcmf_pno_scanresults_le);
3249 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3250
3251 for (i = 0; i < result_count; i++) {
3252 netinfo = &netinfo_start[i];
3253 if (!netinfo) {
3254 WL_ERR("Invalid netinfo ptr. index: %d\n", i);
3255 err = -EINVAL;
3256 goto out_err;
3257 }
3258
3259 WL_SCAN("SSID:%s Channel:%d\n",
3260 netinfo->SSID, netinfo->channel);
3261 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3262 ssid[i].ssid_len = netinfo->SSID_len;
3263 request->n_ssids++;
3264
3265 channel_req = netinfo->channel;
3266 if (channel_req <= CH_MAX_2G_CHANNEL)
3267 band = NL80211_BAND_2GHZ;
3268 else
3269 band = NL80211_BAND_5GHZ;
3270 channel[i].center_freq =
3271 ieee80211_channel_to_frequency(channel_req,
3272 band);
3273 channel[i].band = band;
3274 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3275 request->channels[i] = &channel[i];
3276 request->n_channels++;
3277 }
3278
3279 /* assign parsed ssid array */
3280 if (request->n_ssids)
3281 request->ssids = &ssid[0];
3282
c1179033 3283 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 3284 /* Abort any on-going scan */
27a68fe3 3285 brcmf_abort_scanning(cfg);
e5806072
AS
3286 }
3287
c1179033 3288 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 3289 err = brcmf_do_escan(cfg, wiphy, ndev, request);
e5806072 3290 if (err) {
c1179033 3291 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
3292 goto out_err;
3293 }
27a68fe3
AS
3294 cfg->sched_escan = true;
3295 cfg->scan_request = request;
e5806072
AS
3296 } else {
3297 WL_ERR("FALSE PNO Event. (pfn_count == 0)\n");
3298 goto out_err;
3299 }
3300
3301 kfree(ssid);
3302 kfree(channel);
3303 kfree(request);
3304 return 0;
3305
3306out_err:
3307 kfree(ssid);
3308 kfree(channel);
3309 kfree(request);
3310 cfg80211_sched_scan_stopped(wiphy);
3311 return err;
3312}
3313
3314#ifndef CONFIG_BRCMISCAN
3315static int brcmf_dev_pno_clean(struct net_device *ndev)
3316{
e5806072
AS
3317 int ret;
3318
3319 /* Disable pfn */
ac24be6f 3320 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3321 if (ret == 0) {
3322 /* clear pfn */
ac24be6f
AS
3323 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3324 NULL, 0);
e5806072
AS
3325 }
3326 if (ret < 0)
3327 WL_ERR("failed code %d\n", ret);
3328
3329 return ret;
3330}
3331
3332static int brcmf_dev_pno_config(struct net_device *ndev)
3333{
3334 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3335
3336 memset(&pfn_param, 0, sizeof(pfn_param));
3337 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3338
3339 /* set extra pno params */
3340 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3341 pfn_param.repeat = BRCMF_PNO_REPEAT;
3342 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3343
3344 /* set up pno scan fr */
3345 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3346
ac24be6f
AS
3347 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3348 &pfn_param, sizeof(pfn_param));
e5806072
AS
3349}
3350
3351static int
3352brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3353 struct net_device *ndev,
3354 struct cfg80211_sched_scan_request *request)
3355{
c1179033 3356 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3357 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3358 struct brcmf_pno_net_param_le pfn;
3359 int i;
3360 int ret = 0;
3361
3362 WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n",
3363 request->n_match_sets, request->n_ssids);
c1179033
AS
3364 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3365 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3366 return -EAGAIN;
3367 }
3368
3369 if (!request || !request->n_ssids || !request->n_match_sets) {
3370 WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
9495b31a 3371 request ? request->n_ssids : 0);
e5806072
AS
3372 return -EINVAL;
3373 }
3374
3375 if (request->n_ssids > 0) {
3376 for (i = 0; i < request->n_ssids; i++) {
3377 /* Active scan req for ssids */
3378 WL_SCAN(">>> Active scan req for ssid (%s)\n",
3379 request->ssids[i].ssid);
3380
3381 /*
3382 * match_set ssids is a supert set of n_ssid list,
3383 * so we need not add these set seperately.
3384 */
3385 }
3386 }
3387
3388 if (request->n_match_sets > 0) {
3389 /* clean up everything */
3390 ret = brcmf_dev_pno_clean(ndev);
3391 if (ret < 0) {
3392 WL_ERR("failed error=%d\n", ret);
3393 return ret;
3394 }
3395
3396 /* configure pno */
3397 ret = brcmf_dev_pno_config(ndev);
3398 if (ret < 0) {
3399 WL_ERR("PNO setup failed!! ret=%d\n", ret);
3400 return -EINVAL;
3401 }
3402
3403 /* configure each match set */
3404 for (i = 0; i < request->n_match_sets; i++) {
3405 struct cfg80211_ssid *ssid;
3406 u32 ssid_len;
3407
3408 ssid = &request->match_sets[i].ssid;
3409 ssid_len = ssid->ssid_len;
3410
3411 if (!ssid_len) {
3412 WL_ERR("skip broadcast ssid\n");
3413 continue;
3414 }
3415 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3416 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3417 pfn.wsec = cpu_to_le32(0);
3418 pfn.infra = cpu_to_le32(1);
3419 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3420 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3421 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3422 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3423 sizeof(pfn));
e5806072
AS
3424 WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
3425 ret == 0 ? "set" : "failed",
3426 ssid->ssid);
3427 }
3428 /* Enable the PNO */
c1179033 3429 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
e5806072
AS
3430 WL_ERR("PNO enable failed!! ret=%d\n", ret);
3431 return -EINVAL;
3432 }
3433 } else {
3434 return -EINVAL;
3435 }
3436
3437 return 0;
3438}
3439
3440static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3441 struct net_device *ndev)
3442{
27a68fe3 3443 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072
AS
3444
3445 WL_SCAN("enter\n");
3446 brcmf_dev_pno_clean(ndev);
27a68fe3
AS
3447 if (cfg->sched_escan)
3448 brcmf_notify_escan_complete(cfg, ndev, true, true);
e5806072
AS
3449 return 0;
3450}
3451#endif /* CONFIG_BRCMISCAN */
3452
cbaa177d
AS
3453#ifdef CONFIG_NL80211_TESTMODE
3454static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3455{
27a68fe3 3456 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3457 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3458 struct brcmf_dcmd *dcmd = data;
3459 struct sk_buff *reply;
3460 int ret;
3461
f368a5b6
HM
3462 WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3463 dcmd->buf, dcmd->len);
3464
3465 if (dcmd->set)
ac24be6f
AS
3466 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3467 dcmd->buf, dcmd->len);
f368a5b6 3468 else
ac24be6f
AS
3469 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3470 dcmd->buf, dcmd->len);
cbaa177d
AS
3471 if (ret == 0) {
3472 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3473 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3474 ret = cfg80211_testmode_reply(reply);
3475 }
3476 return ret;
3477}
3478#endif
3479
1a873342
HM
3480static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
3481{
ac24be6f 3482 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3483 s32 err;
3484
3485 /* set auth */
ac24be6f 3486 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342
HM
3487 if (err < 0) {
3488 WL_ERR("auth error %d\n", err);
3489 return err;
3490 }
3491 /* set wsec */
ac24be6f 3492 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342
HM
3493 if (err < 0) {
3494 WL_ERR("wsec error %d\n", err);
3495 return err;
3496 }
3497 /* set upper-layer auth */
ac24be6f 3498 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342
HM
3499 if (err < 0) {
3500 WL_ERR("wpa_auth error %d\n", err);
3501 return err;
3502 }
3503
3504 return 0;
3505}
3506
3507static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3508{
3509 if (is_rsn_ie)
3510 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3511
3512 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3513}
3514
3515static s32
3516brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
3517 bool is_rsn_ie, s32 bssidx)
3518{
ac24be6f 3519 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3520 u32 auth = 0; /* d11 open authentication */
3521 u16 count;
3522 s32 err = 0;
3523 s32 len = 0;
3524 u32 i;
3525 u32 wsec;
3526 u32 pval = 0;
3527 u32 gval = 0;
3528 u32 wpa_auth = 0;
3529 u32 offset;
3530 u8 *data;
3531 u16 rsn_cap;
3532 u32 wme_bss_disable;
3533
3534 WL_TRACE("Enter\n");
3535 if (wpa_ie == NULL)
3536 goto exit;
3537
3538 len = wpa_ie->len + TLV_HDR_LEN;
3539 data = (u8 *)wpa_ie;
3540 offset = 0;
3541 if (!is_rsn_ie)
3542 offset += VS_IE_FIXED_HDR_LEN;
3543 offset += WPA_IE_VERSION_LEN;
3544
3545 /* check for multicast cipher suite */
3546 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3547 err = -EINVAL;
3548 WL_ERR("no multicast cipher suite\n");
3549 goto exit;
3550 }
3551
3552 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3553 err = -EINVAL;
3554 WL_ERR("ivalid OUI\n");
3555 goto exit;
3556 }
3557 offset += TLV_OUI_LEN;
3558
3559 /* pick up multicast cipher */
3560 switch (data[offset]) {
3561 case WPA_CIPHER_NONE:
3562 gval = 0;
3563 break;
3564 case WPA_CIPHER_WEP_40:
3565 case WPA_CIPHER_WEP_104:
3566 gval = WEP_ENABLED;
3567 break;
3568 case WPA_CIPHER_TKIP:
3569 gval = TKIP_ENABLED;
3570 break;
3571 case WPA_CIPHER_AES_CCM:
3572 gval = AES_ENABLED;
3573 break;
3574 default:
3575 err = -EINVAL;
3576 WL_ERR("Invalid multi cast cipher info\n");
3577 goto exit;
3578 }
3579
3580 offset++;
3581 /* walk thru unicast cipher list and pick up what we recognize */
3582 count = data[offset] + (data[offset + 1] << 8);
3583 offset += WPA_IE_SUITE_COUNT_LEN;
3584 /* Check for unicast suite(s) */
3585 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3586 err = -EINVAL;
3587 WL_ERR("no unicast cipher suite\n");
3588 goto exit;
3589 }
3590 for (i = 0; i < count; i++) {
3591 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3592 err = -EINVAL;
3593 WL_ERR("ivalid OUI\n");
3594 goto exit;
3595 }
3596 offset += TLV_OUI_LEN;
3597 switch (data[offset]) {
3598 case WPA_CIPHER_NONE:
3599 break;
3600 case WPA_CIPHER_WEP_40:
3601 case WPA_CIPHER_WEP_104:
3602 pval |= WEP_ENABLED;
3603 break;
3604 case WPA_CIPHER_TKIP:
3605 pval |= TKIP_ENABLED;
3606 break;
3607 case WPA_CIPHER_AES_CCM:
3608 pval |= AES_ENABLED;
3609 break;
3610 default:
3611 WL_ERR("Ivalid unicast security info\n");
3612 }
3613 offset++;
3614 }
3615 /* walk thru auth management suite list and pick up what we recognize */
3616 count = data[offset] + (data[offset + 1] << 8);
3617 offset += WPA_IE_SUITE_COUNT_LEN;
3618 /* Check for auth key management suite(s) */
3619 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3620 err = -EINVAL;
3621 WL_ERR("no auth key mgmt suite\n");
3622 goto exit;
3623 }
3624 for (i = 0; i < count; i++) {
3625 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3626 err = -EINVAL;
3627 WL_ERR("ivalid OUI\n");
3628 goto exit;
3629 }
3630 offset += TLV_OUI_LEN;
3631 switch (data[offset]) {
3632 case RSN_AKM_NONE:
3633 WL_TRACE("RSN_AKM_NONE\n");
3634 wpa_auth |= WPA_AUTH_NONE;
3635 break;
3636 case RSN_AKM_UNSPECIFIED:
3637 WL_TRACE("RSN_AKM_UNSPECIFIED\n");
3638 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3639 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3640 break;
3641 case RSN_AKM_PSK:
3642 WL_TRACE("RSN_AKM_PSK\n");
3643 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3644 (wpa_auth |= WPA_AUTH_PSK);
3645 break;
3646 default:
3647 WL_ERR("Ivalid key mgmt info\n");
3648 }
3649 offset++;
3650 }
3651
3652 if (is_rsn_ie) {
3653 wme_bss_disable = 1;
3654 if ((offset + RSN_CAP_LEN) <= len) {
3655 rsn_cap = data[offset] + (data[offset + 1] << 8);
3656 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3657 wme_bss_disable = 0;
3658 }
3659 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3660 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3661 wme_bss_disable);
1a873342
HM
3662 if (err < 0) {
3663 WL_ERR("wme_bss_disable error %d\n", err);
3664 goto exit;
3665 }
3666 }
3667 /* FOR WPS , set SES_OW_ENABLED */
3668 wsec = (pval | gval | SES_OW_ENABLED);
3669
3670 /* set auth */
ac24be6f 3671 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342
HM
3672 if (err < 0) {
3673 WL_ERR("auth error %d\n", err);
3674 goto exit;
3675 }
3676 /* set wsec */
ac24be6f 3677 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342
HM
3678 if (err < 0) {
3679 WL_ERR("wsec error %d\n", err);
3680 goto exit;
3681 }
3682 /* set upper-layer auth */
ac24be6f 3683 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342
HM
3684 if (err < 0) {
3685 WL_ERR("wpa_auth error %d\n", err);
3686 goto exit;
3687 }
3688
3689exit:
3690 return err;
3691}
3692
3693static s32
3694brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len,
3695 struct parsed_vndr_ies *vndr_ies)
3696{
3697 s32 err = 0;
3698 struct brcmf_vs_tlv *vndrie;
3699 struct brcmf_tlv *ie;
3700 struct parsed_vndr_ie_info *parsed_info;
3701 s32 remaining_len;
3702
3703 remaining_len = (s32)vndr_ie_len;
3704 memset(vndr_ies, 0, sizeof(*vndr_ies));
3705
3706 ie = (struct brcmf_tlv *)vndr_ie_buf;
3707 while (ie) {
3708 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3709 goto next;
3710 vndrie = (struct brcmf_vs_tlv *)ie;
3711 /* len should be bigger than OUI length + one */
3712 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
3713 WL_ERR("invalid vndr ie. length is too small %d\n",
3714 vndrie->len);
3715 goto next;
3716 }
3717 /* if wpa or wme ie, do not add ie */
3718 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3719 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3720 (vndrie->oui_type == WME_OUI_TYPE))) {
3721 WL_TRACE("Found WPA/WME oui. Do not add it\n");
3722 goto next;
3723 }
3724
3725 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3726
3727 /* save vndr ie information */
3728 parsed_info->ie_ptr = (char *)vndrie;
3729 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3730 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3731
3732 vndr_ies->count++;
3733
3734 WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n",
3735 parsed_info->vndrie.oui[0],
3736 parsed_info->vndrie.oui[1],
3737 parsed_info->vndrie.oui[2],
3738 parsed_info->vndrie.oui_type);
3739
3740 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3741 break;
3742next:
3743 remaining_len -= ie->len;
3744 if (remaining_len <= 2)
3745 ie = NULL;
3746 else
3747 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len);
3748 }
3749 return err;
3750}
3751
3752static u32
3753brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3754{
3755
3756 __le32 iecount_le;
3757 __le32 pktflag_le;
3758
3759 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3760 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3761
3762 iecount_le = cpu_to_le32(1);
3763 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3764
3765 pktflag_le = cpu_to_le32(pktflag);
3766 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3767
3768 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3769
3770 return ie_len + VNDR_IE_HDR_SIZE;
3771}
3772
3cb91f53 3773static s32
27a68fe3 3774brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
1d4fd8d7 3775 struct net_device *ndev, s32 pktflag,
1a873342
HM
3776 u8 *vndr_ie_buf, u32 vndr_ie_len)
3777{
c1179033 3778 struct brcmf_if *ifp = netdev_priv(ndev);
8ff5dc92 3779 struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
1a873342
HM
3780 s32 err = 0;
3781 u8 *iovar_ie_buf;
3782 u8 *curr_ie_buf;
3783 u8 *mgmt_ie_buf = NULL;
3e4f319d 3784 int mgmt_ie_buf_len;
81118d16 3785 u32 *mgmt_ie_len;
1a873342
HM
3786 u32 del_add_ie_buf_len = 0;
3787 u32 total_ie_buf_len = 0;
3788 u32 parsed_ie_buf_len = 0;
3789 struct parsed_vndr_ies old_vndr_ies;
3790 struct parsed_vndr_ies new_vndr_ies;
3791 struct parsed_vndr_ie_info *vndrie_info;
3792 s32 i;
3793 u8 *ptr;
3e4f319d 3794 int remained_buf_len;
1a873342 3795
6ac4f4ed
AS
3796 WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
3797 brcmf_ndev_bssidx(ndev), pktflag);
1a873342
HM
3798 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3799 if (!iovar_ie_buf)
3800 return -ENOMEM;
3801 curr_ie_buf = iovar_ie_buf;
8ff5dc92 3802 if (ifp->vif->mode == WL_MODE_AP) {
1a873342
HM
3803 switch (pktflag) {
3804 case VNDR_IE_PRBRSP_FLAG:
8ff5dc92
AS
3805 mgmt_ie_buf = saved_ie->probe_res_ie;
3806 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3807 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
1a873342
HM
3808 break;
3809 case VNDR_IE_BEACON_FLAG:
8ff5dc92
AS
3810 mgmt_ie_buf = saved_ie->beacon_ie;
3811 mgmt_ie_len = &saved_ie->beacon_ie_len;
3812 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
1a873342
HM
3813 break;
3814 default:
3815 err = -EPERM;
3816 WL_ERR("not suitable type\n");
3817 goto exit;
3818 }
1a873342
HM
3819 } else {
3820 err = -EPERM;
3821 WL_ERR("not suitable type\n");
3822 goto exit;
3823 }
3824
3825 if (vndr_ie_len > mgmt_ie_buf_len) {
3826 err = -ENOMEM;
3827 WL_ERR("extra IE size too big\n");
3828 goto exit;
3829 }
3830
3831 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3832 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3833 ptr = curr_ie_buf;
3834 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3835 for (i = 0; i < new_vndr_ies.count; i++) {
3836 vndrie_info = &new_vndr_ies.ie_info[i];
3837 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3838 vndrie_info->ie_len);
3839 parsed_ie_buf_len += vndrie_info->ie_len;
3840 }
3841 }
3842
3843 if (mgmt_ie_buf != NULL) {
3844 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3845 (memcmp(mgmt_ie_buf, curr_ie_buf,
3846 parsed_ie_buf_len) == 0)) {
3847 WL_TRACE("Previous mgmt IE is equals to current IE");
3848 goto exit;
3849 }
3850
3851 /* parse old vndr_ie */
3852 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3853
3854 /* make a command to delete old ie */
3855 for (i = 0; i < old_vndr_ies.count; i++) {
3856 vndrie_info = &old_vndr_ies.ie_info[i];
3857
3858 WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3859 vndrie_info->vndrie.id,
3860 vndrie_info->vndrie.len,
3861 vndrie_info->vndrie.oui[0],
3862 vndrie_info->vndrie.oui[1],
3863 vndrie_info->vndrie.oui[2]);
3864
3865 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3866 vndrie_info->ie_ptr,
3867 vndrie_info->ie_len,
3868 "del");
3869 curr_ie_buf += del_add_ie_buf_len;
3870 total_ie_buf_len += del_add_ie_buf_len;
3871 }
3872 }
3873
3874 *mgmt_ie_len = 0;
3875 /* Add if there is any extra IE */
3876 if (mgmt_ie_buf && parsed_ie_buf_len) {
3877 ptr = mgmt_ie_buf;
3878
3879 remained_buf_len = mgmt_ie_buf_len;
3880
3881 /* make a command to add new ie */
3882 for (i = 0; i < new_vndr_ies.count; i++) {
3883 vndrie_info = &new_vndr_ies.ie_info[i];
3884
3885 WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3886 vndrie_info->vndrie.id,
3887 vndrie_info->vndrie.len,
3888 vndrie_info->vndrie.oui[0],
3889 vndrie_info->vndrie.oui[1],
3890 vndrie_info->vndrie.oui[2]);
3891
3892 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3893 vndrie_info->ie_ptr,
3894 vndrie_info->ie_len,
3895 "add");
3896 /* verify remained buf size before copy data */
3897 remained_buf_len -= vndrie_info->ie_len;
3898 if (remained_buf_len < 0) {
3899 WL_ERR("no space in mgmt_ie_buf: len left %d",
3900 remained_buf_len);
3901 break;
3902 }
3903
3904 /* save the parsed IE in wl struct */
3905 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3906 vndrie_info->ie_len);
3907 *mgmt_ie_len += vndrie_info->ie_len;
3908
3909 curr_ie_buf += del_add_ie_buf_len;
3910 total_ie_buf_len += del_add_ie_buf_len;
3911 }
3912 }
3913 if (total_ie_buf_len) {
c1179033 3914 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3915 total_ie_buf_len);
1a873342
HM
3916 if (err)
3917 WL_ERR("vndr ie set error : %d\n", err);
3918 }
3919
3920exit:
3921 kfree(iovar_ie_buf);
3922 return err;
3923}
3924
3925static s32
3926brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3927 struct cfg80211_ap_settings *settings)
3928{
3929 s32 ie_offset;
ac24be6f 3930 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3931 struct brcmf_tlv *ssid_ie;
3932 struct brcmf_ssid_le ssid_le;
1a873342
HM
3933 s32 err = -EPERM;
3934 struct brcmf_tlv *rsn_ie;
3935 struct brcmf_vs_tlv *wpa_ie;
3936 struct brcmf_join_params join_params;
27a68fe3 3937 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342
HM
3938 s32 bssidx = 0;
3939
3940 WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3941 settings->channel_type, settings->beacon_interval,
3942 settings->dtim_period);
3943 WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n",
3944 settings->ssid, settings->ssid_len, settings->auth_type,
3945 settings->inactivity_timeout);
3946
c1179033 3947 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
1a873342
HM
3948 WL_ERR("Not in AP creation mode\n");
3949 return -EPERM;
3950 }
3951
3952 memset(&ssid_le, 0, sizeof(ssid_le));
3953 if (settings->ssid == NULL || settings->ssid_len == 0) {
3954 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3955 ssid_ie = brcmf_parse_tlvs(
3956 (u8 *)&settings->beacon.head[ie_offset],
3957 settings->beacon.head_len - ie_offset,
3958 WLAN_EID_SSID);
3959 if (!ssid_ie)
3960 return -EINVAL;
3961
3962 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3963 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
3964 WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID);
3965 } else {
3966 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3967 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3968 }
3969
3970 brcmf_set_mpc(ndev, 0);
ac24be6f 3971 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
1a873342
HM
3972 if (err < 0) {
3973 WL_ERR("BRCMF_C_DOWN error %d\n", err);
3974 goto exit;
3975 }
ac24be6f 3976 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342
HM
3977 if (err < 0) {
3978 WL_ERR("SET INFRA error %d\n", err);
3979 goto exit;
3980 }
ac24be6f 3981 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
1a873342
HM
3982 if (err < 0) {
3983 WL_ERR("setting AP mode failed %d\n", err);
3984 goto exit;
3985 }
3986
3987 /* find the RSN_IE */
3988 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3989 settings->beacon.tail_len, WLAN_EID_RSN);
3990
3991 /* find the WPA_IE */
3992 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3993 settings->beacon.tail_len);
3994
27a68fe3
AS
3995 kfree(cfg->ap_info->rsn_ie);
3996 cfg->ap_info->rsn_ie = NULL;
3997 kfree(cfg->ap_info->wpa_ie);
3998 cfg->ap_info->wpa_ie = NULL;
1a873342
HM
3999
4000 if ((wpa_ie != NULL || rsn_ie != NULL)) {
4001 WL_TRACE("WPA(2) IE is found\n");
4002 if (wpa_ie != NULL) {
4003 /* WPA IE */
4004 err = brcmf_configure_wpaie(ndev, wpa_ie, false,
4005 bssidx);
4006 if (err < 0)
4007 goto exit;
27a68fe3 4008 cfg->ap_info->wpa_ie = kmemdup(wpa_ie,
1a873342
HM
4009 wpa_ie->len +
4010 TLV_HDR_LEN,
4011 GFP_KERNEL);
4012 } else {
4013 /* RSN IE */
4014 err = brcmf_configure_wpaie(ndev,
4015 (struct brcmf_vs_tlv *)rsn_ie, true, bssidx);
4016 if (err < 0)
4017 goto exit;
27a68fe3 4018 cfg->ap_info->rsn_ie = kmemdup(rsn_ie,
1a873342
HM
4019 rsn_ie->len +
4020 TLV_HDR_LEN,
4021 GFP_KERNEL);
4022 }
27a68fe3 4023 cfg->ap_info->security_mode = true;
1a873342
HM
4024 } else {
4025 WL_TRACE("No WPA(2) IEs found\n");
4026 brcmf_configure_opensecurity(ndev, bssidx);
27a68fe3 4027 cfg->ap_info->security_mode = false;
1a873342
HM
4028 }
4029 /* Set Beacon IEs to FW */
1d4fd8d7 4030 err = brcmf_set_management_ie(cfg, ndev,
1a873342
HM
4031 VNDR_IE_BEACON_FLAG,
4032 (u8 *)settings->beacon.tail,
4033 settings->beacon.tail_len);
4034 if (err)
4035 WL_ERR("Set Beacon IE Failed\n");
4036 else
4037 WL_TRACE("Applied Vndr IEs for Beacon\n");
4038
4039 /* Set Probe Response IEs to FW */
1d4fd8d7 4040 err = brcmf_set_management_ie(cfg, ndev,
1a873342
HM
4041 VNDR_IE_PRBRSP_FLAG,
4042 (u8 *)settings->beacon.proberesp_ies,
4043 settings->beacon.proberesp_ies_len);
4044 if (err)
4045 WL_ERR("Set Probe Resp IE Failed\n");
4046 else
4047 WL_TRACE("Applied Vndr IEs for Probe Resp\n");
4048
4049 if (settings->beacon_interval) {
ac24be6f 4050 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 4051 settings->beacon_interval);
1a873342
HM
4052 if (err < 0) {
4053 WL_ERR("Beacon Interval Set Error, %d\n", err);
4054 goto exit;
4055 }
4056 }
4057 if (settings->dtim_period) {
ac24be6f 4058 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 4059 settings->dtim_period);
1a873342
HM
4060 if (err < 0) {
4061 WL_ERR("DTIM Interval Set Error, %d\n", err);
4062 goto exit;
4063 }
4064 }
ac24be6f 4065 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
1a873342
HM
4066 if (err < 0) {
4067 WL_ERR("BRCMF_C_UP error (%d)\n", err);
4068 goto exit;
4069 }
4070
4071 memset(&join_params, 0, sizeof(join_params));
4072 /* join parameters starts with ssid */
4073 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4074 /* create softap */
ac24be6f
AS
4075 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4076 &join_params, sizeof(join_params));
1a873342
HM
4077 if (err < 0) {
4078 WL_ERR("SET SSID error (%d)\n", err);
4079 goto exit;
4080 }
c1179033
AS
4081 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4082 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
4083
4084exit:
4085 if (err)
4086 brcmf_set_mpc(ndev, 1);
4087 return err;
4088}
4089
4090static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4091{
c1179033 4092 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 4093 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342
HM
4094 s32 err = -EPERM;
4095
4096 WL_TRACE("Enter\n");
4097
27a68fe3 4098 if (cfg->conf->mode == WL_MODE_AP) {
1a873342
HM
4099 /* Due to most likely deauths outstanding we sleep */
4100 /* first to make sure they get processed by fw. */
4101 msleep(400);
ac24be6f
AS
4102 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
4103 BRCMF_C_SET_AP, 0);
1a873342
HM
4104 if (err < 0) {
4105 WL_ERR("setting AP mode failed %d\n", err);
4106 goto exit;
4107 }
ac24be6f 4108 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
1a873342
HM
4109 if (err < 0) {
4110 WL_ERR("BRCMF_C_UP error %d\n", err);
4111 goto exit;
4112 }
4113 brcmf_set_mpc(ndev, 1);
c1179033
AS
4114 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4115 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
4116 }
4117exit:
4118 return err;
4119}
4120
4121static int
4122brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
4123 u8 *mac)
4124{
4125 struct brcmf_scb_val_le scbval;
0abb5f21 4126 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
4127 s32 err;
4128
4129 if (!mac)
4130 return -EFAULT;
4131
4132 WL_TRACE("Enter %pM\n", mac);
4133
ce81e317 4134 if (!check_vif_up(ifp->vif))
1a873342
HM
4135 return -EIO;
4136
4137 memcpy(&scbval.ea, mac, ETH_ALEN);
4138 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 4139 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 4140 &scbval, sizeof(scbval));
1a873342
HM
4141 if (err)
4142 WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
4143
4144 WL_TRACE("Exit\n");
4145 return err;
4146}
4147
5b435de0
AS
4148static struct cfg80211_ops wl_cfg80211_ops = {
4149 .change_virtual_intf = brcmf_cfg80211_change_iface,
4150 .scan = brcmf_cfg80211_scan,
4151 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4152 .join_ibss = brcmf_cfg80211_join_ibss,
4153 .leave_ibss = brcmf_cfg80211_leave_ibss,
4154 .get_station = brcmf_cfg80211_get_station,
4155 .set_tx_power = brcmf_cfg80211_set_tx_power,
4156 .get_tx_power = brcmf_cfg80211_get_tx_power,
4157 .add_key = brcmf_cfg80211_add_key,
4158 .del_key = brcmf_cfg80211_del_key,
4159 .get_key = brcmf_cfg80211_get_key,
4160 .set_default_key = brcmf_cfg80211_config_default_key,
4161 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4162 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
4163 .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
4164 .connect = brcmf_cfg80211_connect,
4165 .disconnect = brcmf_cfg80211_disconnect,
4166 .suspend = brcmf_cfg80211_suspend,
4167 .resume = brcmf_cfg80211_resume,
4168 .set_pmksa = brcmf_cfg80211_set_pmksa,
4169 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4170 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4171 .start_ap = brcmf_cfg80211_start_ap,
4172 .stop_ap = brcmf_cfg80211_stop_ap,
4173 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
4174#ifndef CONFIG_BRCMISCAN
4175 /* scheduled scan need e-scan, which is mutual exclusive with i-scan */
4176 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4177 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
4178#endif
cbaa177d
AS
4179#ifdef CONFIG_NL80211_TESTMODE
4180 .testmode_cmd = brcmf_cfg80211_testmode
4181#endif
5b435de0
AS
4182};
4183
4184static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
4185{
4186 s32 err = 0;
4187
4188 switch (mode) {
4189 case WL_MODE_BSS:
4190 return NL80211_IFTYPE_STATION;
4191 case WL_MODE_IBSS:
4192 return NL80211_IFTYPE_ADHOC;
4193 default:
4194 return NL80211_IFTYPE_UNSPECIFIED;
4195 }
4196
4197 return err;
4198}
4199
e5806072
AS
4200static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4201{
4202#ifndef CONFIG_BRCMFISCAN
4203 /* scheduled scan settings */
4204 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4205 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4206 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4207 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
4208#endif
4209}
4210
3eacf866 4211static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 4212{
3eacf866 4213 struct wiphy *wiphy;
5b435de0
AS
4214 s32 err = 0;
4215
3eacf866
AS
4216 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4217 if (!wiphy) {
bfeb4dbc 4218 WL_ERR("Could not allocate wiphy device\n");
3eacf866
AS
4219 return ERR_PTR(-ENOMEM);
4220 }
4221 set_wiphy_dev(wiphy, phydev);
4222 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
4223 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4224 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4225 BIT(NL80211_IFTYPE_ADHOC) |
4226 BIT(NL80211_IFTYPE_AP);
4227 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4228 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
5b435de0
AS
4229 * it as 11a by default.
4230 * This will be updated with
4231 * 11n phy tables in
4232 * "ifconfig up"
4233 * if phy has 11n capability
4234 */
3eacf866
AS
4235 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4236 wiphy->cipher_suites = __wl_cipher_suites;
4237 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
4238 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
5b435de0
AS
4239 * save mode
4240 * by default
4241 */
3eacf866
AS
4242 brcmf_wiphy_pno_params(wiphy);
4243 err = wiphy_register(wiphy);
5b435de0 4244 if (err < 0) {
bfeb4dbc 4245 WL_ERR("Could not register wiphy device (%d)\n", err);
3eacf866
AS
4246 wiphy_free(wiphy);
4247 return ERR_PTR(err);
5b435de0 4248 }
3eacf866
AS
4249 return wiphy;
4250}
4251
4252static
4253struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
4254 struct net_device *netdev,
4255 s32 mode, bool pm_block)
4256{
4257 struct brcmf_cfg80211_vif *vif;
5b435de0 4258
3eacf866
AS
4259 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4260 return ERR_PTR(-ENOSPC);
5b435de0 4261
3eacf866
AS
4262 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4263 if (!vif)
4264 return ERR_PTR(-ENOMEM);
4265
4266 vif->wdev.wiphy = cfg->wiphy;
4267 vif->wdev.netdev = netdev;
4268 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
5b435de0 4269
3eacf866
AS
4270 if (netdev) {
4271 vif->ifp = netdev_priv(netdev);
4272 netdev->ieee80211_ptr = &vif->wdev;
4273 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
4274 }
4275
4276 vif->mode = mode;
4277 vif->pm_block = pm_block;
4278 vif->roam_off = -1;
4279
6ac4f4ed
AS
4280 brcmf_init_prof(&vif->profile);
4281
3eacf866
AS
4282 list_add_tail(&vif->list, &cfg->vif_list);
4283 cfg->vif_cnt++;
4284 return vif;
5b435de0
AS
4285}
4286
3eacf866 4287static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4288{
3eacf866
AS
4289 struct brcmf_cfg80211_info *cfg;
4290 struct wiphy *wiphy;
5b435de0 4291
3eacf866
AS
4292 wiphy = vif->wdev.wiphy;
4293 cfg = wiphy_priv(wiphy);
4294 list_del(&vif->list);
4295 cfg->vif_cnt--;
4296
4297 kfree(vif);
4298 if (!cfg->vif_cnt) {
4299 wiphy_unregister(wiphy);
4300 wiphy_free(wiphy);
5b435de0 4301 }
5b435de0
AS
4302}
4303
27a68fe3 4304static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4305 const struct brcmf_event_msg *e)
4306{
4307 u32 event = be32_to_cpu(e->event_type);
4308 u32 status = be32_to_cpu(e->status);
4309
4310 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
4311 WL_CONN("Processing set ssid\n");
27a68fe3 4312 cfg->link_up = true;
5b435de0
AS
4313 return true;
4314 }
4315
4316 return false;
4317}
4318
27a68fe3 4319static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4320 const struct brcmf_event_msg *e)
4321{
4322 u32 event = be32_to_cpu(e->event_type);
4323 u16 flags = be16_to_cpu(e->flags);
4324
4325 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
4326 WL_CONN("Processing link down\n");
4327 return true;
4328 }
4329 return false;
4330}
4331
27a68fe3 4332static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4333 const struct brcmf_event_msg *e)
4334{
4335 u32 event = be32_to_cpu(e->event_type);
4336 u32 status = be32_to_cpu(e->status);
4337
4338 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
4339 WL_CONN("Processing Link %s & no network found\n",
4340 be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
4341 "up" : "down");
4342 return true;
4343 }
4344
4345 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
4346 WL_CONN("Processing connecting & no network found\n");
4347 return true;
4348 }
4349
4350 return false;
4351}
4352
27a68fe3 4353static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4354{
27a68fe3 4355 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4356
4357 kfree(conn_info->req_ie);
4358 conn_info->req_ie = NULL;
4359 conn_info->req_ie_len = 0;
4360 kfree(conn_info->resp_ie);
4361 conn_info->resp_ie = NULL;
4362 conn_info->resp_ie_len = 0;
4363}
4364
27a68fe3 4365static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4366{
ac24be6f 4367 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
c4e382d2 4368 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4369 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4370 u32 req_len;
4371 u32 resp_len;
4372 s32 err = 0;
4373
27a68fe3 4374 brcmf_clear_assoc_ies(cfg);
5b435de0 4375
ac24be6f
AS
4376 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4377 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0
AS
4378 if (err) {
4379 WL_ERR("could not get assoc info (%d)\n", err);
4380 return err;
4381 }
c4e382d2 4382 assoc_info =
27a68fe3 4383 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4384 req_len = le32_to_cpu(assoc_info->req_len);
4385 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4386 if (req_len) {
ac24be6f 4387 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4388 cfg->extra_buf,
4389 WL_ASSOC_INFO_MAX);
5b435de0
AS
4390 if (err) {
4391 WL_ERR("could not get assoc req (%d)\n", err);
4392 return err;
4393 }
4394 conn_info->req_ie_len = req_len;
4395 conn_info->req_ie =
27a68fe3 4396 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4397 GFP_KERNEL);
4398 } else {
4399 conn_info->req_ie_len = 0;
4400 conn_info->req_ie = NULL;
4401 }
4402 if (resp_len) {
ac24be6f 4403 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4404 cfg->extra_buf,
4405 WL_ASSOC_INFO_MAX);
5b435de0
AS
4406 if (err) {
4407 WL_ERR("could not get assoc resp (%d)\n", err);
4408 return err;
4409 }
4410 conn_info->resp_ie_len = resp_len;
4411 conn_info->resp_ie =
27a68fe3 4412 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4413 GFP_KERNEL);
4414 } else {
4415 conn_info->resp_ie_len = 0;
4416 conn_info->resp_ie = NULL;
4417 }
4418 WL_CONN("req len (%d) resp len (%d)\n",
4419 conn_info->req_ie_len, conn_info->resp_ie_len);
4420
4421 return err;
4422}
4423
4424static s32
27a68fe3 4425brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4426 struct net_device *ndev,
4427 const struct brcmf_event_msg *e)
4428{
c1179033
AS
4429 struct brcmf_if *ifp = netdev_priv(ndev);
4430 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4431 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4432 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4433 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4434 struct ieee80211_supported_band *band;
a180b83b 4435 struct brcmf_bss_info_le *bi;
5b435de0
AS
4436 u32 freq;
4437 s32 err = 0;
4438 u32 target_channel;
a180b83b 4439 u8 *buf;
5b435de0
AS
4440
4441 WL_TRACE("Enter\n");
4442
27a68fe3 4443 brcmf_get_assoc_ies(cfg);
6c8c4f72 4444 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4445 brcmf_update_bss_info(cfg);
5b435de0 4446
a180b83b
FL
4447 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4448 if (buf == NULL) {
4449 err = -ENOMEM;
4450 goto done;
4451 }
4452
4453 /* data sent to dongle has to be little endian */
4454 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4455 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4456 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4457
4458 if (err)
4459 goto done;
5b435de0 4460
a180b83b
FL
4461 bi = (struct brcmf_bss_info_le *)(buf + 4);
4462 target_channel = bi->ctl_ch ? bi->ctl_ch :
4463 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
5b435de0
AS
4464
4465 if (target_channel <= CH_MAX_2G_CHANNEL)
4466 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4467 else
4468 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4469
4470 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4471 notify_channel = ieee80211_get_channel(wiphy, freq);
4472
a180b83b
FL
4473done:
4474 kfree(buf);
06bb123e 4475 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4476 conn_info->req_ie, conn_info->req_ie_len,
4477 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4478 WL_CONN("Report roaming result\n");
4479
c1179033 4480 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
5b435de0
AS
4481 WL_TRACE("Exit\n");
4482 return err;
4483}
4484
4485static s32
27a68fe3 4486brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4487 struct net_device *ndev, const struct brcmf_event_msg *e,
4488 bool completed)
4489{
c1179033
AS
4490 struct brcmf_if *ifp = netdev_priv(ndev);
4491 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4492 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4493 s32 err = 0;
4494
4495 WL_TRACE("Enter\n");
4496
c1179033
AS
4497 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4498 &ifp->vif->sme_state)) {
5b435de0 4499 if (completed) {
27a68fe3 4500 brcmf_get_assoc_ies(cfg);
6c8c4f72 4501 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4502 brcmf_update_bss_info(cfg);
5b435de0
AS
4503 }
4504 cfg80211_connect_result(ndev,
06bb123e 4505 (u8 *)profile->bssid,
5b435de0
AS
4506 conn_info->req_ie,
4507 conn_info->req_ie_len,
4508 conn_info->resp_ie,
4509 conn_info->resp_ie_len,
4510 completed ? WLAN_STATUS_SUCCESS :
4511 WLAN_STATUS_AUTH_TIMEOUT,
4512 GFP_KERNEL);
4513 if (completed)
c1179033
AS
4514 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4515 &ifp->vif->sme_state);
5b435de0
AS
4516 WL_CONN("Report connect result - connection %s\n",
4517 completed ? "succeeded" : "failed");
4518 }
4519 WL_TRACE("Exit\n");
4520 return err;
4521}
4522
4523static s32
27a68fe3 4524brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4525 struct net_device *ndev,
4526 const struct brcmf_event_msg *e, void *data)
4527{
4528 s32 err = 0;
4529 u32 event = be32_to_cpu(e->event_type);
4530 u32 reason = be32_to_cpu(e->reason);
4531 u32 len = be32_to_cpu(e->datalen);
4532 static int generation;
4533
4534 struct station_info sinfo;
4535
4536 WL_CONN("event %d, reason %d\n", event, reason);
4537 memset(&sinfo, 0, sizeof(sinfo));
4538
4539 sinfo.filled = 0;
4540 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4541 reason == BRCMF_E_STATUS_SUCCESS) {
4542 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4543 if (!data) {
4544 WL_ERR("No IEs present in ASSOC/REASSOC_IND");
4545 return -EINVAL;
4546 }
4547 sinfo.assoc_req_ies = data;
4548 sinfo.assoc_req_ies_len = len;
4549 generation++;
4550 sinfo.generation = generation;
4551 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
4552 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4553 (event == BRCMF_E_DEAUTH_IND) ||
4554 (event == BRCMF_E_DEAUTH)) {
4555 generation++;
4556 sinfo.generation = generation;
4557 cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
4558 }
4559 return err;
4560}
4561
5b435de0 4562static s32
27a68fe3 4563brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4564 struct net_device *ndev,
4565 const struct brcmf_event_msg *e, void *data)
4566{
c1179033
AS
4567 struct brcmf_if *ifp = netdev_priv(ndev);
4568 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4569 s32 err = 0;
4570
27a68fe3
AS
4571 if (cfg->conf->mode == WL_MODE_AP) {
4572 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4573 } else if (brcmf_is_linkup(cfg, e)) {
5b435de0 4574 WL_CONN("Linkup\n");
27a68fe3 4575 if (brcmf_is_ibssmode(cfg)) {
6c8c4f72 4576 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4577 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4578 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4579 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4580 &ifp->vif->sme_state);
4581 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4582 &ifp->vif->sme_state);
5b435de0 4583 } else
27a68fe3
AS
4584 brcmf_bss_connect_done(cfg, ndev, e, true);
4585 } else if (brcmf_is_linkdown(cfg, e)) {
5b435de0 4586 WL_CONN("Linkdown\n");
27a68fe3 4587 if (brcmf_is_ibssmode(cfg)) {
c1179033
AS
4588 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4589 &ifp->vif->sme_state);
4590 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4591 &ifp->vif->sme_state))
27a68fe3 4592 brcmf_link_down(cfg);
5b435de0 4593 } else {
27a68fe3 4594 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033
AS
4595 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4596 &ifp->vif->sme_state)) {
5b435de0 4597 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4598 GFP_KERNEL);
27a68fe3 4599 brcmf_link_down(cfg);
5b435de0
AS
4600 }
4601 }
6ac4f4ed 4602 brcmf_init_prof(ndev_to_prof(ndev));
27a68fe3
AS
4603 } else if (brcmf_is_nonetwork(cfg, e)) {
4604 if (brcmf_is_ibssmode(cfg))
c1179033
AS
4605 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4606 &ifp->vif->sme_state);
5b435de0 4607 else
27a68fe3 4608 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4609 }
4610
4611 return err;
4612}
4613
4614static s32
27a68fe3 4615brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4616 struct net_device *ndev,
4617 const struct brcmf_event_msg *e, void *data)
4618{
c1179033 4619 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
4620 s32 err = 0;
4621 u32 event = be32_to_cpu(e->event_type);
4622 u32 status = be32_to_cpu(e->status);
4623
4624 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4625 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
27a68fe3 4626 brcmf_bss_roaming_done(cfg, ndev, e);
5b435de0 4627 else
27a68fe3 4628 brcmf_bss_connect_done(cfg, ndev, e, true);
5b435de0
AS
4629 }
4630
4631 return err;
4632}
4633
4634static s32
27a68fe3 4635brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4636 struct net_device *ndev,
4637 const struct brcmf_event_msg *e, void *data)
4638{
4639 u16 flags = be16_to_cpu(e->flags);
4640 enum nl80211_key_type key_type;
4641
4642 if (flags & BRCMF_EVENT_MSG_GROUP)
4643 key_type = NL80211_KEYTYPE_GROUP;
4644 else
4645 key_type = NL80211_KEYTYPE_PAIRWISE;
4646
4647 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
4648 NULL, GFP_KERNEL);
4649
4650 return 0;
4651}
4652
4653static s32
27a68fe3 4654brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4655 struct net_device *ndev,
4656 const struct brcmf_event_msg *e, void *data)
4657{
c1179033 4658 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
4659 struct brcmf_channel_info_le channel_inform_le;
4660 struct brcmf_scan_results_le *bss_list_le;
4661 u32 len = WL_SCAN_BUF_MAX;
4662 s32 err = 0;
4663 bool scan_abort = false;
4664 u32 scan_channel;
4665
4666 WL_TRACE("Enter\n");
4667
27a68fe3 4668 if (cfg->iscan_on && cfg->iscan_kickstart) {
5b435de0 4669 WL_TRACE("Exit\n");
27a68fe3 4670 return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
5b435de0
AS
4671 }
4672
c1179033 4673 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
5b435de0
AS
4674 WL_ERR("Scan complete while device not scanning\n");
4675 scan_abort = true;
4676 err = -EINVAL;
4677 goto scan_done_out;
4678 }
4679
c1179033 4680 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
81f5dcb8
HM
4681 &channel_inform_le,
4682 sizeof(channel_inform_le));
5b435de0
AS
4683 if (err) {
4684 WL_ERR("scan busy (%d)\n", err);
4685 scan_abort = true;
4686 goto scan_done_out;
4687 }
4688 scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
4689 if (scan_channel)
4690 WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
27a68fe3
AS
4691 cfg->bss_list = cfg->scan_results;
4692 bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list;
5b435de0 4693
27a68fe3 4694 memset(cfg->scan_results, 0, len);
5b435de0 4695 bss_list_le->buflen = cpu_to_le32(len);
c1179033 4696 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
81f5dcb8 4697 cfg->scan_results, len);
5b435de0
AS
4698 if (err) {
4699 WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
4700 err = -EINVAL;
4701 scan_abort = true;
4702 goto scan_done_out;
4703 }
27a68fe3
AS
4704 cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
4705 cfg->scan_results->version = le32_to_cpu(bss_list_le->version);
4706 cfg->scan_results->count = le32_to_cpu(bss_list_le->count);
5b435de0 4707
27a68fe3 4708 err = brcmf_inform_bss(cfg);
35aafa9d 4709 if (err)
5b435de0 4710 scan_abort = true;
5b435de0
AS
4711
4712scan_done_out:
27a68fe3 4713 if (cfg->scan_request) {
5b435de0 4714 WL_SCAN("calling cfg80211_scan_done\n");
27a68fe3 4715 cfg80211_scan_done(cfg->scan_request, scan_abort);
5b435de0 4716 brcmf_set_mpc(ndev, 1);
27a68fe3 4717 cfg->scan_request = NULL;
5b435de0
AS
4718 }
4719
4720 WL_TRACE("Exit\n");
4721
4722 return err;
4723}
4724
4725static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4726{
4727 conf->mode = (u32)-1;
4728 conf->frag_threshold = (u32)-1;
4729 conf->rts_threshold = (u32)-1;
4730 conf->retry_short = (u32)-1;
4731 conf->retry_long = (u32)-1;
4732 conf->tx_power = -1;
4733}
4734
4735static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
4736{
4737 memset(el, 0, sizeof(*el));
4738 el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
4739 el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
1a873342
HM
4740 el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;
4741 el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status;
4742 el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status;
4743 el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status;
4744 el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status;
5b435de0
AS
4745 el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
4746 el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
4747 el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
e5806072 4748 el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
5b435de0
AS
4749}
4750
27a68fe3
AS
4751static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4752{
4753 kfree(cfg->scan_results);
4754 cfg->scan_results = NULL;
4755 kfree(cfg->bss_info);
4756 cfg->bss_info = NULL;
4757 kfree(cfg->conf);
4758 cfg->conf = NULL;
27a68fe3
AS
4759 kfree(cfg->scan_req_int);
4760 cfg->scan_req_int = NULL;
4761 kfree(cfg->escan_ioctl_buf);
4762 cfg->escan_ioctl_buf = NULL;
4763 kfree(cfg->dcmd_buf);
4764 cfg->dcmd_buf = NULL;
4765 kfree(cfg->extra_buf);
4766 cfg->extra_buf = NULL;
4767 kfree(cfg->iscan);
4768 cfg->iscan = NULL;
4769 kfree(cfg->pmk_list);
4770 cfg->pmk_list = NULL;
4771 if (cfg->ap_info) {
4772 kfree(cfg->ap_info->wpa_ie);
4773 kfree(cfg->ap_info->rsn_ie);
4774 kfree(cfg->ap_info);
4775 cfg->ap_info = NULL;
4776 }
4777}
4778
4779static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4780{
4781 cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
4782 if (!cfg->scan_results)
5b435de0 4783 goto init_priv_mem_out;
27a68fe3
AS
4784 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4785 if (!cfg->conf)
5b435de0 4786 goto init_priv_mem_out;
27a68fe3
AS
4787 cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4788 if (!cfg->bss_info)
5b435de0 4789 goto init_priv_mem_out;
27a68fe3 4790 cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int),
5b435de0 4791 GFP_KERNEL);
27a68fe3 4792 if (!cfg->scan_req_int)
5b435de0 4793 goto init_priv_mem_out;
27a68fe3
AS
4794 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4795 if (!cfg->escan_ioctl_buf)
e756af5b 4796 goto init_priv_mem_out;
27a68fe3
AS
4797 cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
4798 if (!cfg->dcmd_buf)
5b435de0 4799 goto init_priv_mem_out;
27a68fe3
AS
4800 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4801 if (!cfg->extra_buf)
5b435de0 4802 goto init_priv_mem_out;
27a68fe3
AS
4803 cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL);
4804 if (!cfg->iscan)
5b435de0 4805 goto init_priv_mem_out;
27a68fe3
AS
4806 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4807 if (!cfg->pmk_list)
5b435de0
AS
4808 goto init_priv_mem_out;
4809
4810 return 0;
4811
4812init_priv_mem_out:
27a68fe3 4813 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4814
4815 return -ENOMEM;
4816}
4817
4818/*
4819* retrieve first queued event from head
4820*/
4821
4822static struct brcmf_cfg80211_event_q *brcmf_deq_event(
27a68fe3 4823 struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4824{
4825 struct brcmf_cfg80211_event_q *e = NULL;
4826
27a68fe3
AS
4827 spin_lock_irq(&cfg->evt_q_lock);
4828 if (!list_empty(&cfg->evt_q_list)) {
4829 e = list_first_entry(&cfg->evt_q_list,
5b435de0
AS
4830 struct brcmf_cfg80211_event_q, evt_q_list);
4831 list_del(&e->evt_q_list);
4832 }
27a68fe3 4833 spin_unlock_irq(&cfg->evt_q_lock);
5b435de0
AS
4834
4835 return e;
4836}
4837
4838/*
bcbec9e7
AS
4839* push event to tail of the queue
4840*
4841* remark: this function may not sleep as it is called in atomic context.
5b435de0
AS
4842*/
4843
4844static s32
27a68fe3 4845brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event,
c4fdb056 4846 const struct brcmf_event_msg *msg, void *data)
5b435de0
AS
4847{
4848 struct brcmf_cfg80211_event_q *e;
4849 s32 err = 0;
cf44066a 4850 ulong flags;
c4fdb056
HM
4851 u32 data_len;
4852 u32 total_len;
5b435de0 4853
c4fdb056
HM
4854 total_len = sizeof(struct brcmf_cfg80211_event_q);
4855 if (data)
4856 data_len = be32_to_cpu(msg->datalen);
4857 else
4858 data_len = 0;
4859 total_len += data_len;
4860 e = kzalloc(total_len, GFP_ATOMIC);
5b435de0
AS
4861 if (!e)
4862 return -ENOMEM;
4863
4864 e->etype = event;
4865 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
c4fdb056
HM
4866 if (data)
4867 memcpy(&e->edata, data, data_len);
5b435de0 4868
27a68fe3
AS
4869 spin_lock_irqsave(&cfg->evt_q_lock, flags);
4870 list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
4871 spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
5b435de0
AS
4872
4873 return err;
4874}
4875
4876static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
4877{
4878 kfree(e);
4879}
4880
4881static void brcmf_cfg80211_event_handler(struct work_struct *work)
4882{
27a68fe3
AS
4883 struct brcmf_cfg80211_info *cfg =
4884 container_of(work, struct brcmf_cfg80211_info,
5b435de0
AS
4885 event_work);
4886 struct brcmf_cfg80211_event_q *e;
4887
27a68fe3 4888 e = brcmf_deq_event(cfg);
5b435de0
AS
4889 if (unlikely(!e)) {
4890 WL_ERR("event queue empty...\n");
4891 return;
4892 }
4893
4894 do {
4895 WL_INFO("event type (%d)\n", e->etype);
27a68fe3
AS
4896 if (cfg->el.handler[e->etype])
4897 cfg->el.handler[e->etype](cfg,
4898 cfg_to_ndev(cfg),
5b435de0
AS
4899 &e->emsg, e->edata);
4900 else
4901 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
4902 brcmf_put_event(e);
27a68fe3 4903 } while ((e = brcmf_deq_event(cfg)));
5b435de0
AS
4904
4905}
4906
27a68fe3 4907static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
5b435de0 4908{
27a68fe3
AS
4909 spin_lock_init(&cfg->evt_q_lock);
4910 INIT_LIST_HEAD(&cfg->evt_q_list);
5b435de0
AS
4911}
4912
27a68fe3 4913static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4914{
4915 struct brcmf_cfg80211_event_q *e;
4916
27a68fe3
AS
4917 spin_lock_irq(&cfg->evt_q_lock);
4918 while (!list_empty(&cfg->evt_q_list)) {
4919 e = list_first_entry(&cfg->evt_q_list,
5b435de0
AS
4920 struct brcmf_cfg80211_event_q, evt_q_list);
4921 list_del(&e->evt_q_list);
4922 kfree(e);
4923 }
27a68fe3 4924 spin_unlock_irq(&cfg->evt_q_lock);
5b435de0
AS
4925}
4926
27a68fe3 4927static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4928{
4929 s32 err = 0;
4930
27a68fe3
AS
4931 cfg->scan_request = NULL;
4932 cfg->pwr_save = true;
e756af5b 4933#ifdef CONFIG_BRCMISCAN
27a68fe3 4934 cfg->iscan_on = true; /* iscan on & off switch.
5b435de0 4935 we enable iscan per default */
27a68fe3 4936 cfg->escan_on = false; /* escan on & off switch.
e756af5b
HM
4937 we disable escan per default */
4938#else
27a68fe3 4939 cfg->iscan_on = false; /* iscan on & off switch.
e756af5b 4940 we disable iscan per default */
27a68fe3 4941 cfg->escan_on = true; /* escan on & off switch.
e756af5b
HM
4942 we enable escan per default */
4943#endif
27a68fe3 4944 cfg->roam_on = true; /* roam on & off switch.
5b435de0
AS
4945 we enable roam per default */
4946
27a68fe3
AS
4947 cfg->iscan_kickstart = false;
4948 cfg->active_scan = true; /* we do active scan for
5b435de0 4949 specific scan per default */
27a68fe3
AS
4950 cfg->dongle_up = false; /* dongle is not up yet */
4951 brcmf_init_eq(cfg);
4952 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4953 if (err)
4954 return err;
27a68fe3
AS
4955 INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);
4956 brcmf_init_eloop_handler(&cfg->el);
4957 mutex_init(&cfg->usr_sync);
4958 err = brcmf_init_iscan(cfg);
5b435de0
AS
4959 if (err)
4960 return err;
27a68fe3
AS
4961 brcmf_init_escan(cfg);
4962 brcmf_init_conf(cfg->conf);
27a68fe3 4963 brcmf_link_down(cfg);
5b435de0
AS
4964
4965 return err;
4966}
4967
27a68fe3 4968static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4969{
27a68fe3
AS
4970 cancel_work_sync(&cfg->event_work);
4971 cfg->dongle_up = false; /* dongle down */
4972 brcmf_flush_eq(cfg);
4973 brcmf_link_down(cfg);
4974 brcmf_abort_scanning(cfg);
4975 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4976}
4977
1ed9baf0 4978struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
5b435de0 4979{
1ed9baf0
AS
4980 struct net_device *ndev = drvr->iflist[0]->ndev;
4981 struct device *busdev = drvr->dev;
27a68fe3 4982 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4983 struct wiphy *wiphy;
4984 struct brcmf_cfg80211_vif *vif;
4985 struct brcmf_if *ifp;
5b435de0
AS
4986 s32 err = 0;
4987
4988 if (!ndev) {
4989 WL_ERR("ndev is invalid\n");
4990 return NULL;
4991 }
5b435de0 4992
3eacf866
AS
4993 ifp = netdev_priv(ndev);
4994 wiphy = brcmf_setup_wiphy(busdev);
4995 if (IS_ERR(wiphy))
5b435de0 4996 return NULL;
5b435de0 4997
3eacf866
AS
4998 cfg = wiphy_priv(wiphy);
4999 cfg->wiphy = wiphy;
27a68fe3 5000 cfg->pub = drvr;
3eacf866
AS
5001 INIT_LIST_HEAD(&cfg->vif_list);
5002
5003 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
5004 if (IS_ERR(vif)) {
5005 wiphy_free(wiphy);
5006 return NULL;
5007 }
5008
27a68fe3 5009 err = wl_init_priv(cfg);
5b435de0
AS
5010 if (err) {
5011 WL_ERR("Failed to init iwm_priv (%d)\n", err);
5012 goto cfg80211_attach_out;
5013 }
5b435de0 5014
3eacf866 5015 ifp->vif = vif;
27a68fe3 5016 return cfg;
5b435de0
AS
5017
5018cfg80211_attach_out:
3eacf866 5019 brcmf_free_vif(vif);
5b435de0
AS
5020 return NULL;
5021}
5022
27a68fe3 5023void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 5024{
3eacf866
AS
5025 struct brcmf_cfg80211_vif *vif;
5026 struct brcmf_cfg80211_vif *tmp;
5027
27a68fe3 5028 wl_deinit_priv(cfg);
3eacf866
AS
5029 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
5030 brcmf_free_vif(vif);
5031 }
5b435de0
AS
5032}
5033
5034void
5035brcmf_cfg80211_event(struct net_device *ndev,
5036 const struct brcmf_event_msg *e, void *data)
5037{
5038 u32 event_type = be32_to_cpu(e->event_type);
27a68fe3 5039 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
5b435de0 5040
27a68fe3
AS
5041 if (!brcmf_enq_event(cfg, event_type, e, data))
5042 schedule_work(&cfg->event_work);
5b435de0
AS
5043}
5044
5b435de0
AS
5045static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
5046{
5b435de0
AS
5047 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
5048 s32 err = 0;
5049
5050 WL_TRACE("Enter\n");
5051
5052 /* Setup event_msgs */
ac24be6f
AS
5053 err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
5054 eventmask, BRCMF_EVENTING_MASK_LEN);
5b435de0
AS
5055 if (err) {
5056 WL_ERR("Get event_msgs error (%d)\n", err);
5057 goto dongle_eventmsg_out;
5058 }
5b435de0
AS
5059
5060 setbit(eventmask, BRCMF_E_SET_SSID);
5061 setbit(eventmask, BRCMF_E_ROAM);
5062 setbit(eventmask, BRCMF_E_PRUNE);
5063 setbit(eventmask, BRCMF_E_AUTH);
5064 setbit(eventmask, BRCMF_E_REASSOC);
5065 setbit(eventmask, BRCMF_E_REASSOC_IND);
5066 setbit(eventmask, BRCMF_E_DEAUTH_IND);
5067 setbit(eventmask, BRCMF_E_DISASSOC_IND);
5068 setbit(eventmask, BRCMF_E_DISASSOC);
5069 setbit(eventmask, BRCMF_E_JOIN);
5070 setbit(eventmask, BRCMF_E_ASSOC_IND);
5071 setbit(eventmask, BRCMF_E_PSK_SUP);
5072 setbit(eventmask, BRCMF_E_LINK);
5073 setbit(eventmask, BRCMF_E_NDIS_LINK);
5074 setbit(eventmask, BRCMF_E_MIC_ERROR);
5075 setbit(eventmask, BRCMF_E_PMKID_CACHE);
5076 setbit(eventmask, BRCMF_E_TXFAIL);
5077 setbit(eventmask, BRCMF_E_JOIN_START);
5078 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
e756af5b 5079 setbit(eventmask, BRCMF_E_ESCAN_RESULT);
e5806072 5080 setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
5b435de0 5081
ac24be6f
AS
5082 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
5083 eventmask, BRCMF_EVENTING_MASK_LEN);
5b435de0
AS
5084 if (err) {
5085 WL_ERR("Set event_msgs error (%d)\n", err);
5086 goto dongle_eventmsg_out;
5087 }
5088
5089dongle_eventmsg_out:
5090 WL_TRACE("Exit\n");
5091 return err;
5092}
5093
5094static s32
5095brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
5096{
ac24be6f 5097 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 5098 s32 err = 0;
f588bc0c
AS
5099 __le32 roamtrigger[2];
5100 __le32 roam_delta[2];
5b435de0
AS
5101
5102 /*
5103 * Setup timeout if Beacons are lost and roam is
5104 * off to report link down
5105 */
5106 if (roamvar) {
ac24be6f 5107 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0
AS
5108 if (err) {
5109 WL_ERR("bcn_timeout error (%d)\n", err);
5110 goto dongle_rom_out;
5111 }
5112 }
5113
5114 /*
5115 * Enable/Disable built-in roaming to allow supplicant
5116 * to take care of roaming
5117 */
5118 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 5119 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0
AS
5120 if (err) {
5121 WL_ERR("roam_off error (%d)\n", err);
5122 goto dongle_rom_out;
5123 }
5124
f588bc0c
AS
5125 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5126 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5127 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 5128 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0
AS
5129 if (err) {
5130 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5131 goto dongle_rom_out;
5132 }
5133
f588bc0c
AS
5134 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5135 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 5136 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 5137 (void *)roam_delta, sizeof(roam_delta));
5b435de0
AS
5138 if (err) {
5139 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
5140 goto dongle_rom_out;
5141 }
5142
5143dongle_rom_out:
5144 return err;
5145}
5146
5147static s32
5148brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
c68cdc0f 5149 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0 5150{
ac24be6f 5151 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
5152 s32 err = 0;
5153
ac24be6f 5154 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 5155 scan_assoc_time);
5b435de0
AS
5156 if (err) {
5157 if (err == -EOPNOTSUPP)
5158 WL_INFO("Scan assoc time is not supported\n");
5159 else
5160 WL_ERR("Scan assoc time error (%d)\n", err);
5161 goto dongle_scantime_out;
5162 }
ac24be6f 5163 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 5164 scan_unassoc_time);
5b435de0
AS
5165 if (err) {
5166 if (err == -EOPNOTSUPP)
5167 WL_INFO("Scan unassoc time is not supported\n");
5168 else
5169 WL_ERR("Scan unassoc time error (%d)\n", err);
5170 goto dongle_scantime_out;
5171 }
5172
ac24be6f 5173 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 5174 scan_passive_time);
5b435de0
AS
5175 if (err) {
5176 if (err == -EOPNOTSUPP)
5177 WL_INFO("Scan passive time is not supported\n");
5178 else
5179 WL_ERR("Scan passive time error (%d)\n", err);
5180 goto dongle_scantime_out;
5181 }
5182
5183dongle_scantime_out:
5184 return err;
5185}
5186
27a68fe3 5187static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 5188{
ac24be6f 5189 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5190 struct wiphy *wiphy;
5191 s32 phy_list;
5192 s8 phy;
5193 s32 err = 0;
5194
ac24be6f 5195 err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
81f5dcb8 5196 &phy_list, sizeof(phy_list));
5b435de0
AS
5197 if (err) {
5198 WL_ERR("error (%d)\n", err);
5199 return err;
5200 }
5201
3ba81376 5202 phy = ((char *)&phy_list)[0];
5b435de0
AS
5203 WL_INFO("%c phy\n", phy);
5204 if (phy == 'n' || phy == 'a') {
27a68fe3 5205 wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
5206 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
5207 }
5208
5209 return err;
5210}
5211
27a68fe3 5212static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 5213{
27a68fe3 5214 return wl_update_wiphybands(cfg);
5b435de0
AS
5215}
5216
27a68fe3 5217static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
5218{
5219 struct net_device *ndev;
5220 struct wireless_dev *wdev;
5221 s32 power_mode;
5222 s32 err = 0;
5223
27a68fe3 5224 if (cfg->dongle_up)
5b435de0
AS
5225 return err;
5226
27a68fe3 5227 ndev = cfg_to_ndev(cfg);
5b435de0
AS
5228 wdev = ndev->ieee80211_ptr;
5229
5230 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
5231 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5232
5233 err = brcmf_dongle_eventmsg(ndev);
5234 if (err)
5235 goto default_conf_out;
5236
27a68fe3 5237 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
ac24be6f
AS
5238 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
5239 power_mode);
5b435de0
AS
5240 if (err)
5241 goto default_conf_out;
5242 WL_INFO("power save set to %s\n",
5243 (power_mode ? "enabled" : "disabled"));
5244
27a68fe3 5245 err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
5b435de0
AS
5246 WL_BEACON_TIMEOUT);
5247 if (err)
5248 goto default_conf_out;
5dd161ff
FL
5249 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5250 NULL, NULL);
5b435de0
AS
5251 if (err && err != -EINPROGRESS)
5252 goto default_conf_out;
27a68fe3 5253 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
5254 if (err)
5255 goto default_conf_out;
5256
5257 /* -EINPROGRESS: Call commit handler */
5258
5259default_conf_out:
5260
27a68fe3 5261 cfg->dongle_up = true;
5b435de0
AS
5262
5263 return err;
5264
5265}
5266
27a68fe3 5267static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 5268{
c1179033 5269 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
5270 s32 err = 0;
5271
c1179033 5272 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5273
27a68fe3 5274 err = brcmf_config_dongle(cfg);
5b435de0
AS
5275 if (err)
5276 return err;
5277
27a68fe3 5278 brcmf_invoke_iscan(cfg);
5b435de0
AS
5279
5280 return err;
5281}
5282
27a68fe3 5283static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 5284{
c1179033
AS
5285 struct net_device *ndev = cfg_to_ndev(cfg);
5286 struct brcmf_if *ifp = netdev_priv(ndev);
5287
5b435de0
AS
5288 /*
5289 * While going down, if associated with AP disassociate
5290 * from AP to save power
5291 */
c1179033
AS
5292 if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
5293 test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
ce81e317 5294 check_vif_up(ifp->vif)) {
5b435de0 5295 WL_INFO("Disassociating from AP");
27a68fe3 5296 brcmf_link_down(cfg);
5b435de0
AS
5297
5298 /* Make sure WPA_Supplicant receives all the event
5299 generated due to DISASSOC call to the fw to keep
5300 the state fw and WPA_Supplicant state consistent
5301 */
5302 brcmf_delay(500);
5303 }
5304
27a68fe3 5305 brcmf_abort_scanning(cfg);
c1179033 5306 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5307
5b435de0
AS
5308 return 0;
5309}
5310
27a68fe3 5311s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 5312{
5b435de0
AS
5313 s32 err = 0;
5314
27a68fe3
AS
5315 mutex_lock(&cfg->usr_sync);
5316 err = __brcmf_cfg80211_up(cfg);
5317 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5318
5319 return err;
5320}
5321
27a68fe3 5322s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 5323{
5b435de0
AS
5324 s32 err = 0;
5325
27a68fe3
AS
5326 mutex_lock(&cfg->usr_sync);
5327 err = __brcmf_cfg80211_down(cfg);
5328 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5329
5330 return err;
5331}
5332
This page took 0.529656 seconds and 5 git commands to generate.