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