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