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