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