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