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