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