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