brcmfmac: fix stopping AP.
[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 }
f09d0c02 2124 switch (wsec & ~SES_OW_ENABLED) {
5b435de0 2125 case WEP_ENABLED:
06bb123e 2126 sec = &profile->sec;
5b435de0
AS
2127 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2128 params.cipher = WLAN_CIPHER_SUITE_WEP40;
16886735 2129 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
5b435de0
AS
2130 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2131 params.cipher = WLAN_CIPHER_SUITE_WEP104;
16886735 2132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
5b435de0
AS
2133 }
2134 break;
2135 case TKIP_ENABLED:
2136 params.cipher = WLAN_CIPHER_SUITE_TKIP;
16886735 2137 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
5b435de0
AS
2138 break;
2139 case AES_ENABLED:
2140 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
16886735 2141 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
5b435de0
AS
2142 break;
2143 default:
57d6e91a 2144 brcmf_err("Invalid algo (0x%x)\n", wsec);
5b435de0
AS
2145 err = -EINVAL;
2146 goto done;
2147 }
2148 callback(cookie, &params);
2149
2150done:
d96b801f 2151 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2152 return err;
2153}
2154
2155static s32
2156brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2157 struct net_device *ndev, u8 key_idx)
2158{
647c9ae0 2159 brcmf_dbg(INFO, "Not supported\n");
5b435de0
AS
2160
2161 return -EOPNOTSUPP;
2162}
2163
2164static s32
2165brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
1a873342 2166 u8 *mac, struct station_info *sinfo)
5b435de0 2167{
0abb5f21
AS
2168 struct brcmf_if *ifp = netdev_priv(ndev);
2169 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
2170 struct brcmf_scb_val_le scb_val;
2171 int rssi;
2172 s32 rate;
2173 s32 err = 0;
06bb123e 2174 u8 *bssid = profile->bssid;
81f5dcb8 2175 struct brcmf_sta_info_le sta_info_le;
5b435de0 2176
d96b801f 2177 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
ce81e317 2178 if (!check_vif_up(ifp->vif))
5b435de0
AS
2179 return -EIO;
2180
128ce3b6 2181 if (ifp->vif->mode == WL_MODE_AP) {
81f5dcb8 2182 memcpy(&sta_info_le, mac, ETH_ALEN);
0abb5f21 2183 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
ac24be6f 2184 &sta_info_le,
81f5dcb8 2185 sizeof(sta_info_le));
1a873342 2186 if (err < 0) {
57d6e91a 2187 brcmf_err("GET STA INFO failed, %d\n", err);
1a873342
HM
2188 goto done;
2189 }
1a873342 2190 sinfo->filled = STATION_INFO_INACTIVE_TIME;
81f5dcb8
HM
2191 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2192 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
1a873342 2193 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
81f5dcb8 2194 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
1a873342 2195 }
d96b801f
AS
2196 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2197 sinfo->inactive_time, sinfo->connected_time);
128ce3b6 2198 } else if (ifp->vif->mode == WL_MODE_BSS) {
1a873342 2199 if (memcmp(mac, bssid, ETH_ALEN)) {
57d6e91a
AS
2200 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2201 mac, bssid);
1a873342
HM
2202 err = -ENOENT;
2203 goto done;
2204 }
2205 /* Report the current tx rate */
89286dc9 2206 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
7f6c562d 2207 if (err) {
57d6e91a 2208 brcmf_err("Could not get rate (%d)\n", err);
1a873342 2209 goto done;
7f6c562d 2210 } else {
1a873342
HM
2211 sinfo->filled |= STATION_INFO_TX_BITRATE;
2212 sinfo->txrate.legacy = rate * 5;
16886735 2213 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
7f6c562d 2214 }
5b435de0 2215
c1179033
AS
2216 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2217 &ifp->vif->sme_state)) {
1a873342 2218 memset(&scb_val, 0, sizeof(scb_val));
c1179033
AS
2219 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2220 &scb_val, sizeof(scb_val));
1a873342 2221 if (err) {
57d6e91a 2222 brcmf_err("Could not get rssi (%d)\n", err);
1a873342
HM
2223 goto done;
2224 } else {
2225 rssi = le32_to_cpu(scb_val.val);
2226 sinfo->filled |= STATION_INFO_SIGNAL;
2227 sinfo->signal = rssi;
16886735 2228 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
1a873342
HM
2229 }
2230 }
2231 } else
2232 err = -EPERM;
5b435de0 2233done:
d96b801f 2234 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2235 return err;
2236}
2237
2238static s32
2239brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2240 bool enabled, s32 timeout)
2241{
2242 s32 pm;
2243 s32 err = 0;
27a68fe3 2244 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
c1179033 2245 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 2246
d96b801f 2247 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2248
2249 /*
2250 * Powersave enable/disable request is coming from the
2251 * cfg80211 even before the interface is up. In that
2252 * scenario, driver will be storing the power save
27a68fe3 2253 * preference in cfg struct to apply this to
5b435de0
AS
2254 * FW later while initializing the dongle
2255 */
27a68fe3 2256 cfg->pwr_save = enabled;
ce81e317 2257 if (!check_vif_up(ifp->vif)) {
5b435de0 2258
647c9ae0 2259 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
5b435de0
AS
2260 goto done;
2261 }
2262
2263 pm = enabled ? PM_FAST : PM_OFF;
647c9ae0 2264 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
5b435de0 2265
c1179033 2266 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
5b435de0
AS
2267 if (err) {
2268 if (err == -ENODEV)
57d6e91a 2269 brcmf_err("net_device is not ready yet\n");
5b435de0 2270 else
57d6e91a 2271 brcmf_err("error (%d)\n", err);
5b435de0
AS
2272 }
2273done:
d96b801f 2274 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2275 return err;
2276}
2277
27a68fe3 2278static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
d34bf64f 2279 struct brcmf_bss_info_le *bi)
5b435de0 2280{
27a68fe3 2281 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
2282 struct ieee80211_channel *notify_channel;
2283 struct cfg80211_bss *bss;
2284 struct ieee80211_supported_band *band;
2285 s32 err = 0;
2286 u16 channel;
2287 u32 freq;
5b435de0
AS
2288 u16 notify_capability;
2289 u16 notify_interval;
2290 u8 *notify_ie;
2291 size_t notify_ielen;
2292 s32 notify_signal;
2293
2294 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
57d6e91a 2295 brcmf_err("Bss info is larger than buffer. Discarding\n");
5b435de0
AS
2296 return 0;
2297 }
2298
2299 channel = bi->ctl_ch ? bi->ctl_ch :
2300 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2301
2302 if (channel <= CH_MAX_2G_CHANNEL)
2303 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2304 else
2305 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2306
2307 freq = ieee80211_channel_to_frequency(channel, band->band);
2308 notify_channel = ieee80211_get_channel(wiphy, freq);
2309
5b435de0
AS
2310 notify_capability = le16_to_cpu(bi->capability);
2311 notify_interval = le16_to_cpu(bi->beacon_period);
2312 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2313 notify_ielen = le32_to_cpu(bi->ie_length);
2314 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2315
16886735
AS
2316 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2317 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2318 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2319 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2320 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
5b435de0
AS
2321
2322 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
8e6cffb3 2323 0, notify_capability, notify_interval, notify_ie,
5b435de0
AS
2324 notify_ielen, notify_signal, GFP_KERNEL);
2325
e78946e1
FL
2326 if (!bss)
2327 return -ENOMEM;
2328
5b112d3d 2329 cfg80211_put_bss(wiphy, bss);
5b435de0
AS
2330
2331 return err;
2332}
2333
6f09be0a
RV
2334static struct brcmf_bss_info_le *
2335next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2336{
2337 if (bss == NULL)
2338 return list->bss_info_le;
2339 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2340 le32_to_cpu(bss->length));
2341}
2342
27a68fe3 2343static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
2344{
2345 struct brcmf_scan_results *bss_list;
d34bf64f 2346 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
5b435de0
AS
2347 s32 err = 0;
2348 int i;
2349
27a68fe3 2350 bss_list = cfg->bss_list;
0ecd8164
AS
2351 if (bss_list->count != 0 &&
2352 bss_list->version != BRCMF_BSS_INFO_VERSION) {
57d6e91a
AS
2353 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2354 bss_list->version);
5b435de0
AS
2355 return -EOPNOTSUPP;
2356 }
4e8a008e 2357 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
f0799895 2358 for (i = 0; i < bss_list->count; i++) {
6f09be0a 2359 bi = next_bss_le(bss_list, bi);
27a68fe3 2360 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2361 if (err)
2362 break;
2363 }
2364 return err;
2365}
2366
27a68fe3 2367static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
2368 struct net_device *ndev, const u8 *bssid)
2369{
27a68fe3 2370 struct wiphy *wiphy = cfg_to_wiphy(cfg);
5b435de0 2371 struct ieee80211_channel *notify_channel;
d34bf64f 2372 struct brcmf_bss_info_le *bi = NULL;
5b435de0 2373 struct ieee80211_supported_band *band;
e78946e1 2374 struct cfg80211_bss *bss;
5b435de0
AS
2375 u8 *buf = NULL;
2376 s32 err = 0;
2377 u16 channel;
2378 u32 freq;
5b435de0
AS
2379 u16 notify_capability;
2380 u16 notify_interval;
2381 u8 *notify_ie;
2382 size_t notify_ielen;
2383 s32 notify_signal;
2384
d96b801f 2385 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2386
2387 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2388 if (buf == NULL) {
2389 err = -ENOMEM;
2390 goto CleanUp;
2391 }
2392
2393 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2394
ac24be6f
AS
2395 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2396 buf, WL_BSS_INFO_MAX);
5b435de0 2397 if (err) {
57d6e91a 2398 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
5b435de0
AS
2399 goto CleanUp;
2400 }
2401
d34bf64f 2402 bi = (struct brcmf_bss_info_le *)(buf + 4);
5b435de0
AS
2403
2404 channel = bi->ctl_ch ? bi->ctl_ch :
2405 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2406
2407 if (channel <= CH_MAX_2G_CHANNEL)
2408 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2409 else
2410 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2411
2412 freq = ieee80211_channel_to_frequency(channel, band->band);
2413 notify_channel = ieee80211_get_channel(wiphy, freq);
2414
5b435de0
AS
2415 notify_capability = le16_to_cpu(bi->capability);
2416 notify_interval = le16_to_cpu(bi->beacon_period);
2417 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2418 notify_ielen = le32_to_cpu(bi->ie_length);
2419 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2420
16886735
AS
2421 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2422 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2423 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2424 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
5b435de0 2425
e78946e1 2426 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
8e6cffb3 2427 0, notify_capability, notify_interval,
5b435de0
AS
2428 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2429
e78946e1
FL
2430 if (!bss) {
2431 err = -ENOMEM;
2432 goto CleanUp;
2433 }
2434
5b112d3d 2435 cfg80211_put_bss(wiphy, bss);
e78946e1 2436
5b435de0
AS
2437CleanUp:
2438
2439 kfree(buf);
2440
d96b801f 2441 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2442
2443 return err;
2444}
2445
128ce3b6 2446static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
5b435de0 2447{
128ce3b6 2448 return vif->mode == WL_MODE_IBSS;
5b435de0
AS
2449}
2450
89286dc9
HM
2451static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2452 struct brcmf_if *ifp)
1a873342 2453{
89286dc9 2454 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
d34bf64f 2455 struct brcmf_bss_info_le *bi;
5b435de0 2456 struct brcmf_ssid *ssid;
f8e4b412 2457 struct brcmf_tlv *tim;
5b435de0
AS
2458 u16 beacon_interval;
2459 u8 dtim_period;
2460 size_t ie_len;
2461 u8 *ie;
2462 s32 err = 0;
2463
d96b801f 2464 brcmf_dbg(TRACE, "Enter\n");
128ce3b6 2465 if (brcmf_is_ibssmode(ifp->vif))
5b435de0
AS
2466 return err;
2467
06bb123e 2468 ssid = &profile->ssid;
5b435de0 2469
27a68fe3 2470 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
ac24be6f 2471 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
81f5dcb8 2472 cfg->extra_buf, WL_EXTRA_BUF_MAX);
5b435de0 2473 if (err) {
57d6e91a 2474 brcmf_err("Could not get bss info %d\n", err);
5b435de0
AS
2475 goto update_bss_info_out;
2476 }
2477
27a68fe3
AS
2478 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2479 err = brcmf_inform_single_bss(cfg, bi);
5b435de0
AS
2480 if (err)
2481 goto update_bss_info_out;
2482
2483 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2484 ie_len = le32_to_cpu(bi->ie_length);
2485 beacon_interval = le16_to_cpu(bi->beacon_period);
2486
f8e4b412 2487 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
5b435de0
AS
2488 if (tim)
2489 dtim_period = tim->data[1];
2490 else {
2491 /*
2492 * active scan was done so we could not get dtim
2493 * information out of probe response.
2494 * so we speficially query dtim information to dongle.
2495 */
2496 u32 var;
ac24be6f 2497 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
5b435de0 2498 if (err) {
57d6e91a 2499 brcmf_err("wl dtim_assoc failed (%d)\n", err);
5b435de0
AS
2500 goto update_bss_info_out;
2501 }
2502 dtim_period = (u8)var;
2503 }
2504
5b435de0 2505update_bss_info_out:
d96b801f 2506 brcmf_dbg(TRACE, "Exit");
5b435de0
AS
2507 return err;
2508}
2509
18e2f61d 2510void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
5b435de0 2511{
27a68fe3 2512 struct escan_info *escan = &cfg->escan_info;
5b435de0 2513
c1179033 2514 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
f0799895 2515 if (cfg->scan_request) {
108a4bee 2516 escan->escan_state = WL_ESCAN_STATE_IDLE;
27a68fe3 2517 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
5b435de0 2518 }
c1179033
AS
2519 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2520 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
5b435de0
AS
2521}
2522
e756af5b
HM
2523static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2524{
27a68fe3
AS
2525 struct brcmf_cfg80211_info *cfg =
2526 container_of(work, struct brcmf_cfg80211_info,
e756af5b
HM
2527 escan_timeout_work);
2528
6eda4e2c 2529 brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
e756af5b
HM
2530}
2531
2532static void brcmf_escan_timeout(unsigned long data)
2533{
27a68fe3
AS
2534 struct brcmf_cfg80211_info *cfg =
2535 (struct brcmf_cfg80211_info *)data;
e756af5b 2536
27a68fe3 2537 if (cfg->scan_request) {
57d6e91a 2538 brcmf_err("timer expired\n");
f0799895 2539 schedule_work(&cfg->escan_timeout_work);
e756af5b
HM
2540 }
2541}
2542
2543static s32
2544brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2545 struct brcmf_bss_info_le *bss_info_le)
2546{
2547 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2548 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2549 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2550 bss_info_le->SSID_len == bss->SSID_len &&
2551 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2552 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2553 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
029591f3
AS
2554 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2555 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2556
e756af5b
HM
2557 /* preserve max RSSI if the measurements are
2558 * both on-channel or both off-channel
2559 */
029591f3 2560 if (bss_info_rssi > bss_rssi)
e756af5b
HM
2561 bss->RSSI = bss_info_le->RSSI;
2562 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2563 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2564 /* preserve the on-channel rssi measurement
2565 * if the new measurement is off channel
2566 */
2567 bss->RSSI = bss_info_le->RSSI;
2568 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2569 }
2570 return 1;
2571 }
2572 return 0;
2573}
2574
2575static s32
1993732e 2576brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
e756af5b
HM
2577 const struct brcmf_event_msg *e, void *data)
2578{
1993732e
AS
2579 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2580 struct net_device *ndev = ifp->ndev;
e756af5b
HM
2581 s32 status;
2582 s32 err = 0;
2583 struct brcmf_escan_result_le *escan_result_le;
2584 struct brcmf_bss_info_le *bss_info_le;
2585 struct brcmf_bss_info_le *bss = NULL;
2586 u32 bi_length;
2587 struct brcmf_scan_results *list;
2588 u32 i;
97ed15c7 2589 bool aborted;
e756af5b 2590
5c36b99a 2591 status = e->status;
e756af5b 2592
f0799895 2593 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a
AS
2594 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2595 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
e756af5b
HM
2596 return -EPERM;
2597 }
2598
2599 if (status == BRCMF_E_STATUS_PARTIAL) {
4e8a008e 2600 brcmf_dbg(SCAN, "ESCAN Partial result\n");
e756af5b
HM
2601 escan_result_le = (struct brcmf_escan_result_le *) data;
2602 if (!escan_result_le) {
57d6e91a 2603 brcmf_err("Invalid escan result (NULL pointer)\n");
e756af5b
HM
2604 goto exit;
2605 }
e756af5b 2606 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
57d6e91a
AS
2607 brcmf_err("Invalid bss_count %d: ignoring\n",
2608 escan_result_le->bss_count);
e756af5b
HM
2609 goto exit;
2610 }
2611 bss_info_le = &escan_result_le->bss_info_le;
2612
6eda4e2c
HM
2613 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2614 goto exit;
2615
2616 if (!cfg->scan_request) {
2617 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2618 goto exit;
2619 }
2620
e756af5b
HM
2621 bi_length = le32_to_cpu(bss_info_le->length);
2622 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2623 WL_ESCAN_RESULTS_FIXED_SIZE)) {
57d6e91a
AS
2624 brcmf_err("Invalid bss_info length %d: ignoring\n",
2625 bi_length);
e756af5b
HM
2626 goto exit;
2627 }
2628
27a68fe3 2629 if (!(cfg_to_wiphy(cfg)->interface_modes &
e756af5b
HM
2630 BIT(NL80211_IFTYPE_ADHOC))) {
2631 if (le16_to_cpu(bss_info_le->capability) &
2632 WLAN_CAPABILITY_IBSS) {
57d6e91a 2633 brcmf_err("Ignoring IBSS result\n");
e756af5b
HM
2634 goto exit;
2635 }
2636 }
2637
2638 list = (struct brcmf_scan_results *)
27a68fe3 2639 cfg->escan_info.escan_buf;
e756af5b 2640 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
57d6e91a 2641 brcmf_err("Buffer is too small: ignoring\n");
e756af5b
HM
2642 goto exit;
2643 }
2644
2645 for (i = 0; i < list->count; i++) {
2646 bss = bss ? (struct brcmf_bss_info_le *)
2647 ((unsigned char *)bss +
2648 le32_to_cpu(bss->length)) : list->bss_info_le;
2649 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2650 goto exit;
2651 }
27a68fe3 2652 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
e756af5b
HM
2653 bss_info_le, bi_length);
2654 list->version = le32_to_cpu(bss_info_le->version);
2655 list->buflen += bi_length;
2656 list->count++;
2657 } else {
27a68fe3 2658 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
6eda4e2c
HM
2659 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2660 goto exit;
27a68fe3
AS
2661 if (cfg->scan_request) {
2662 cfg->bss_list = (struct brcmf_scan_results *)
2663 cfg->escan_info.escan_buf;
2664 brcmf_inform_bss(cfg);
97ed15c7 2665 aborted = status != BRCMF_E_STATUS_SUCCESS;
27a68fe3 2666 brcmf_notify_escan_complete(cfg, ndev, aborted,
97ed15c7 2667 false);
e756af5b 2668 } else
6eda4e2c
HM
2669 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2670 status);
e756af5b
HM
2671 }
2672exit:
2673 return err;
2674}
2675
27a68fe3 2676static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
e756af5b 2677{
5c36b99a
AS
2678 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2679 brcmf_cfg80211_escan_handler);
f0799895
HM
2680 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2681 /* Init scan_timeout timer */
2682 init_timer(&cfg->escan_timeout);
2683 cfg->escan_timeout.data = (unsigned long) cfg;
2684 cfg->escan_timeout.function = brcmf_escan_timeout;
2685 INIT_WORK(&cfg->escan_timeout_work,
2686 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2687}
2688
5addc0de 2689static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2690{
2691 if (ms < 1000 / HZ) {
2692 cond_resched();
2693 mdelay(ms);
2694 } else {
2695 msleep(ms);
2696 }
2697}
2698
2699static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2700{
d96b801f 2701 brcmf_dbg(TRACE, "Enter\n");
5b435de0 2702
5b435de0
AS
2703 return 0;
2704}
2705
2706static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2707 struct cfg80211_wowlan *wow)
2708{
27a68fe3
AS
2709 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2710 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 2711 struct brcmf_cfg80211_vif *vif;
5b435de0 2712
d96b801f 2713 brcmf_dbg(TRACE, "Enter\n");
5b435de0
AS
2714
2715 /*
7d641072
AS
2716 * if the primary net_device is not READY there is nothing
2717 * we can do but pray resume goes smoothly.
5b435de0 2718 */
7d641072
AS
2719 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2720 if (!check_vif_up(vif))
2721 goto exit;
5b435de0 2722
7d641072
AS
2723 list_for_each_entry(vif, &cfg->vif_list, list) {
2724 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2725 continue;
5b435de0 2726 /*
7d641072
AS
2727 * While going to suspend if associated with AP disassociate
2728 * from AP to save power while system is in suspended state
5b435de0 2729 */
903e0eee
AS
2730 brcmf_link_down(vif);
2731
2732 /* Make sure WPA_Supplicant receives all the event
2733 * generated due to DISASSOC call to the fw to keep
2734 * the state fw and WPA_Supplicant state consistent
2735 */
2736 brcmf_delay(500);
5b435de0
AS
2737 }
2738
7d641072
AS
2739 /* end any scanning */
2740 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 2741 brcmf_abort_scanning(cfg);
5b435de0
AS
2742
2743 /* Turn off watchdog timer */
7d641072 2744 brcmf_set_mpc(ndev, 1);
5b435de0 2745
7d641072 2746exit:
d96b801f 2747 brcmf_dbg(TRACE, "Exit\n");
7d641072
AS
2748 /* clear any scanning activity */
2749 cfg->scan_status = 0;
5b435de0
AS
2750 return 0;
2751}
2752
5b435de0
AS
2753static __used s32
2754brcmf_update_pmklist(struct net_device *ndev,
2755 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2756{
2757 int i, j;
40c8e95a 2758 int pmkid_len;
5b435de0 2759
40c8e95a
AS
2760 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2761
16886735 2762 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
40c8e95a 2763 for (i = 0; i < pmkid_len; i++) {
16886735
AS
2764 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2765 &pmk_list->pmkids.pmkid[i].BSSID);
5b435de0 2766 for (j = 0; j < WLAN_PMKID_LEN; j++)
16886735
AS
2767 brcmf_dbg(CONN, "%02x\n",
2768 pmk_list->pmkids.pmkid[i].PMKID[j]);
5b435de0
AS
2769 }
2770
2771 if (!err)
ac24be6f
AS
2772 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2773 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
2774
2775 return err;
2776}
2777
2778static s32
2779brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2780 struct cfg80211_pmksa *pmksa)
2781{
27a68fe3 2782 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2783 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2784 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
2785 s32 err = 0;
2786 int i;
40c8e95a 2787 int pmkid_len;
5b435de0 2788
d96b801f 2789 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2790 if (!check_vif_up(ifp->vif))
5b435de0
AS
2791 return -EIO;
2792
40c8e95a
AS
2793 pmkid_len = le32_to_cpu(pmkids->npmkid);
2794 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
2795 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2796 break;
2797 if (i < WL_NUM_PMKIDS_MAX) {
2798 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2799 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
2800 if (i == pmkid_len) {
2801 pmkid_len++;
2802 pmkids->npmkid = cpu_to_le32(pmkid_len);
2803 }
5b435de0
AS
2804 } else
2805 err = -EINVAL;
2806
16886735
AS
2807 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2808 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 2809 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2810 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 2811
27a68fe3 2812 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2813
d96b801f 2814 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2815 return err;
2816}
2817
2818static s32
2819brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2820 struct cfg80211_pmksa *pmksa)
2821{
27a68fe3 2822 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2823 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2824 struct pmkid_list pmkid;
2825 s32 err = 0;
40c8e95a 2826 int i, pmkid_len;
5b435de0 2827
d96b801f 2828 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2829 if (!check_vif_up(ifp->vif))
5b435de0
AS
2830 return -EIO;
2831
2832 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2833 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2834
16886735
AS
2835 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2836 &pmkid.pmkid[0].BSSID);
5b435de0 2837 for (i = 0; i < WLAN_PMKID_LEN; i++)
16886735 2838 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
5b435de0 2839
27a68fe3 2840 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 2841 for (i = 0; i < pmkid_len; i++)
5b435de0 2842 if (!memcmp
27a68fe3 2843 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
2844 ETH_ALEN))
2845 break;
2846
40c8e95a
AS
2847 if ((pmkid_len > 0)
2848 && (i < pmkid_len)) {
27a68fe3 2849 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 2850 sizeof(struct pmkid));
40c8e95a 2851 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
2852 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2853 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 2854 ETH_ALEN);
27a68fe3
AS
2855 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2856 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
2857 WLAN_PMKID_LEN);
2858 }
27a68fe3 2859 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
2860 } else
2861 err = -EINVAL;
2862
27a68fe3 2863 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2864
d96b801f 2865 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2866 return err;
2867
2868}
2869
2870static s32
2871brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2872{
27a68fe3 2873 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2874 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2875 s32 err = 0;
2876
d96b801f 2877 brcmf_dbg(TRACE, "Enter\n");
ce81e317 2878 if (!check_vif_up(ifp->vif))
5b435de0
AS
2879 return -EIO;
2880
27a68fe3
AS
2881 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2882 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0 2883
d96b801f 2884 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
2885 return err;
2886
2887}
2888
e5806072
AS
2889/*
2890 * PFN result doesn't have all the info which are
2891 * required by the supplicant
2892 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2893 * via wl_inform_single_bss in the required format. Escan does require the
2894 * scan request in the form of cfg80211_scan_request. For timebeing, create
2895 * cfg80211_scan_request one out of the received PNO event.
2896 */
2897static s32
1993732e 2898brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
2899 const struct brcmf_event_msg *e, void *data)
2900{
1993732e
AS
2901 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2902 struct net_device *ndev = ifp->ndev;
e5806072
AS
2903 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2904 struct cfg80211_scan_request *request = NULL;
2905 struct cfg80211_ssid *ssid = NULL;
2906 struct ieee80211_channel *channel = NULL;
27a68fe3 2907 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
2908 int err = 0;
2909 int channel_req = 0;
2910 int band = 0;
2911 struct brcmf_pno_scanresults_le *pfn_result;
2912 u32 result_count;
2913 u32 status;
2914
4e8a008e 2915 brcmf_dbg(SCAN, "Enter\n");
e5806072 2916
5c36b99a 2917 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
4e8a008e 2918 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
e5806072
AS
2919 return 0;
2920 }
2921
2922 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2923 result_count = le32_to_cpu(pfn_result->count);
2924 status = le32_to_cpu(pfn_result->status);
2925
2926 /*
2927 * PFN event is limited to fit 512 bytes so we may get
2928 * multiple NET_FOUND events. For now place a warning here.
2929 */
2930 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
4e8a008e 2931 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
e5806072
AS
2932 if (result_count > 0) {
2933 int i;
2934
2935 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
2936 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2937 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
2938 if (!request || !ssid || !channel) {
2939 err = -ENOMEM;
2940 goto out_err;
2941 }
2942
2943 request->wiphy = wiphy;
2944 data += sizeof(struct brcmf_pno_scanresults_le);
2945 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2946
2947 for (i = 0; i < result_count; i++) {
2948 netinfo = &netinfo_start[i];
2949 if (!netinfo) {
57d6e91a
AS
2950 brcmf_err("Invalid netinfo ptr. index: %d\n",
2951 i);
e5806072
AS
2952 err = -EINVAL;
2953 goto out_err;
2954 }
2955
4e8a008e
AS
2956 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2957 netinfo->SSID, netinfo->channel);
e5806072
AS
2958 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2959 ssid[i].ssid_len = netinfo->SSID_len;
2960 request->n_ssids++;
2961
2962 channel_req = netinfo->channel;
2963 if (channel_req <= CH_MAX_2G_CHANNEL)
2964 band = NL80211_BAND_2GHZ;
2965 else
2966 band = NL80211_BAND_5GHZ;
2967 channel[i].center_freq =
2968 ieee80211_channel_to_frequency(channel_req,
2969 band);
2970 channel[i].band = band;
2971 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2972 request->channels[i] = &channel[i];
2973 request->n_channels++;
2974 }
2975
2976 /* assign parsed ssid array */
2977 if (request->n_ssids)
2978 request->ssids = &ssid[0];
2979
c1179033 2980 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 2981 /* Abort any on-going scan */
27a68fe3 2982 brcmf_abort_scanning(cfg);
e5806072
AS
2983 }
2984
c1179033 2985 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 2986 err = brcmf_do_escan(cfg, wiphy, ndev, request);
e5806072 2987 if (err) {
c1179033 2988 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
2989 goto out_err;
2990 }
27a68fe3
AS
2991 cfg->sched_escan = true;
2992 cfg->scan_request = request;
e5806072 2993 } else {
57d6e91a 2994 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
e5806072
AS
2995 goto out_err;
2996 }
2997
2998 kfree(ssid);
2999 kfree(channel);
3000 kfree(request);
3001 return 0;
3002
3003out_err:
3004 kfree(ssid);
3005 kfree(channel);
3006 kfree(request);
3007 cfg80211_sched_scan_stopped(wiphy);
3008 return err;
3009}
3010
e5806072
AS
3011static int brcmf_dev_pno_clean(struct net_device *ndev)
3012{
e5806072
AS
3013 int ret;
3014
3015 /* Disable pfn */
ac24be6f 3016 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
3017 if (ret == 0) {
3018 /* clear pfn */
ac24be6f
AS
3019 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3020 NULL, 0);
e5806072
AS
3021 }
3022 if (ret < 0)
57d6e91a 3023 brcmf_err("failed code %d\n", ret);
e5806072
AS
3024
3025 return ret;
3026}
3027
3028static int brcmf_dev_pno_config(struct net_device *ndev)
3029{
3030 struct brcmf_pno_param_le pfn_param;
e5806072
AS
3031
3032 memset(&pfn_param, 0, sizeof(pfn_param));
3033 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3034
3035 /* set extra pno params */
3036 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3037 pfn_param.repeat = BRCMF_PNO_REPEAT;
3038 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3039
3040 /* set up pno scan fr */
3041 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3042
ac24be6f
AS
3043 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3044 &pfn_param, sizeof(pfn_param));
e5806072
AS
3045}
3046
3047static int
3048brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3049 struct net_device *ndev,
3050 struct cfg80211_sched_scan_request *request)
3051{
c1179033 3052 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3053 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
3054 struct brcmf_pno_net_param_le pfn;
3055 int i;
3056 int ret = 0;
3057
4e8a008e
AS
3058 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3059 request->n_match_sets, request->n_ssids);
c1179033 3060 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
57d6e91a 3061 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
3062 return -EAGAIN;
3063 }
3064
3065 if (!request || !request->n_ssids || !request->n_match_sets) {
57d6e91a
AS
3066 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
3067 request ? request->n_ssids : 0);
e5806072
AS
3068 return -EINVAL;
3069 }
3070
3071 if (request->n_ssids > 0) {
3072 for (i = 0; i < request->n_ssids; i++) {
3073 /* Active scan req for ssids */
4e8a008e
AS
3074 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3075 request->ssids[i].ssid);
e5806072
AS
3076
3077 /*
3078 * match_set ssids is a supert set of n_ssid list,
3079 * so we need not add these set seperately.
3080 */
3081 }
3082 }
3083
3084 if (request->n_match_sets > 0) {
3085 /* clean up everything */
3086 ret = brcmf_dev_pno_clean(ndev);
3087 if (ret < 0) {
57d6e91a 3088 brcmf_err("failed error=%d\n", ret);
e5806072
AS
3089 return ret;
3090 }
3091
3092 /* configure pno */
3093 ret = brcmf_dev_pno_config(ndev);
3094 if (ret < 0) {
57d6e91a 3095 brcmf_err("PNO setup failed!! ret=%d\n", ret);
e5806072
AS
3096 return -EINVAL;
3097 }
3098
3099 /* configure each match set */
3100 for (i = 0; i < request->n_match_sets; i++) {
3101 struct cfg80211_ssid *ssid;
3102 u32 ssid_len;
3103
3104 ssid = &request->match_sets[i].ssid;
3105 ssid_len = ssid->ssid_len;
3106
3107 if (!ssid_len) {
57d6e91a 3108 brcmf_err("skip broadcast ssid\n");
e5806072
AS
3109 continue;
3110 }
3111 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3112 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3113 pfn.wsec = cpu_to_le32(0);
3114 pfn.infra = cpu_to_le32(1);
3115 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3116 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3117 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 3118 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 3119 sizeof(pfn));
4e8a008e
AS
3120 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3121 ret == 0 ? "set" : "failed", ssid->ssid);
e5806072
AS
3122 }
3123 /* Enable the PNO */
c1179033 3124 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
57d6e91a 3125 brcmf_err("PNO enable failed!! ret=%d\n", ret);
e5806072
AS
3126 return -EINVAL;
3127 }
3128 } else {
3129 return -EINVAL;
3130 }
3131
3132 return 0;
3133}
3134
3135static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3136 struct net_device *ndev)
3137{
27a68fe3 3138 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072 3139
4e8a008e 3140 brcmf_dbg(SCAN, "enter\n");
e5806072 3141 brcmf_dev_pno_clean(ndev);
27a68fe3
AS
3142 if (cfg->sched_escan)
3143 brcmf_notify_escan_complete(cfg, ndev, true, true);
e5806072
AS
3144 return 0;
3145}
e5806072 3146
cbaa177d
AS
3147#ifdef CONFIG_NL80211_TESTMODE
3148static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3149{
27a68fe3 3150 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3151 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3152 struct brcmf_dcmd *dcmd = data;
3153 struct sk_buff *reply;
3154 int ret;
3155
d96b801f
AS
3156 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3157 dcmd->buf, dcmd->len);
f368a5b6
HM
3158
3159 if (dcmd->set)
ac24be6f
AS
3160 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3161 dcmd->buf, dcmd->len);
f368a5b6 3162 else
ac24be6f
AS
3163 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3164 dcmd->buf, dcmd->len);
cbaa177d
AS
3165 if (ret == 0) {
3166 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3167 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3168 ret = cfg80211_testmode_reply(reply);
3169 }
3170 return ret;
3171}
3172#endif
3173
1f170110 3174static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
1a873342
HM
3175{
3176 s32 err;
3177
3178 /* set auth */
ac24be6f 3179 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342 3180 if (err < 0) {
57d6e91a 3181 brcmf_err("auth error %d\n", err);
1a873342
HM
3182 return err;
3183 }
3184 /* set wsec */
ac24be6f 3185 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342 3186 if (err < 0) {
57d6e91a 3187 brcmf_err("wsec error %d\n", err);
1a873342
HM
3188 return err;
3189 }
3190 /* set upper-layer auth */
ac24be6f 3191 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342 3192 if (err < 0) {
57d6e91a 3193 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3194 return err;
3195 }
3196
3197 return 0;
3198}
3199
3200static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3201{
3202 if (is_rsn_ie)
3203 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3204
3205 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3206}
3207
3208static s32
3209brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
34778529 3210 bool is_rsn_ie)
1a873342 3211{
ac24be6f 3212 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3213 u32 auth = 0; /* d11 open authentication */
3214 u16 count;
3215 s32 err = 0;
3216 s32 len = 0;
3217 u32 i;
3218 u32 wsec;
3219 u32 pval = 0;
3220 u32 gval = 0;
3221 u32 wpa_auth = 0;
3222 u32 offset;
3223 u8 *data;
3224 u16 rsn_cap;
3225 u32 wme_bss_disable;
3226
d96b801f 3227 brcmf_dbg(TRACE, "Enter\n");
1a873342
HM
3228 if (wpa_ie == NULL)
3229 goto exit;
3230
3231 len = wpa_ie->len + TLV_HDR_LEN;
3232 data = (u8 *)wpa_ie;
619c5a9a 3233 offset = TLV_HDR_LEN;
1a873342
HM
3234 if (!is_rsn_ie)
3235 offset += VS_IE_FIXED_HDR_LEN;
619c5a9a
HM
3236 else
3237 offset += WPA_IE_VERSION_LEN;
1a873342
HM
3238
3239 /* check for multicast cipher suite */
3240 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3241 err = -EINVAL;
57d6e91a 3242 brcmf_err("no multicast cipher suite\n");
1a873342
HM
3243 goto exit;
3244 }
3245
3246 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3247 err = -EINVAL;
57d6e91a 3248 brcmf_err("ivalid OUI\n");
1a873342
HM
3249 goto exit;
3250 }
3251 offset += TLV_OUI_LEN;
3252
3253 /* pick up multicast cipher */
3254 switch (data[offset]) {
3255 case WPA_CIPHER_NONE:
3256 gval = 0;
3257 break;
3258 case WPA_CIPHER_WEP_40:
3259 case WPA_CIPHER_WEP_104:
3260 gval = WEP_ENABLED;
3261 break;
3262 case WPA_CIPHER_TKIP:
3263 gval = TKIP_ENABLED;
3264 break;
3265 case WPA_CIPHER_AES_CCM:
3266 gval = AES_ENABLED;
3267 break;
3268 default:
3269 err = -EINVAL;
57d6e91a 3270 brcmf_err("Invalid multi cast cipher info\n");
1a873342
HM
3271 goto exit;
3272 }
3273
3274 offset++;
3275 /* walk thru unicast cipher list and pick up what we recognize */
3276 count = data[offset] + (data[offset + 1] << 8);
3277 offset += WPA_IE_SUITE_COUNT_LEN;
3278 /* Check for unicast suite(s) */
3279 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3280 err = -EINVAL;
57d6e91a 3281 brcmf_err("no unicast cipher suite\n");
1a873342
HM
3282 goto exit;
3283 }
3284 for (i = 0; i < count; i++) {
3285 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3286 err = -EINVAL;
57d6e91a 3287 brcmf_err("ivalid OUI\n");
1a873342
HM
3288 goto exit;
3289 }
3290 offset += TLV_OUI_LEN;
3291 switch (data[offset]) {
3292 case WPA_CIPHER_NONE:
3293 break;
3294 case WPA_CIPHER_WEP_40:
3295 case WPA_CIPHER_WEP_104:
3296 pval |= WEP_ENABLED;
3297 break;
3298 case WPA_CIPHER_TKIP:
3299 pval |= TKIP_ENABLED;
3300 break;
3301 case WPA_CIPHER_AES_CCM:
3302 pval |= AES_ENABLED;
3303 break;
3304 default:
57d6e91a 3305 brcmf_err("Ivalid unicast security info\n");
1a873342
HM
3306 }
3307 offset++;
3308 }
3309 /* walk thru auth management suite list and pick up what we recognize */
3310 count = data[offset] + (data[offset + 1] << 8);
3311 offset += WPA_IE_SUITE_COUNT_LEN;
3312 /* Check for auth key management suite(s) */
3313 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3314 err = -EINVAL;
57d6e91a 3315 brcmf_err("no auth key mgmt suite\n");
1a873342
HM
3316 goto exit;
3317 }
3318 for (i = 0; i < count; i++) {
3319 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3320 err = -EINVAL;
57d6e91a 3321 brcmf_err("ivalid OUI\n");
1a873342
HM
3322 goto exit;
3323 }
3324 offset += TLV_OUI_LEN;
3325 switch (data[offset]) {
3326 case RSN_AKM_NONE:
d96b801f 3327 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
1a873342
HM
3328 wpa_auth |= WPA_AUTH_NONE;
3329 break;
3330 case RSN_AKM_UNSPECIFIED:
d96b801f 3331 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
1a873342
HM
3332 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3333 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3334 break;
3335 case RSN_AKM_PSK:
d96b801f 3336 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
1a873342
HM
3337 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3338 (wpa_auth |= WPA_AUTH_PSK);
3339 break;
3340 default:
57d6e91a 3341 brcmf_err("Ivalid key mgmt info\n");
1a873342
HM
3342 }
3343 offset++;
3344 }
3345
3346 if (is_rsn_ie) {
3347 wme_bss_disable = 1;
3348 if ((offset + RSN_CAP_LEN) <= len) {
3349 rsn_cap = data[offset] + (data[offset + 1] << 8);
3350 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3351 wme_bss_disable = 0;
3352 }
3353 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3354 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3355 wme_bss_disable);
1a873342 3356 if (err < 0) {
57d6e91a 3357 brcmf_err("wme_bss_disable error %d\n", err);
1a873342
HM
3358 goto exit;
3359 }
3360 }
3361 /* FOR WPS , set SES_OW_ENABLED */
3362 wsec = (pval | gval | SES_OW_ENABLED);
3363
3364 /* set auth */
ac24be6f 3365 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342 3366 if (err < 0) {
57d6e91a 3367 brcmf_err("auth error %d\n", err);
1a873342
HM
3368 goto exit;
3369 }
3370 /* set wsec */
ac24be6f 3371 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342 3372 if (err < 0) {
57d6e91a 3373 brcmf_err("wsec error %d\n", err);
1a873342
HM
3374 goto exit;
3375 }
3376 /* set upper-layer auth */
ac24be6f 3377 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342 3378 if (err < 0) {
57d6e91a 3379 brcmf_err("wpa_auth error %d\n", err);
1a873342
HM
3380 goto exit;
3381 }
3382
3383exit:
3384 return err;
3385}
3386
3387static s32
3082b9be 3388brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
3389 struct parsed_vndr_ies *vndr_ies)
3390{
3391 s32 err = 0;
3392 struct brcmf_vs_tlv *vndrie;
3393 struct brcmf_tlv *ie;
3394 struct parsed_vndr_ie_info *parsed_info;
3395 s32 remaining_len;
3396
3397 remaining_len = (s32)vndr_ie_len;
3398 memset(vndr_ies, 0, sizeof(*vndr_ies));
3399
3400 ie = (struct brcmf_tlv *)vndr_ie_buf;
3401 while (ie) {
3402 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3403 goto next;
3404 vndrie = (struct brcmf_vs_tlv *)ie;
3405 /* len should be bigger than OUI length + one */
3406 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
57d6e91a
AS
3407 brcmf_err("invalid vndr ie. length is too small %d\n",
3408 vndrie->len);
1a873342
HM
3409 goto next;
3410 }
3411 /* if wpa or wme ie, do not add ie */
3412 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3413 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3414 (vndrie->oui_type == WME_OUI_TYPE))) {
d96b801f 3415 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
1a873342
HM
3416 goto next;
3417 }
3418
3419 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3420
3421 /* save vndr ie information */
3422 parsed_info->ie_ptr = (char *)vndrie;
3423 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3424 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3425
3426 vndr_ies->count++;
3427
d96b801f
AS
3428 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3429 parsed_info->vndrie.oui[0],
3430 parsed_info->vndrie.oui[1],
3431 parsed_info->vndrie.oui[2],
3432 parsed_info->vndrie.oui_type);
1a873342 3433
9f440b7b 3434 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
1a873342
HM
3435 break;
3436next:
b41fc3d7
HM
3437 remaining_len -= (ie->len + TLV_HDR_LEN);
3438 if (remaining_len <= TLV_HDR_LEN)
1a873342
HM
3439 ie = NULL;
3440 else
b41fc3d7
HM
3441 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3442 TLV_HDR_LEN);
1a873342
HM
3443 }
3444 return err;
3445}
3446
3447static u32
3448brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3449{
3450
3451 __le32 iecount_le;
3452 __le32 pktflag_le;
3453
3454 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3455 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3456
3457 iecount_le = cpu_to_le32(1);
3458 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3459
3460 pktflag_le = cpu_to_le32(pktflag);
3461 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3462
3463 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3464
3465 return ie_len + VNDR_IE_HDR_SIZE;
3466}
3467
1332e26e
AS
3468s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3469 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 3470{
1332e26e
AS
3471 struct brcmf_if *ifp;
3472 struct vif_saved_ie *saved_ie;
1a873342
HM
3473 s32 err = 0;
3474 u8 *iovar_ie_buf;
3475 u8 *curr_ie_buf;
3476 u8 *mgmt_ie_buf = NULL;
3e4f319d 3477 int mgmt_ie_buf_len;
81118d16 3478 u32 *mgmt_ie_len;
1a873342
HM
3479 u32 del_add_ie_buf_len = 0;
3480 u32 total_ie_buf_len = 0;
3481 u32 parsed_ie_buf_len = 0;
3482 struct parsed_vndr_ies old_vndr_ies;
3483 struct parsed_vndr_ies new_vndr_ies;
3484 struct parsed_vndr_ie_info *vndrie_info;
3485 s32 i;
3486 u8 *ptr;
3e4f319d 3487 int remained_buf_len;
1a873342 3488
1332e26e
AS
3489 if (!vif)
3490 return -ENODEV;
3491 ifp = vif->ifp;
3492 saved_ie = &vif->saved_ie;
3493
d96b801f 3494 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
1a873342
HM
3495 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3496 if (!iovar_ie_buf)
3497 return -ENOMEM;
3498 curr_ie_buf = iovar_ie_buf;
89286dc9
HM
3499 switch (pktflag) {
3500 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3501 mgmt_ie_buf = saved_ie->probe_req_ie;
3502 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3503 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3504 break;
3505 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3506 mgmt_ie_buf = saved_ie->probe_res_ie;
3507 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3508 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3509 break;
3510 case BRCMF_VNDR_IE_BEACON_FLAG:
3511 mgmt_ie_buf = saved_ie->beacon_ie;
3512 mgmt_ie_len = &saved_ie->beacon_ie_len;
3513 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3514 break;
3515 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3516 mgmt_ie_buf = saved_ie->assoc_req_ie;
3517 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3518 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3519 break;
3520 default:
3521 err = -EPERM;
3522 brcmf_err("not suitable type\n");
3523 goto exit;
1a873342
HM
3524 }
3525
3526 if (vndr_ie_len > mgmt_ie_buf_len) {
3527 err = -ENOMEM;
57d6e91a 3528 brcmf_err("extra IE size too big\n");
1a873342
HM
3529 goto exit;
3530 }
3531
3532 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3533 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3534 ptr = curr_ie_buf;
3535 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3536 for (i = 0; i < new_vndr_ies.count; i++) {
3537 vndrie_info = &new_vndr_ies.ie_info[i];
3538 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3539 vndrie_info->ie_len);
3540 parsed_ie_buf_len += vndrie_info->ie_len;
3541 }
3542 }
3543
b41fc3d7 3544 if (mgmt_ie_buf && *mgmt_ie_len) {
1a873342
HM
3545 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3546 (memcmp(mgmt_ie_buf, curr_ie_buf,
3547 parsed_ie_buf_len) == 0)) {
d96b801f 3548 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
1a873342
HM
3549 goto exit;
3550 }
3551
3552 /* parse old vndr_ie */
3553 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3554
3555 /* make a command to delete old ie */
3556 for (i = 0; i < old_vndr_ies.count; i++) {
3557 vndrie_info = &old_vndr_ies.ie_info[i];
3558
d96b801f
AS
3559 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3560 vndrie_info->vndrie.id,
3561 vndrie_info->vndrie.len,
3562 vndrie_info->vndrie.oui[0],
3563 vndrie_info->vndrie.oui[1],
3564 vndrie_info->vndrie.oui[2]);
1a873342
HM
3565
3566 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3567 vndrie_info->ie_ptr,
3568 vndrie_info->ie_len,
3569 "del");
3570 curr_ie_buf += del_add_ie_buf_len;
3571 total_ie_buf_len += del_add_ie_buf_len;
3572 }
3573 }
3574
3575 *mgmt_ie_len = 0;
3576 /* Add if there is any extra IE */
3577 if (mgmt_ie_buf && parsed_ie_buf_len) {
3578 ptr = mgmt_ie_buf;
3579
3580 remained_buf_len = mgmt_ie_buf_len;
3581
3582 /* make a command to add new ie */
3583 for (i = 0; i < new_vndr_ies.count; i++) {
3584 vndrie_info = &new_vndr_ies.ie_info[i];
3585
b41fc3d7
HM
3586 /* verify remained buf size before copy data */
3587 if (remained_buf_len < (vndrie_info->vndrie.len +
3588 VNDR_IE_VSIE_OFFSET)) {
57d6e91a
AS
3589 brcmf_err("no space in mgmt_ie_buf: len left %d",
3590 remained_buf_len);
b41fc3d7
HM
3591 break;
3592 }
3593 remained_buf_len -= (vndrie_info->ie_len +
3594 VNDR_IE_VSIE_OFFSET);
3595
d96b801f
AS
3596 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3597 vndrie_info->vndrie.id,
3598 vndrie_info->vndrie.len,
3599 vndrie_info->vndrie.oui[0],
3600 vndrie_info->vndrie.oui[1],
3601 vndrie_info->vndrie.oui[2]);
1a873342
HM
3602
3603 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3604 vndrie_info->ie_ptr,
3605 vndrie_info->ie_len,
3606 "add");
1a873342
HM
3607
3608 /* save the parsed IE in wl struct */
3609 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3610 vndrie_info->ie_len);
3611 *mgmt_ie_len += vndrie_info->ie_len;
3612
3613 curr_ie_buf += del_add_ie_buf_len;
3614 total_ie_buf_len += del_add_ie_buf_len;
3615 }
3616 }
3617 if (total_ie_buf_len) {
c1179033 3618 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3619 total_ie_buf_len);
1a873342 3620 if (err)
57d6e91a 3621 brcmf_err("vndr ie set error : %d\n", err);
1a873342
HM
3622 }
3623
3624exit:
3625 kfree(iovar_ie_buf);
3626 return err;
3627}
3628
5f4f9f11
AS
3629s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3630{
3631 s32 pktflags[] = {
3632 BRCMF_VNDR_IE_PRBREQ_FLAG,
3633 BRCMF_VNDR_IE_PRBRSP_FLAG,
3634 BRCMF_VNDR_IE_BEACON_FLAG
3635 };
3636 int i;
3637
3638 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3639 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3640
3641 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3642 return 0;
3643}
3644
a0f07959
HM
3645static s32
3646brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3647 struct cfg80211_beacon_data *beacon)
3648{
3649 s32 err;
3650
3651 /* Set Beacon IEs to FW */
3652 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3653 beacon->tail, beacon->tail_len);
3654 if (err) {
3655 brcmf_err("Set Beacon IE Failed\n");
3656 return err;
3657 }
3658 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3659
3660 /* Set Probe Response IEs to FW */
3661 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3662 beacon->proberesp_ies,
3663 beacon->proberesp_ies_len);
3664 if (err)
3665 brcmf_err("Set Probe Resp IE Failed\n");
3666 else
3667 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3668
3669 return err;
3670}
3671
1a873342
HM
3672static s32
3673brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3674 struct cfg80211_ap_settings *settings)
3675{
3676 s32 ie_offset;
ac24be6f 3677 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3678 struct brcmf_tlv *ssid_ie;
3679 struct brcmf_ssid_le ssid_le;
1a873342
HM
3680 s32 err = -EPERM;
3681 struct brcmf_tlv *rsn_ie;
3682 struct brcmf_vs_tlv *wpa_ie;
3683 struct brcmf_join_params join_params;
a0f07959
HM
3684 enum nl80211_iftype dev_role;
3685 struct brcmf_fil_bss_enable_le bss_enable;
1a873342 3686
d96b801f
AS
3687 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3688 cfg80211_get_chandef_type(&settings->chandef),
3689 settings->beacon_interval,
3690 settings->dtim_period);
3691 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3692 settings->ssid, settings->ssid_len, settings->auth_type,
3693 settings->inactivity_timeout);
1a873342 3694
426d0a56 3695 dev_role = ifp->vif->wdev.iftype;
1a873342
HM
3696
3697 memset(&ssid_le, 0, sizeof(ssid_le));
3698 if (settings->ssid == NULL || settings->ssid_len == 0) {
3699 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3700 ssid_ie = brcmf_parse_tlvs(
3701 (u8 *)&settings->beacon.head[ie_offset],
3702 settings->beacon.head_len - ie_offset,
3703 WLAN_EID_SSID);
3704 if (!ssid_ie)
3705 return -EINVAL;
3706
3707 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3708 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
d96b801f 3709 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
1a873342
HM
3710 } else {
3711 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3712 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3713 }
3714
3715 brcmf_set_mpc(ndev, 0);
1a873342
HM
3716
3717 /* find the RSN_IE */
3718 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3719 settings->beacon.tail_len, WLAN_EID_RSN);
3720
3721 /* find the WPA_IE */
3722 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3723 settings->beacon.tail_len);
3724
1a873342 3725 if ((wpa_ie != NULL || rsn_ie != NULL)) {
d96b801f 3726 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
1a873342
HM
3727 if (wpa_ie != NULL) {
3728 /* WPA IE */
34778529 3729 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
1a873342
HM
3730 if (err < 0)
3731 goto exit;
1a873342
HM
3732 } else {
3733 /* RSN IE */
3734 err = brcmf_configure_wpaie(ndev,
34778529 3735 (struct brcmf_vs_tlv *)rsn_ie, true);
1a873342
HM
3736 if (err < 0)
3737 goto exit;
1a873342 3738 }
1a873342 3739 } else {
d96b801f 3740 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
1f170110 3741 brcmf_configure_opensecurity(ifp);
1a873342 3742 }
1a873342 3743
a0f07959 3744 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
1a873342
HM
3745
3746 if (settings->beacon_interval) {
ac24be6f 3747 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 3748 settings->beacon_interval);
1a873342 3749 if (err < 0) {
57d6e91a 3750 brcmf_err("Beacon Interval Set Error, %d\n", err);
1a873342
HM
3751 goto exit;
3752 }
3753 }
3754 if (settings->dtim_period) {
ac24be6f 3755 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 3756 settings->dtim_period);
1a873342 3757 if (err < 0) {
57d6e91a 3758 brcmf_err("DTIM Interval Set Error, %d\n", err);
1a873342
HM
3759 goto exit;
3760 }
3761 }
a0f07959
HM
3762
3763 if (dev_role == NL80211_IFTYPE_AP) {
3764 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3765 if (err < 0) {
3766 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3767 goto exit;
3768 }
2880b868 3769 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
1a873342
HM
3770 }
3771
a0f07959 3772 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342 3773 if (err < 0) {
a0f07959 3774 brcmf_err("SET INFRA error %d\n", err);
1a873342
HM
3775 goto exit;
3776 }
a0f07959
HM
3777 if (dev_role == NL80211_IFTYPE_AP) {
3778 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3779 if (err < 0) {
3780 brcmf_err("setting AP mode failed %d\n", err);
3781 goto exit;
3782 }
3783 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3784 if (err < 0) {
3785 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3786 goto exit;
3787 }
3788
3789 memset(&join_params, 0, sizeof(join_params));
3790 /* join parameters starts with ssid */
3791 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3792 /* create softap */
3793 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3794 &join_params, sizeof(join_params));
3795 if (err < 0) {
3796 brcmf_err("SET SSID error (%d)\n", err);
3797 goto exit;
3798 }
3799 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3800 } else {
3801 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3802 sizeof(ssid_le));
3803 if (err < 0) {
3804 brcmf_err("setting ssid failed %d\n", err);
3805 goto exit;
3806 }
3807 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3808 bss_enable.enable = cpu_to_le32(1);
3809 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3810 sizeof(bss_enable));
3811 if (err < 0) {
3812 brcmf_err("bss_enable config failed %d\n", err);
3813 goto exit;
3814 }
3815
3816 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3817 }
c1179033
AS
3818 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3819 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
3820
3821exit:
3822 if (err)
3823 brcmf_set_mpc(ndev, 1);
3824 return err;
3825}
3826
3827static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3828{
c1179033 3829 struct brcmf_if *ifp = netdev_priv(ndev);
5c33a942 3830 s32 err;
426d0a56 3831 struct brcmf_fil_bss_enable_le bss_enable;
5c33a942 3832 struct brcmf_join_params join_params;
1a873342 3833
d96b801f 3834 brcmf_dbg(TRACE, "Enter\n");
1a873342 3835
426d0a56 3836 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
1a873342
HM
3837 /* Due to most likely deauths outstanding we sleep */
3838 /* first to make sure they get processed by fw. */
3839 msleep(400);
5c33a942
HM
3840
3841 memset(&join_params, 0, sizeof(join_params));
3842 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3843 &join_params, sizeof(join_params));
3844 if (err < 0)
3845 brcmf_err("SET SSID error (%d)\n", err);
128ce3b6 3846 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5c33a942 3847 if (err < 0)
57d6e91a 3848 brcmf_err("BRCMF_C_UP error %d\n", err);
5c33a942
HM
3849 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3850 if (err < 0)
3851 brcmf_err("setting AP mode failed %d\n", err);
3852 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3853 if (err < 0)
3854 brcmf_err("setting INFRA mode failed %d\n", err);
426d0a56
HM
3855 } else {
3856 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3857 bss_enable.enable = cpu_to_le32(0);
3858 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3859 sizeof(bss_enable));
3860 if (err < 0)
3861 brcmf_err("bss_enable config failed %d\n", err);
1a873342 3862 }
426d0a56
HM
3863 brcmf_set_mpc(ndev, 1);
3864 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3865 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3866
1a873342
HM
3867 return err;
3868}
3869
a0f07959
HM
3870static s32
3871brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3872 struct cfg80211_beacon_data *info)
3873{
a0f07959
HM
3874 struct brcmf_if *ifp = netdev_priv(ndev);
3875 s32 err;
3876
3877 brcmf_dbg(TRACE, "Enter\n");
3878
a0f07959
HM
3879 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3880
3881 return err;
3882}
3883
1a873342
HM
3884static int
3885brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3886 u8 *mac)
3887{
a0f07959 3888 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342 3889 struct brcmf_scb_val_le scbval;
0abb5f21 3890 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3891 s32 err;
3892
3893 if (!mac)
3894 return -EFAULT;
3895
d96b801f 3896 brcmf_dbg(TRACE, "Enter %pM\n", mac);
1a873342 3897
a0f07959
HM
3898 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3899 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ce81e317 3900 if (!check_vif_up(ifp->vif))
1a873342
HM
3901 return -EIO;
3902
3903 memcpy(&scbval.ea, mac, ETH_ALEN);
3904 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 3905 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 3906 &scbval, sizeof(scbval));
1a873342 3907 if (err)
57d6e91a 3908 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
7ab6acd0 3909
d96b801f 3910 brcmf_dbg(TRACE, "Exit\n");
1a873342
HM
3911 return err;
3912}
3913
0de8aace
HM
3914
3915static void
3916brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3917 struct wireless_dev *wdev,
3918 u16 frame_type, bool reg)
3919{
3920 struct brcmf_if *ifp = netdev_priv(wdev->netdev);
3921 struct brcmf_cfg80211_vif *vif = ifp->vif;
3922 u16 mgmt_type;
3923
3924 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3925
3926 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3927 if (reg)
3928 vif->mgmt_rx_reg |= BIT(mgmt_type);
3929 else
318a64ce 3930 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
0de8aace
HM
3931}
3932
3933
3934static int
3935brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3936 struct ieee80211_channel *chan, bool offchan,
3937 unsigned int wait, const u8 *buf, size_t len,
3938 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3939{
3940 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3941 const struct ieee80211_mgmt *mgmt;
a0f07959 3942 struct brcmf_if *ifp;
0de8aace
HM
3943 struct brcmf_cfg80211_vif *vif;
3944 s32 err = 0;
3945 s32 ie_offset;
3946 s32 ie_len;
18e2f61d
HM
3947 struct brcmf_fil_action_frame_le *action_frame;
3948 struct brcmf_fil_af_params_le *af_params;
3949 bool ack;
3950 s32 chan_nr;
0de8aace
HM
3951
3952 brcmf_dbg(TRACE, "Enter\n");
3953
3954 *cookie = 0;
3955
3956 mgmt = (const struct ieee80211_mgmt *)buf;
3957
a0f07959
HM
3958 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
3959 brcmf_err("Driver only allows MGMT packet type\n");
3960 return -EPERM;
3961 }
0de8aace 3962
a0f07959
HM
3963 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3964 /* Right now the only reason to get a probe response */
3965 /* is for p2p listen response or for p2p GO from */
3966 /* wpa_supplicant. Unfortunately the probe is send */
3967 /* on primary ndev, while dongle wants it on the p2p */
3968 /* vif. Since this is only reason for a probe */
3969 /* response to be sent, the vif is taken from cfg. */
3970 /* If ever desired to send proberesp for non p2p */
3971 /* response then data should be checked for */
3972 /* "DIRECT-". Note in future supplicant will take */
3973 /* dedicated p2p wdev to do this and then this 'hack'*/
3974 /* is not needed anymore. */
3975 ie_offset = DOT11_MGMT_HDR_LEN +
3976 DOT11_BCN_PRB_FIXED_LEN;
3977 ie_len = len - ie_offset;
3978 ifp = netdev_priv(wdev->netdev);
3979 vif = ifp->vif;
3980 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
0de8aace 3981 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
a0f07959
HM
3982 err = brcmf_vif_set_mgmt_ie(vif,
3983 BRCMF_VNDR_IE_PRBRSP_FLAG,
3984 &buf[ie_offset],
3985 ie_len);
3986 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3987 GFP_KERNEL);
18e2f61d
HM
3988 } else if (ieee80211_is_action(mgmt->frame_control)) {
3989 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
3990 if (af_params == NULL) {
3991 brcmf_err("unable to allocate frame\n");
3992 err = -ENOMEM;
3993 goto exit;
3994 }
3995 action_frame = &af_params->action_frame;
3996 /* Add the packet Id */
3997 action_frame->packet_id = cpu_to_le32(*cookie);
3998 /* Add BSSID */
3999 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4000 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4001 /* Add the length exepted for 802.11 header */
4002 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
4003 /* Add the channel */
4004 chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
4005 af_params->channel = cpu_to_le32(chan_nr);
4006
4007 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4008 le16_to_cpu(action_frame->len));
4009
4010 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
4011 *cookie, le16_to_cpu(action_frame->len),
4012 chan->center_freq);
4013
4014 ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
4015 af_params);
4016
4017 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4018 GFP_KERNEL);
4019 kfree(af_params);
a0f07959
HM
4020 } else {
4021 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4022 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
0de8aace 4023 }
a0f07959 4024
18e2f61d 4025exit:
0de8aace
HM
4026 return err;
4027}
4028
4029
4030static int
4031brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4032 struct wireless_dev *wdev,
4033 u64 cookie)
4034{
4035 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4036 struct brcmf_cfg80211_vif *vif;
4037 int err = 0;
4038
4039 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4040
4041 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4042 if (vif == NULL) {
4043 brcmf_err("No p2p device available for probe response\n");
4044 err = -ENODEV;
4045 goto exit;
4046 }
4047 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4048exit:
4049 return err;
4050}
4051
5b435de0 4052static struct cfg80211_ops wl_cfg80211_ops = {
9f440b7b
AS
4053 .add_virtual_intf = brcmf_cfg80211_add_iface,
4054 .del_virtual_intf = brcmf_cfg80211_del_iface,
5b435de0
AS
4055 .change_virtual_intf = brcmf_cfg80211_change_iface,
4056 .scan = brcmf_cfg80211_scan,
4057 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4058 .join_ibss = brcmf_cfg80211_join_ibss,
4059 .leave_ibss = brcmf_cfg80211_leave_ibss,
4060 .get_station = brcmf_cfg80211_get_station,
4061 .set_tx_power = brcmf_cfg80211_set_tx_power,
4062 .get_tx_power = brcmf_cfg80211_get_tx_power,
4063 .add_key = brcmf_cfg80211_add_key,
4064 .del_key = brcmf_cfg80211_del_key,
4065 .get_key = brcmf_cfg80211_get_key,
4066 .set_default_key = brcmf_cfg80211_config_default_key,
4067 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4068 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
5b435de0
AS
4069 .connect = brcmf_cfg80211_connect,
4070 .disconnect = brcmf_cfg80211_disconnect,
4071 .suspend = brcmf_cfg80211_suspend,
4072 .resume = brcmf_cfg80211_resume,
4073 .set_pmksa = brcmf_cfg80211_set_pmksa,
4074 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 4075 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
4076 .start_ap = brcmf_cfg80211_start_ap,
4077 .stop_ap = brcmf_cfg80211_stop_ap,
a0f07959 4078 .change_beacon = brcmf_cfg80211_change_beacon,
1a873342 4079 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
4080 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4081 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
0de8aace
HM
4082 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4083 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4084 .remain_on_channel = brcmf_p2p_remain_on_channel,
4085 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
cbaa177d
AS
4086#ifdef CONFIG_NL80211_TESTMODE
4087 .testmode_cmd = brcmf_cfg80211_testmode
4088#endif
5b435de0
AS
4089};
4090
9f440b7b 4091static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
5b435de0 4092{
9f440b7b
AS
4093 switch (type) {
4094 case NL80211_IFTYPE_AP_VLAN:
4095 case NL80211_IFTYPE_WDS:
4096 case NL80211_IFTYPE_MONITOR:
4097 case NL80211_IFTYPE_MESH_POINT:
4098 return -ENOTSUPP;
4099 case NL80211_IFTYPE_ADHOC:
4100 return WL_MODE_IBSS;
4101 case NL80211_IFTYPE_STATION:
4102 case NL80211_IFTYPE_P2P_CLIENT:
4103 return WL_MODE_BSS;
4104 case NL80211_IFTYPE_AP:
4105 case NL80211_IFTYPE_P2P_GO:
4106 return WL_MODE_AP;
4107 case NL80211_IFTYPE_P2P_DEVICE:
4108 return WL_MODE_P2P;
4109 case NL80211_IFTYPE_UNSPECIFIED:
5b435de0 4110 default:
9f440b7b 4111 break;
5b435de0
AS
4112 }
4113
9f440b7b 4114 return -EINVAL;
5b435de0
AS
4115}
4116
e5806072
AS
4117static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4118{
e5806072
AS
4119 /* scheduled scan settings */
4120 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4121 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4122 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4123 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
e5806072
AS
4124}
4125
9f440b7b
AS
4126static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4127 {
dded3d53 4128 .max = 2,
9f440b7b
AS
4129 .types = BIT(NL80211_IFTYPE_STATION) |
4130 BIT(NL80211_IFTYPE_ADHOC) |
4131 BIT(NL80211_IFTYPE_AP)
4132 },
dded3d53
HM
4133 {
4134 .max = 1,
4135 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4136 },
9f440b7b
AS
4137 {
4138 .max = 1,
4139 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4140 BIT(NL80211_IFTYPE_P2P_GO)
4141 },
4142};
4143static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4144 {
dded3d53 4145 .max_interfaces = BRCMF_IFACE_MAX_CNT,
9f440b7b
AS
4146 .num_different_channels = 1, /* no multi-channel for now */
4147 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4148 .limits = brcmf_iface_limits
4149 }
4150};
4151
0de8aace
HM
4152static const struct ieee80211_txrx_stypes
4153brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4154 [NL80211_IFTYPE_STATION] = {
4155 .tx = 0xffff,
4156 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4157 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4158 },
4159 [NL80211_IFTYPE_P2P_CLIENT] = {
4160 .tx = 0xffff,
4161 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4162 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4163 },
4164 [NL80211_IFTYPE_P2P_GO] = {
4165 .tx = 0xffff,
4166 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4167 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4168 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4169 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4170 BIT(IEEE80211_STYPE_AUTH >> 4) |
4171 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4172 BIT(IEEE80211_STYPE_ACTION >> 4)
4173 }
4174};
4175
3eacf866 4176static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 4177{
3eacf866 4178 struct wiphy *wiphy;
5b435de0
AS
4179 s32 err = 0;
4180
3eacf866
AS
4181 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4182 if (!wiphy) {
57d6e91a 4183 brcmf_err("Could not allocate wiphy device\n");
3eacf866
AS
4184 return ERR_PTR(-ENOMEM);
4185 }
4186 set_wiphy_dev(wiphy, phydev);
4187 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
9f440b7b 4188 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3eacf866
AS
4189 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4190 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4191 BIT(NL80211_IFTYPE_ADHOC) |
9f440b7b
AS
4192 BIT(NL80211_IFTYPE_AP) |
4193 BIT(NL80211_IFTYPE_P2P_CLIENT) |
dded3d53
HM
4194 BIT(NL80211_IFTYPE_P2P_GO) |
4195 BIT(NL80211_IFTYPE_P2P_DEVICE);
9f440b7b
AS
4196 wiphy->iface_combinations = brcmf_iface_combos;
4197 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
3eacf866
AS
4198 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4199 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
5b435de0
AS
4200 * it as 11a by default.
4201 * This will be updated with
4202 * 11n phy tables in
4203 * "ifconfig up"
4204 * if phy has 11n capability
4205 */
3eacf866
AS
4206 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4207 wiphy->cipher_suites = __wl_cipher_suites;
4208 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
0de8aace 4209 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6eda4e2c 4210 WIPHY_FLAG_OFFCHAN_TX |
0de8aace
HM
4211 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
4212 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4213 wiphy->max_remain_on_channel_duration = 5000;
3eacf866
AS
4214 brcmf_wiphy_pno_params(wiphy);
4215 err = wiphy_register(wiphy);
5b435de0 4216 if (err < 0) {
57d6e91a 4217 brcmf_err("Could not register wiphy device (%d)\n", err);
3eacf866
AS
4218 wiphy_free(wiphy);
4219 return ERR_PTR(err);
5b435de0 4220 }
3eacf866
AS
4221 return wiphy;
4222}
4223
3eacf866 4224struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
9f440b7b
AS
4225 enum nl80211_iftype type,
4226 bool pm_block)
3eacf866
AS
4227{
4228 struct brcmf_cfg80211_vif *vif;
5b435de0 4229
3eacf866
AS
4230 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4231 return ERR_PTR(-ENOSPC);
5b435de0 4232
33a6b157 4233 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
9f440b7b 4234 sizeof(*vif));
3eacf866
AS
4235 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4236 if (!vif)
4237 return ERR_PTR(-ENOMEM);
4238
4239 vif->wdev.wiphy = cfg->wiphy;
9f440b7b 4240 vif->wdev.iftype = type;
5b435de0 4241
9f440b7b 4242 vif->mode = brcmf_nl80211_iftype_to_mode(type);
3eacf866
AS
4243 vif->pm_block = pm_block;
4244 vif->roam_off = -1;
4245
6ac4f4ed
AS
4246 brcmf_init_prof(&vif->profile);
4247
3eacf866
AS
4248 list_add_tail(&vif->list, &cfg->vif_list);
4249 cfg->vif_cnt++;
4250 return vif;
5b435de0
AS
4251}
4252
9f440b7b 4253void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 4254{
3eacf866
AS
4255 struct brcmf_cfg80211_info *cfg;
4256 struct wiphy *wiphy;
5b435de0 4257
3eacf866
AS
4258 wiphy = vif->wdev.wiphy;
4259 cfg = wiphy_priv(wiphy);
4260 list_del(&vif->list);
4261 cfg->vif_cnt--;
4262
4263 kfree(vif);
4264 if (!cfg->vif_cnt) {
4265 wiphy_unregister(wiphy);
4266 wiphy_free(wiphy);
5b435de0 4267 }
5b435de0
AS
4268}
4269
903e0eee 4270static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
5b435de0 4271{
5c36b99a
AS
4272 u32 event = e->event_code;
4273 u32 status = e->status;
5b435de0
AS
4274
4275 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
16886735 4276 brcmf_dbg(CONN, "Processing set ssid\n");
5b435de0
AS
4277 return true;
4278 }
4279
4280 return false;
4281}
4282
903e0eee 4283static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
5b435de0 4284{
5c36b99a
AS
4285 u32 event = e->event_code;
4286 u16 flags = e->flags;
5b435de0
AS
4287
4288 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
16886735 4289 brcmf_dbg(CONN, "Processing link down\n");
5b435de0
AS
4290 return true;
4291 }
4292 return false;
4293}
4294
27a68fe3 4295static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4296 const struct brcmf_event_msg *e)
4297{
5c36b99a
AS
4298 u32 event = e->event_code;
4299 u32 status = e->status;
5b435de0
AS
4300
4301 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
16886735
AS
4302 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4303 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
4304 return true;
4305 }
4306
4307 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
16886735 4308 brcmf_dbg(CONN, "Processing connecting & no network found\n");
5b435de0
AS
4309 return true;
4310 }
4311
4312 return false;
4313}
4314
27a68fe3 4315static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 4316{
27a68fe3 4317 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4318
4319 kfree(conn_info->req_ie);
4320 conn_info->req_ie = NULL;
4321 conn_info->req_ie_len = 0;
4322 kfree(conn_info->resp_ie);
4323 conn_info->resp_ie = NULL;
4324 conn_info->resp_ie_len = 0;
4325}
4326
89286dc9
HM
4327static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4328 struct brcmf_if *ifp)
5b435de0 4329{
c4e382d2 4330 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 4331 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4332 u32 req_len;
4333 u32 resp_len;
4334 s32 err = 0;
4335
27a68fe3 4336 brcmf_clear_assoc_ies(cfg);
5b435de0 4337
ac24be6f
AS
4338 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4339 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0 4340 if (err) {
57d6e91a 4341 brcmf_err("could not get assoc info (%d)\n", err);
5b435de0
AS
4342 return err;
4343 }
c4e382d2 4344 assoc_info =
27a68fe3 4345 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
4346 req_len = le32_to_cpu(assoc_info->req_len);
4347 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 4348 if (req_len) {
ac24be6f 4349 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
4350 cfg->extra_buf,
4351 WL_ASSOC_INFO_MAX);
5b435de0 4352 if (err) {
57d6e91a 4353 brcmf_err("could not get assoc req (%d)\n", err);
5b435de0
AS
4354 return err;
4355 }
4356 conn_info->req_ie_len = req_len;
4357 conn_info->req_ie =
27a68fe3 4358 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
4359 GFP_KERNEL);
4360 } else {
4361 conn_info->req_ie_len = 0;
4362 conn_info->req_ie = NULL;
4363 }
4364 if (resp_len) {
ac24be6f 4365 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
4366 cfg->extra_buf,
4367 WL_ASSOC_INFO_MAX);
5b435de0 4368 if (err) {
57d6e91a 4369 brcmf_err("could not get assoc resp (%d)\n", err);
5b435de0
AS
4370 return err;
4371 }
4372 conn_info->resp_ie_len = resp_len;
4373 conn_info->resp_ie =
27a68fe3 4374 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
4375 GFP_KERNEL);
4376 } else {
4377 conn_info->resp_ie_len = 0;
4378 conn_info->resp_ie = NULL;
4379 }
16886735
AS
4380 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4381 conn_info->req_ie_len, conn_info->resp_ie_len);
5b435de0
AS
4382
4383 return err;
4384}
4385
4386static s32
27a68fe3 4387brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4388 struct net_device *ndev,
4389 const struct brcmf_event_msg *e)
4390{
c1179033
AS
4391 struct brcmf_if *ifp = netdev_priv(ndev);
4392 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
4393 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4394 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 4395 struct ieee80211_channel *notify_channel = NULL;
5b435de0 4396 struct ieee80211_supported_band *band;
a180b83b 4397 struct brcmf_bss_info_le *bi;
5b435de0
AS
4398 u32 freq;
4399 s32 err = 0;
4400 u32 target_channel;
a180b83b 4401 u8 *buf;
5b435de0 4402
d96b801f 4403 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4404
89286dc9 4405 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4406 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9 4407 brcmf_update_bss_info(cfg, ifp);
5b435de0 4408
a180b83b
FL
4409 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4410 if (buf == NULL) {
4411 err = -ENOMEM;
4412 goto done;
4413 }
4414
4415 /* data sent to dongle has to be little endian */
4416 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4417 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4418 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4419
4420 if (err)
4421 goto done;
5b435de0 4422
a180b83b
FL
4423 bi = (struct brcmf_bss_info_le *)(buf + 4);
4424 target_channel = bi->ctl_ch ? bi->ctl_ch :
4425 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
5b435de0
AS
4426
4427 if (target_channel <= CH_MAX_2G_CHANNEL)
4428 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4429 else
4430 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4431
4432 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4433 notify_channel = ieee80211_get_channel(wiphy, freq);
4434
a180b83b
FL
4435done:
4436 kfree(buf);
06bb123e 4437 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4438 conn_info->req_ie, conn_info->req_ie_len,
4439 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16886735 4440 brcmf_dbg(CONN, "Report roaming result\n");
5b435de0 4441
c1179033 4442 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
d96b801f 4443 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4444 return err;
4445}
4446
4447static s32
27a68fe3 4448brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4449 struct net_device *ndev, const struct brcmf_event_msg *e,
4450 bool completed)
4451{
c1179033
AS
4452 struct brcmf_if *ifp = netdev_priv(ndev);
4453 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4454 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4455 s32 err = 0;
4456
d96b801f 4457 brcmf_dbg(TRACE, "Enter\n");
5b435de0 4458
c1179033
AS
4459 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4460 &ifp->vif->sme_state)) {
5b435de0 4461 if (completed) {
89286dc9 4462 brcmf_get_assoc_ies(cfg, ifp);
6c8c4f72 4463 memcpy(profile->bssid, e->addr, ETH_ALEN);
89286dc9
HM
4464 brcmf_update_bss_info(cfg, ifp);
4465 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4466 &ifp->vif->sme_state);
5b435de0
AS
4467 }
4468 cfg80211_connect_result(ndev,
06bb123e 4469 (u8 *)profile->bssid,
5b435de0
AS
4470 conn_info->req_ie,
4471 conn_info->req_ie_len,
4472 conn_info->resp_ie,
4473 conn_info->resp_ie_len,
4474 completed ? WLAN_STATUS_SUCCESS :
4475 WLAN_STATUS_AUTH_TIMEOUT,
4476 GFP_KERNEL);
16886735
AS
4477 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4478 completed ? "succeeded" : "failed");
5b435de0 4479 }
d96b801f 4480 brcmf_dbg(TRACE, "Exit\n");
5b435de0
AS
4481 return err;
4482}
4483
4484static s32
27a68fe3 4485brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4486 struct net_device *ndev,
4487 const struct brcmf_event_msg *e, void *data)
4488{
7ee29602 4489 static int generation;
5c36b99a
AS
4490 u32 event = e->event_code;
4491 u32 reason = e->reason;
1a873342
HM
4492 struct station_info sinfo;
4493
16886735 4494 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
5f4f9f11
AS
4495 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4496 ndev != cfg_to_ndev(cfg)) {
4497 brcmf_dbg(CONN, "AP mode link down\n");
4498 complete(&cfg->vif_disabled);
4499 return 0;
4500 }
1a873342 4501
1a873342 4502 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
7ee29602
HM
4503 (reason == BRCMF_E_STATUS_SUCCESS)) {
4504 memset(&sinfo, 0, sizeof(sinfo));
1a873342
HM
4505 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4506 if (!data) {
57d6e91a 4507 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
1a873342
HM
4508 return -EINVAL;
4509 }
4510 sinfo.assoc_req_ies = data;
7ee29602 4511 sinfo.assoc_req_ies_len = e->datalen;
1a873342
HM
4512 generation++;
4513 sinfo.generation = generation;
7ee29602 4514 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
1a873342
HM
4515 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4516 (event == BRCMF_E_DEAUTH_IND) ||
4517 (event == BRCMF_E_DEAUTH)) {
7ee29602 4518 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
1a873342 4519 }
7ee29602 4520 return 0;
1a873342
HM
4521}
4522
5b435de0 4523static s32
1993732e 4524brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
4525 const struct brcmf_event_msg *e, void *data)
4526{
1993732e
AS
4527 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4528 struct net_device *ndev = ifp->ndev;
c1179033 4529 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4530 s32 err = 0;
4531
128ce3b6 4532 if (ifp->vif->mode == WL_MODE_AP) {
27a68fe3 4533 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
903e0eee 4534 } else if (brcmf_is_linkup(e)) {
16886735 4535 brcmf_dbg(CONN, "Linkup\n");
128ce3b6 4536 if (brcmf_is_ibssmode(ifp->vif)) {
6c8c4f72 4537 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4538 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4539 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4540 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4541 &ifp->vif->sme_state);
4542 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4543 &ifp->vif->sme_state);
5b435de0 4544 } else
27a68fe3 4545 brcmf_bss_connect_done(cfg, ndev, e, true);
903e0eee 4546 } else if (brcmf_is_linkdown(e)) {
16886735 4547 brcmf_dbg(CONN, "Linkdown\n");
128ce3b6 4548 if (!brcmf_is_ibssmode(ifp->vif)) {
27a68fe3 4549 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033 4550 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
903e0eee 4551 &ifp->vif->sme_state))
5b435de0 4552 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4553 GFP_KERNEL);
5b435de0 4554 }
903e0eee 4555 brcmf_link_down(ifp->vif);
6ac4f4ed 4556 brcmf_init_prof(ndev_to_prof(ndev));
5f4f9f11
AS
4557 if (ndev != cfg_to_ndev(cfg))
4558 complete(&cfg->vif_disabled);
27a68fe3 4559 } else if (brcmf_is_nonetwork(cfg, e)) {
128ce3b6 4560 if (brcmf_is_ibssmode(ifp->vif))
c1179033
AS
4561 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4562 &ifp->vif->sme_state);
5b435de0 4563 else
27a68fe3 4564 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4565 }
4566
4567 return err;
4568}
4569
4570static s32
1993732e 4571brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
4572 const struct brcmf_event_msg *e, void *data)
4573{
1993732e 4574 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0 4575 s32 err = 0;
5c36b99a
AS
4576 u32 event = e->event_code;
4577 u32 status = e->status;
5b435de0
AS
4578
4579 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4580 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 4581 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 4582 else
1993732e 4583 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
4584 }
4585
4586 return err;
4587}
4588
4589static s32
1993732e 4590brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
4591 const struct brcmf_event_msg *e, void *data)
4592{
5c36b99a 4593 u16 flags = e->flags;
5b435de0
AS
4594 enum nl80211_key_type key_type;
4595
4596 if (flags & BRCMF_EVENT_MSG_GROUP)
4597 key_type = NL80211_KEYTYPE_GROUP;
4598 else
4599 key_type = NL80211_KEYTYPE_PAIRWISE;
4600
1993732e 4601 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
4602 NULL, GFP_KERNEL);
4603
4604 return 0;
4605}
4606
d3c0b633
AS
4607static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4608 const struct brcmf_event_msg *e, void *data)
4609{
4610 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4611 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4612 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4613 struct brcmf_cfg80211_vif *vif;
4614
4615 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4616 ifevent->action, ifevent->flags, ifevent->ifidx,
4617 ifevent->bssidx);
4618
d3c0b633
AS
4619 mutex_lock(&event->vif_event_lock);
4620 event->action = ifevent->action;
4621 vif = event->vif;
4622
4623 switch (ifevent->action) {
4624 case BRCMF_E_IF_ADD:
4625 /* waiting process may have timed out */
dc4a787c
WY
4626 if (!cfg->vif_event.vif) {
4627 mutex_unlock(&event->vif_event_lock);
d3c0b633 4628 return -EBADF;
dc4a787c 4629 }
d3c0b633
AS
4630
4631 ifp->vif = vif;
4632 vif->ifp = ifp;
4633 vif->wdev.netdev = ifp->ndev;
4634 ifp->ndev->ieee80211_ptr = &vif->wdev;
4635 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4636 mutex_unlock(&event->vif_event_lock);
4637 wake_up(&event->vif_wq);
4b3a89de 4638 return 0;
d3c0b633
AS
4639
4640 case BRCMF_E_IF_DEL:
4641 ifp->vif = NULL;
d3c0b633
AS
4642 mutex_unlock(&event->vif_event_lock);
4643 /* event may not be upon user request */
4644 if (brcmf_cfg80211_vif_event_armed(cfg))
4645 wake_up(&event->vif_wq);
4646 return 0;
4647
7a5c1f64
HM
4648 case BRCMF_E_IF_CHANGE:
4649 mutex_unlock(&event->vif_event_lock);
4650 wake_up(&event->vif_wq);
4651 return 0;
4652
d3c0b633
AS
4653 default:
4654 mutex_unlock(&event->vif_event_lock);
4655 break;
4656 }
4657 return -EINVAL;
4658}
4659
5b435de0
AS
4660static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4661{
5b435de0
AS
4662 conf->frag_threshold = (u32)-1;
4663 conf->rts_threshold = (u32)-1;
4664 conf->retry_short = (u32)-1;
4665 conf->retry_long = (u32)-1;
4666 conf->tx_power = -1;
4667}
4668
5c36b99a 4669static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 4670{
5c36b99a
AS
4671 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4672 brcmf_notify_connect_status);
4673 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4674 brcmf_notify_connect_status);
4675 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4676 brcmf_notify_connect_status);
4677 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4678 brcmf_notify_connect_status);
4679 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4680 brcmf_notify_connect_status);
4681 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4682 brcmf_notify_connect_status);
4683 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4684 brcmf_notify_roaming_status);
4685 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4686 brcmf_notify_mic_status);
4687 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4688 brcmf_notify_connect_status);
4689 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4690 brcmf_notify_sched_scan_results);
d3c0b633
AS
4691 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4692 brcmf_notify_vif_event);
0de8aace 4693 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
6eda4e2c 4694 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
0de8aace
HM
4695 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4696 brcmf_p2p_notify_listen_complete);
e6da3400
HM
4697 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4698 brcmf_p2p_notify_action_frame_rx);
18e2f61d
HM
4699 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4700 brcmf_p2p_notify_action_tx_complete);
6eda4e2c
HM
4701 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4702 brcmf_p2p_notify_action_tx_complete);
5b435de0
AS
4703}
4704
27a68fe3
AS
4705static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4706{
27a68fe3
AS
4707 kfree(cfg->conf);
4708 cfg->conf = NULL;
27a68fe3
AS
4709 kfree(cfg->escan_ioctl_buf);
4710 cfg->escan_ioctl_buf = NULL;
27a68fe3
AS
4711 kfree(cfg->extra_buf);
4712 cfg->extra_buf = NULL;
27a68fe3
AS
4713 kfree(cfg->pmk_list);
4714 cfg->pmk_list = NULL;
27a68fe3
AS
4715}
4716
4717static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4718{
27a68fe3
AS
4719 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4720 if (!cfg->conf)
5b435de0 4721 goto init_priv_mem_out;
27a68fe3
AS
4722 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4723 if (!cfg->escan_ioctl_buf)
e756af5b 4724 goto init_priv_mem_out;
27a68fe3
AS
4725 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4726 if (!cfg->extra_buf)
5b435de0 4727 goto init_priv_mem_out;
27a68fe3
AS
4728 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4729 if (!cfg->pmk_list)
5b435de0
AS
4730 goto init_priv_mem_out;
4731
4732 return 0;
4733
4734init_priv_mem_out:
27a68fe3 4735 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4736
4737 return -ENOMEM;
4738}
4739
27a68fe3 4740static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4741{
4742 s32 err = 0;
4743
27a68fe3
AS
4744 cfg->scan_request = NULL;
4745 cfg->pwr_save = true;
27a68fe3 4746 cfg->roam_on = true; /* roam on & off switch.
5b435de0 4747 we enable roam per default */
27a68fe3 4748 cfg->active_scan = true; /* we do active scan for
5b435de0 4749 specific scan per default */
27a68fe3 4750 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 4751 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4752 if (err)
4753 return err;
5c36b99a 4754 brcmf_register_event_handlers(cfg);
27a68fe3 4755 mutex_init(&cfg->usr_sync);
27a68fe3
AS
4756 brcmf_init_escan(cfg);
4757 brcmf_init_conf(cfg->conf);
5f4f9f11 4758 init_completion(&cfg->vif_disabled);
5b435de0
AS
4759 return err;
4760}
4761
27a68fe3 4762static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4763{
27a68fe3 4764 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
4765 brcmf_abort_scanning(cfg);
4766 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4767}
4768
d3c0b633
AS
4769static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4770{
4771 init_waitqueue_head(&event->vif_wq);
d3c0b633
AS
4772 mutex_init(&event->vif_event_lock);
4773}
4774
d9cb2596
AS
4775struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4776 struct device *busdev)
5b435de0 4777{
1ed9baf0 4778 struct net_device *ndev = drvr->iflist[0]->ndev;
27a68fe3 4779 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4780 struct wiphy *wiphy;
4781 struct brcmf_cfg80211_vif *vif;
4782 struct brcmf_if *ifp;
5b435de0
AS
4783 s32 err = 0;
4784
4785 if (!ndev) {
57d6e91a 4786 brcmf_err("ndev is invalid\n");
5b435de0
AS
4787 return NULL;
4788 }
5b435de0 4789
3eacf866
AS
4790 ifp = netdev_priv(ndev);
4791 wiphy = brcmf_setup_wiphy(busdev);
4792 if (IS_ERR(wiphy))
5b435de0 4793 return NULL;
5b435de0 4794
3eacf866
AS
4795 cfg = wiphy_priv(wiphy);
4796 cfg->wiphy = wiphy;
27a68fe3 4797 cfg->pub = drvr;
d3c0b633 4798 init_vif_event(&cfg->vif_event);
3eacf866
AS
4799 INIT_LIST_HEAD(&cfg->vif_list);
4800
d3c0b633 4801 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
3eacf866
AS
4802 if (IS_ERR(vif)) {
4803 wiphy_free(wiphy);
4804 return NULL;
4805 }
4806
d3c0b633
AS
4807 vif->ifp = ifp;
4808 vif->wdev.netdev = ndev;
4809 ndev->ieee80211_ptr = &vif->wdev;
4810 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4811
27a68fe3 4812 err = wl_init_priv(cfg);
5b435de0 4813 if (err) {
57d6e91a 4814 brcmf_err("Failed to init iwm_priv (%d)\n", err);
5b435de0
AS
4815 goto cfg80211_attach_out;
4816 }
3eacf866 4817 ifp->vif = vif;
2fde59d9
HM
4818
4819 err = brcmf_p2p_attach(cfg);
4820 if (err) {
4821 brcmf_err("P2P initilisation failed (%d)\n", err);
4822 goto cfg80211_p2p_attach_out;
4823 }
4824
27a68fe3 4825 return cfg;
5b435de0 4826
2fde59d9
HM
4827cfg80211_p2p_attach_out:
4828 wl_deinit_priv(cfg);
4829
5b435de0 4830cfg80211_attach_out:
3eacf866 4831 brcmf_free_vif(vif);
2880b868 4832 wiphy_free(wiphy);
5b435de0
AS
4833 return NULL;
4834}
4835
27a68fe3 4836void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 4837{
3eacf866
AS
4838 struct brcmf_cfg80211_vif *vif;
4839 struct brcmf_cfg80211_vif *tmp;
4840
27a68fe3 4841 wl_deinit_priv(cfg);
3eacf866
AS
4842 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4843 brcmf_free_vif(vif);
4844 }
5b435de0
AS
4845}
4846
5b435de0 4847static s32
40a23296 4848brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
5b435de0 4849{
5b435de0 4850 s32 err = 0;
f588bc0c
AS
4851 __le32 roamtrigger[2];
4852 __le32 roam_delta[2];
5b435de0
AS
4853
4854 /*
4855 * Setup timeout if Beacons are lost and roam is
4856 * off to report link down
4857 */
4858 if (roamvar) {
ac24be6f 4859 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0 4860 if (err) {
57d6e91a 4861 brcmf_err("bcn_timeout error (%d)\n", err);
5b435de0
AS
4862 goto dongle_rom_out;
4863 }
4864 }
4865
4866 /*
4867 * Enable/Disable built-in roaming to allow supplicant
4868 * to take care of roaming
4869 */
647c9ae0 4870 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 4871 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0 4872 if (err) {
57d6e91a 4873 brcmf_err("roam_off error (%d)\n", err);
5b435de0
AS
4874 goto dongle_rom_out;
4875 }
4876
f588bc0c
AS
4877 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4878 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4879 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 4880 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0 4881 if (err) {
57d6e91a 4882 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5b435de0
AS
4883 goto dongle_rom_out;
4884 }
4885
f588bc0c
AS
4886 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4887 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4888 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 4889 (void *)roam_delta, sizeof(roam_delta));
5b435de0 4890 if (err) {
57d6e91a 4891 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
5b435de0
AS
4892 goto dongle_rom_out;
4893 }
4894
4895dongle_rom_out:
4896 return err;
4897}
4898
4899static s32
40a23296 4900brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
c68cdc0f 4901 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0
AS
4902{
4903 s32 err = 0;
4904
ac24be6f 4905 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 4906 scan_assoc_time);
5b435de0
AS
4907 if (err) {
4908 if (err == -EOPNOTSUPP)
647c9ae0 4909 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
5b435de0 4910 else
57d6e91a 4911 brcmf_err("Scan assoc time error (%d)\n", err);
5b435de0
AS
4912 goto dongle_scantime_out;
4913 }
ac24be6f 4914 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 4915 scan_unassoc_time);
5b435de0
AS
4916 if (err) {
4917 if (err == -EOPNOTSUPP)
647c9ae0 4918 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
5b435de0 4919 else
57d6e91a 4920 brcmf_err("Scan unassoc time error (%d)\n", err);
5b435de0
AS
4921 goto dongle_scantime_out;
4922 }
4923
ac24be6f 4924 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 4925 scan_passive_time);
5b435de0
AS
4926 if (err) {
4927 if (err == -EOPNOTSUPP)
647c9ae0 4928 brcmf_dbg(INFO, "Scan passive time is not supported\n");
5b435de0 4929 else
57d6e91a 4930 brcmf_err("Scan passive time error (%d)\n", err);
5b435de0
AS
4931 goto dongle_scantime_out;
4932 }
4933
4934dongle_scantime_out:
4935 return err;
4936}
4937
27a68fe3 4938static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 4939{
ac24be6f 4940 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
4941 struct wiphy *wiphy;
4942 s32 phy_list;
4943 s8 phy;
4944 s32 err = 0;
4945
b87e2c48 4946 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
81f5dcb8 4947 &phy_list, sizeof(phy_list));
5b435de0 4948 if (err) {
57d6e91a 4949 brcmf_err("error (%d)\n", err);
5b435de0
AS
4950 return err;
4951 }
4952
3ba81376 4953 phy = ((char *)&phy_list)[0];
647c9ae0 4954 brcmf_dbg(INFO, "%c phy\n", phy);
5b435de0 4955 if (phy == 'n' || phy == 'a') {
27a68fe3 4956 wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
4957 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4958 }
4959
4960 return err;
4961}
4962
27a68fe3 4963static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 4964{
27a68fe3 4965 return wl_update_wiphybands(cfg);
5b435de0
AS
4966}
4967
27a68fe3 4968static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4969{
4970 struct net_device *ndev;
4971 struct wireless_dev *wdev;
40a23296 4972 struct brcmf_if *ifp;
5b435de0
AS
4973 s32 power_mode;
4974 s32 err = 0;
4975
27a68fe3 4976 if (cfg->dongle_up)
5b435de0
AS
4977 return err;
4978
27a68fe3 4979 ndev = cfg_to_ndev(cfg);
5b435de0 4980 wdev = ndev->ieee80211_ptr;
40a23296
HM
4981 ifp = netdev_priv(ndev);
4982
4983 /* make sure RF is ready for work */
4984 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5b435de0 4985
40a23296
HM
4986 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4987 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5b435de0 4988
27a68fe3 4989 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
40a23296 4990 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5b435de0
AS
4991 if (err)
4992 goto default_conf_out;
647c9ae0
AS
4993 brcmf_dbg(INFO, "power save set to %s\n",
4994 (power_mode ? "enabled" : "disabled"));
5b435de0 4995
40a23296 4996 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
5b435de0
AS
4997 if (err)
4998 goto default_conf_out;
5dd161ff
FL
4999 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5000 NULL, NULL);
40a23296 5001 if (err)
5b435de0 5002 goto default_conf_out;
27a68fe3 5003 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
5004 if (err)
5005 goto default_conf_out;
5006
27a68fe3 5007 cfg->dongle_up = true;
40a23296 5008default_conf_out:
5b435de0
AS
5009
5010 return err;
5011
5012}
5013
bdf5ff51 5014static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5b435de0 5015{
c1179033 5016 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5017
bdf5ff51 5018 return brcmf_config_dongle(ifp->drvr->config);
5b435de0
AS
5019}
5020
bdf5ff51 5021static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5b435de0 5022{
bdf5ff51 5023 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
c1179033 5024
5b435de0
AS
5025 /*
5026 * While going down, if associated with AP disassociate
5027 * from AP to save power
5028 */
903e0eee
AS
5029 if (check_vif_up(ifp->vif)) {
5030 brcmf_link_down(ifp->vif);
5b435de0
AS
5031
5032 /* Make sure WPA_Supplicant receives all the event
5033 generated due to DISASSOC call to the fw to keep
5034 the state fw and WPA_Supplicant state consistent
5035 */
5036 brcmf_delay(500);
5037 }
5038
27a68fe3 5039 brcmf_abort_scanning(cfg);
c1179033 5040 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 5041
5b435de0
AS
5042 return 0;
5043}
5044
bdf5ff51 5045s32 brcmf_cfg80211_up(struct net_device *ndev)
5b435de0 5046{
bdf5ff51
AS
5047 struct brcmf_if *ifp = netdev_priv(ndev);
5048 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5049 s32 err = 0;
5050
27a68fe3 5051 mutex_lock(&cfg->usr_sync);
bdf5ff51 5052 err = __brcmf_cfg80211_up(ifp);
27a68fe3 5053 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5054
5055 return err;
5056}
5057
bdf5ff51 5058s32 brcmf_cfg80211_down(struct net_device *ndev)
5b435de0 5059{
bdf5ff51
AS
5060 struct brcmf_if *ifp = netdev_priv(ndev);
5061 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0
AS
5062 s32 err = 0;
5063
27a68fe3 5064 mutex_lock(&cfg->usr_sync);
bdf5ff51 5065 err = __brcmf_cfg80211_down(ifp);
27a68fe3 5066 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
5067
5068 return err;
5069}
5070
9f440b7b
AS
5071u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5072{
5073 struct brcmf_cfg80211_vif *vif;
5074 bool result = 0;
5075
5076 list_for_each_entry(vif, &cfg->vif_list, list) {
5077 if (test_bit(state, &vif->sme_state))
5078 result++;
5079 }
5080 return result;
5081}
d3c0b633
AS
5082
5083static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5084 u8 action)
5085{
5086 u8 evt_action;
5087
5088 mutex_lock(&event->vif_event_lock);
5089 evt_action = event->action;
5090 mutex_unlock(&event->vif_event_lock);
5091 return evt_action == action;
5092}
5093
5094void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5095 struct brcmf_cfg80211_vif *vif)
5096{
5097 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5098
5099 mutex_lock(&event->vif_event_lock);
5100 event->vif = vif;
5101 event->action = 0;
5102 mutex_unlock(&event->vif_event_lock);
5103}
5104
5105bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5106{
5107 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5108 bool armed;
5109
5110 mutex_lock(&event->vif_event_lock);
5111 armed = event->vif != NULL;
5112 mutex_unlock(&event->vif_event_lock);
5113
5114 return armed;
5115}
5116int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5117 u8 action, ulong timeout)
5118{
5119 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5120
5121 return wait_event_timeout(event->vif_wq,
5122 vif_event_equals(event, action), timeout);
5123}
5124
This page took 0.523991 seconds and 5 git commands to generate.