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