brcmfmac: change parameter in brcmf_add_if() function
[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 2472
5c36b99a 2473 status = e->status;
e756af5b 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 2553{
5c36b99a
AS
2554 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2555 brcmf_cfg80211_escan_handler);
f0799895
HM
2556 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2557 /* Init scan_timeout timer */
2558 init_timer(&cfg->escan_timeout);
2559 cfg->escan_timeout.data = (unsigned long) cfg;
2560 cfg->escan_timeout.function = brcmf_escan_timeout;
2561 INIT_WORK(&cfg->escan_timeout_work,
2562 brcmf_cfg80211_escan_timeout_worker);
e756af5b
HM
2563}
2564
5addc0de 2565static __always_inline void brcmf_delay(u32 ms)
5b435de0
AS
2566{
2567 if (ms < 1000 / HZ) {
2568 cond_resched();
2569 mdelay(ms);
2570 } else {
2571 msleep(ms);
2572 }
2573}
2574
2575static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2576{
5b435de0
AS
2577 WL_TRACE("Enter\n");
2578
5b435de0
AS
2579 return 0;
2580}
2581
2582static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2583 struct cfg80211_wowlan *wow)
2584{
27a68fe3
AS
2585 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2586 struct net_device *ndev = cfg_to_ndev(cfg);
7d641072 2587 struct brcmf_cfg80211_vif *vif;
5b435de0
AS
2588
2589 WL_TRACE("Enter\n");
2590
2591 /*
7d641072
AS
2592 * if the primary net_device is not READY there is nothing
2593 * we can do but pray resume goes smoothly.
5b435de0 2594 */
7d641072
AS
2595 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2596 if (!check_vif_up(vif))
2597 goto exit;
5b435de0 2598
7d641072
AS
2599 list_for_each_entry(vif, &cfg->vif_list, list) {
2600 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2601 continue;
5b435de0 2602 /*
7d641072
AS
2603 * While going to suspend if associated with AP disassociate
2604 * from AP to save power while system is in suspended state
5b435de0 2605 */
7d641072
AS
2606 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
2607 test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
2608 WL_INFO("Disassociating from AP before suspend\n");
2609 brcmf_link_down(cfg);
2610
2611 /* Make sure WPA_Supplicant receives all the event
2612 * generated due to DISASSOC call to the fw to keep
2613 * the state fw and WPA_Supplicant state consistent
2614 */
2615 brcmf_delay(500);
2616 }
5b435de0
AS
2617 }
2618
7d641072
AS
2619 /* end any scanning */
2620 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
27a68fe3 2621 brcmf_abort_scanning(cfg);
5b435de0
AS
2622
2623 /* Turn off watchdog timer */
7d641072 2624 brcmf_set_mpc(ndev, 1);
5b435de0 2625
7d641072 2626exit:
5b435de0 2627 WL_TRACE("Exit\n");
7d641072
AS
2628 /* clear any scanning activity */
2629 cfg->scan_status = 0;
5b435de0
AS
2630 return 0;
2631}
2632
5b435de0
AS
2633static __used s32
2634brcmf_update_pmklist(struct net_device *ndev,
2635 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2636{
2637 int i, j;
40c8e95a 2638 int pmkid_len;
5b435de0 2639
40c8e95a
AS
2640 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2641
2642 WL_CONN("No of elements %d\n", pmkid_len);
2643 for (i = 0; i < pmkid_len; i++) {
5b435de0
AS
2644 WL_CONN("PMKID[%d]: %pM =\n", i,
2645 &pmk_list->pmkids.pmkid[i].BSSID);
2646 for (j = 0; j < WLAN_PMKID_LEN; j++)
2647 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
2648 }
2649
2650 if (!err)
ac24be6f
AS
2651 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2652 (char *)pmk_list, sizeof(*pmk_list));
5b435de0
AS
2653
2654 return err;
2655}
2656
2657static s32
2658brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2659 struct cfg80211_pmksa *pmksa)
2660{
27a68fe3 2661 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2662 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2663 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
5b435de0
AS
2664 s32 err = 0;
2665 int i;
40c8e95a 2666 int pmkid_len;
5b435de0
AS
2667
2668 WL_TRACE("Enter\n");
ce81e317 2669 if (!check_vif_up(ifp->vif))
5b435de0
AS
2670 return -EIO;
2671
40c8e95a
AS
2672 pmkid_len = le32_to_cpu(pmkids->npmkid);
2673 for (i = 0; i < pmkid_len; i++)
5b435de0
AS
2674 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2675 break;
2676 if (i < WL_NUM_PMKIDS_MAX) {
2677 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2678 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
40c8e95a
AS
2679 if (i == pmkid_len) {
2680 pmkid_len++;
2681 pmkids->npmkid = cpu_to_le32(pmkid_len);
2682 }
5b435de0
AS
2683 } else
2684 err = -EINVAL;
2685
2686 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
40c8e95a 2687 pmkids->pmkid[pmkid_len].BSSID);
5b435de0 2688 for (i = 0; i < WLAN_PMKID_LEN; i++)
40c8e95a 2689 WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
5b435de0 2690
27a68fe3 2691 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
2692
2693 WL_TRACE("Exit\n");
2694 return err;
2695}
2696
2697static s32
2698brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2699 struct cfg80211_pmksa *pmksa)
2700{
27a68fe3 2701 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2702 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2703 struct pmkid_list pmkid;
2704 s32 err = 0;
40c8e95a 2705 int i, pmkid_len;
5b435de0
AS
2706
2707 WL_TRACE("Enter\n");
ce81e317 2708 if (!check_vif_up(ifp->vif))
5b435de0
AS
2709 return -EIO;
2710
2711 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2712 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2713
2714 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2715 &pmkid.pmkid[0].BSSID);
2716 for (i = 0; i < WLAN_PMKID_LEN; i++)
2717 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
2718
27a68fe3 2719 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
40c8e95a 2720 for (i = 0; i < pmkid_len; i++)
5b435de0 2721 if (!memcmp
27a68fe3 2722 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5b435de0
AS
2723 ETH_ALEN))
2724 break;
2725
40c8e95a
AS
2726 if ((pmkid_len > 0)
2727 && (i < pmkid_len)) {
27a68fe3 2728 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
5b435de0 2729 sizeof(struct pmkid));
40c8e95a 2730 for (; i < (pmkid_len - 1); i++) {
27a68fe3
AS
2731 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2732 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5b435de0 2733 ETH_ALEN);
27a68fe3
AS
2734 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2735 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5b435de0
AS
2736 WLAN_PMKID_LEN);
2737 }
27a68fe3 2738 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
5b435de0
AS
2739 } else
2740 err = -EINVAL;
2741
27a68fe3 2742 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
2743
2744 WL_TRACE("Exit\n");
2745 return err;
2746
2747}
2748
2749static s32
2750brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2751{
27a68fe3 2752 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
0abb5f21 2753 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
2754 s32 err = 0;
2755
2756 WL_TRACE("Enter\n");
ce81e317 2757 if (!check_vif_up(ifp->vif))
5b435de0
AS
2758 return -EIO;
2759
27a68fe3
AS
2760 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2761 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
5b435de0
AS
2762
2763 WL_TRACE("Exit\n");
2764 return err;
2765
2766}
2767
e5806072
AS
2768/*
2769 * PFN result doesn't have all the info which are
2770 * required by the supplicant
2771 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2772 * via wl_inform_single_bss in the required format. Escan does require the
2773 * scan request in the form of cfg80211_scan_request. For timebeing, create
2774 * cfg80211_scan_request one out of the received PNO event.
2775 */
2776static s32
1993732e 2777brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
e5806072
AS
2778 const struct brcmf_event_msg *e, void *data)
2779{
1993732e
AS
2780 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2781 struct net_device *ndev = ifp->ndev;
e5806072
AS
2782 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2783 struct cfg80211_scan_request *request = NULL;
2784 struct cfg80211_ssid *ssid = NULL;
2785 struct ieee80211_channel *channel = NULL;
27a68fe3 2786 struct wiphy *wiphy = cfg_to_wiphy(cfg);
e5806072
AS
2787 int err = 0;
2788 int channel_req = 0;
2789 int band = 0;
2790 struct brcmf_pno_scanresults_le *pfn_result;
2791 u32 result_count;
2792 u32 status;
2793
2794 WL_SCAN("Enter\n");
2795
5c36b99a 2796 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
e5806072
AS
2797 WL_SCAN("PFN NET LOST event. Do Nothing\n");
2798 return 0;
2799 }
2800
2801 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2802 result_count = le32_to_cpu(pfn_result->count);
2803 status = le32_to_cpu(pfn_result->status);
2804
2805 /*
2806 * PFN event is limited to fit 512 bytes so we may get
2807 * multiple NET_FOUND events. For now place a warning here.
2808 */
2809 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
2810 WL_SCAN("PFN NET FOUND event. count: %d\n", result_count);
2811 if (result_count > 0) {
2812 int i;
2813
2814 request = kzalloc(sizeof(*request), GFP_KERNEL);
58901d18
DC
2815 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2816 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
e5806072
AS
2817 if (!request || !ssid || !channel) {
2818 err = -ENOMEM;
2819 goto out_err;
2820 }
2821
2822 request->wiphy = wiphy;
2823 data += sizeof(struct brcmf_pno_scanresults_le);
2824 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2825
2826 for (i = 0; i < result_count; i++) {
2827 netinfo = &netinfo_start[i];
2828 if (!netinfo) {
2829 WL_ERR("Invalid netinfo ptr. index: %d\n", i);
2830 err = -EINVAL;
2831 goto out_err;
2832 }
2833
2834 WL_SCAN("SSID:%s Channel:%d\n",
2835 netinfo->SSID, netinfo->channel);
2836 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2837 ssid[i].ssid_len = netinfo->SSID_len;
2838 request->n_ssids++;
2839
2840 channel_req = netinfo->channel;
2841 if (channel_req <= CH_MAX_2G_CHANNEL)
2842 band = NL80211_BAND_2GHZ;
2843 else
2844 band = NL80211_BAND_5GHZ;
2845 channel[i].center_freq =
2846 ieee80211_channel_to_frequency(channel_req,
2847 band);
2848 channel[i].band = band;
2849 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2850 request->channels[i] = &channel[i];
2851 request->n_channels++;
2852 }
2853
2854 /* assign parsed ssid array */
2855 if (request->n_ssids)
2856 request->ssids = &ssid[0];
2857
c1179033 2858 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
e5806072 2859 /* Abort any on-going scan */
27a68fe3 2860 brcmf_abort_scanning(cfg);
e5806072
AS
2861 }
2862
c1179033 2863 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
27a68fe3 2864 err = brcmf_do_escan(cfg, wiphy, ndev, request);
e5806072 2865 if (err) {
c1179033 2866 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
e5806072
AS
2867 goto out_err;
2868 }
27a68fe3
AS
2869 cfg->sched_escan = true;
2870 cfg->scan_request = request;
e5806072
AS
2871 } else {
2872 WL_ERR("FALSE PNO Event. (pfn_count == 0)\n");
2873 goto out_err;
2874 }
2875
2876 kfree(ssid);
2877 kfree(channel);
2878 kfree(request);
2879 return 0;
2880
2881out_err:
2882 kfree(ssid);
2883 kfree(channel);
2884 kfree(request);
2885 cfg80211_sched_scan_stopped(wiphy);
2886 return err;
2887}
2888
e5806072
AS
2889static int brcmf_dev_pno_clean(struct net_device *ndev)
2890{
e5806072
AS
2891 int ret;
2892
2893 /* Disable pfn */
ac24be6f 2894 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
e5806072
AS
2895 if (ret == 0) {
2896 /* clear pfn */
ac24be6f
AS
2897 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2898 NULL, 0);
e5806072
AS
2899 }
2900 if (ret < 0)
2901 WL_ERR("failed code %d\n", ret);
2902
2903 return ret;
2904}
2905
2906static int brcmf_dev_pno_config(struct net_device *ndev)
2907{
2908 struct brcmf_pno_param_le pfn_param;
e5806072
AS
2909
2910 memset(&pfn_param, 0, sizeof(pfn_param));
2911 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2912
2913 /* set extra pno params */
2914 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2915 pfn_param.repeat = BRCMF_PNO_REPEAT;
2916 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2917
2918 /* set up pno scan fr */
2919 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2920
ac24be6f
AS
2921 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2922 &pfn_param, sizeof(pfn_param));
e5806072
AS
2923}
2924
2925static int
2926brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2927 struct net_device *ndev,
2928 struct cfg80211_sched_scan_request *request)
2929{
c1179033 2930 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 2931 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
e5806072
AS
2932 struct brcmf_pno_net_param_le pfn;
2933 int i;
2934 int ret = 0;
2935
2936 WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n",
2937 request->n_match_sets, request->n_ssids);
c1179033
AS
2938 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2939 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
e5806072
AS
2940 return -EAGAIN;
2941 }
2942
2943 if (!request || !request->n_ssids || !request->n_match_sets) {
2944 WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
9495b31a 2945 request ? request->n_ssids : 0);
e5806072
AS
2946 return -EINVAL;
2947 }
2948
2949 if (request->n_ssids > 0) {
2950 for (i = 0; i < request->n_ssids; i++) {
2951 /* Active scan req for ssids */
2952 WL_SCAN(">>> Active scan req for ssid (%s)\n",
2953 request->ssids[i].ssid);
2954
2955 /*
2956 * match_set ssids is a supert set of n_ssid list,
2957 * so we need not add these set seperately.
2958 */
2959 }
2960 }
2961
2962 if (request->n_match_sets > 0) {
2963 /* clean up everything */
2964 ret = brcmf_dev_pno_clean(ndev);
2965 if (ret < 0) {
2966 WL_ERR("failed error=%d\n", ret);
2967 return ret;
2968 }
2969
2970 /* configure pno */
2971 ret = brcmf_dev_pno_config(ndev);
2972 if (ret < 0) {
2973 WL_ERR("PNO setup failed!! ret=%d\n", ret);
2974 return -EINVAL;
2975 }
2976
2977 /* configure each match set */
2978 for (i = 0; i < request->n_match_sets; i++) {
2979 struct cfg80211_ssid *ssid;
2980 u32 ssid_len;
2981
2982 ssid = &request->match_sets[i].ssid;
2983 ssid_len = ssid->ssid_len;
2984
2985 if (!ssid_len) {
2986 WL_ERR("skip broadcast ssid\n");
2987 continue;
2988 }
2989 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
2990 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
2991 pfn.wsec = cpu_to_le32(0);
2992 pfn.infra = cpu_to_le32(1);
2993 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
2994 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
2995 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
c1179033 2996 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
ac24be6f 2997 sizeof(pfn));
e5806072
AS
2998 WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
2999 ret == 0 ? "set" : "failed",
3000 ssid->ssid);
3001 }
3002 /* Enable the PNO */
c1179033 3003 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
e5806072
AS
3004 WL_ERR("PNO enable failed!! ret=%d\n", ret);
3005 return -EINVAL;
3006 }
3007 } else {
3008 return -EINVAL;
3009 }
3010
3011 return 0;
3012}
3013
3014static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3015 struct net_device *ndev)
3016{
27a68fe3 3017 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
e5806072
AS
3018
3019 WL_SCAN("enter\n");
3020 brcmf_dev_pno_clean(ndev);
27a68fe3
AS
3021 if (cfg->sched_escan)
3022 brcmf_notify_escan_complete(cfg, ndev, true, true);
e5806072
AS
3023 return 0;
3024}
e5806072 3025
cbaa177d
AS
3026#ifdef CONFIG_NL80211_TESTMODE
3027static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3028{
27a68fe3 3029 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3eacf866 3030 struct net_device *ndev = cfg_to_ndev(cfg);
cbaa177d
AS
3031 struct brcmf_dcmd *dcmd = data;
3032 struct sk_buff *reply;
3033 int ret;
3034
f368a5b6
HM
3035 WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3036 dcmd->buf, dcmd->len);
3037
3038 if (dcmd->set)
ac24be6f
AS
3039 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3040 dcmd->buf, dcmd->len);
f368a5b6 3041 else
ac24be6f
AS
3042 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3043 dcmd->buf, dcmd->len);
cbaa177d
AS
3044 if (ret == 0) {
3045 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3046 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3047 ret = cfg80211_testmode_reply(reply);
3048 }
3049 return ret;
3050}
3051#endif
3052
1a873342
HM
3053static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
3054{
ac24be6f 3055 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3056 s32 err;
3057
3058 /* set auth */
ac24be6f 3059 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
1a873342
HM
3060 if (err < 0) {
3061 WL_ERR("auth error %d\n", err);
3062 return err;
3063 }
3064 /* set wsec */
ac24be6f 3065 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
1a873342
HM
3066 if (err < 0) {
3067 WL_ERR("wsec error %d\n", err);
3068 return err;
3069 }
3070 /* set upper-layer auth */
ac24be6f 3071 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
1a873342
HM
3072 if (err < 0) {
3073 WL_ERR("wpa_auth error %d\n", err);
3074 return err;
3075 }
3076
3077 return 0;
3078}
3079
3080static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3081{
3082 if (is_rsn_ie)
3083 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3084
3085 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3086}
3087
3088static s32
3089brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
34778529 3090 bool is_rsn_ie)
1a873342 3091{
ac24be6f 3092 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3093 u32 auth = 0; /* d11 open authentication */
3094 u16 count;
3095 s32 err = 0;
3096 s32 len = 0;
3097 u32 i;
3098 u32 wsec;
3099 u32 pval = 0;
3100 u32 gval = 0;
3101 u32 wpa_auth = 0;
3102 u32 offset;
3103 u8 *data;
3104 u16 rsn_cap;
3105 u32 wme_bss_disable;
3106
3107 WL_TRACE("Enter\n");
3108 if (wpa_ie == NULL)
3109 goto exit;
3110
3111 len = wpa_ie->len + TLV_HDR_LEN;
3112 data = (u8 *)wpa_ie;
3113 offset = 0;
3114 if (!is_rsn_ie)
3115 offset += VS_IE_FIXED_HDR_LEN;
3116 offset += WPA_IE_VERSION_LEN;
3117
3118 /* check for multicast cipher suite */
3119 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3120 err = -EINVAL;
3121 WL_ERR("no multicast cipher suite\n");
3122 goto exit;
3123 }
3124
3125 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3126 err = -EINVAL;
3127 WL_ERR("ivalid OUI\n");
3128 goto exit;
3129 }
3130 offset += TLV_OUI_LEN;
3131
3132 /* pick up multicast cipher */
3133 switch (data[offset]) {
3134 case WPA_CIPHER_NONE:
3135 gval = 0;
3136 break;
3137 case WPA_CIPHER_WEP_40:
3138 case WPA_CIPHER_WEP_104:
3139 gval = WEP_ENABLED;
3140 break;
3141 case WPA_CIPHER_TKIP:
3142 gval = TKIP_ENABLED;
3143 break;
3144 case WPA_CIPHER_AES_CCM:
3145 gval = AES_ENABLED;
3146 break;
3147 default:
3148 err = -EINVAL;
3149 WL_ERR("Invalid multi cast cipher info\n");
3150 goto exit;
3151 }
3152
3153 offset++;
3154 /* walk thru unicast cipher list and pick up what we recognize */
3155 count = data[offset] + (data[offset + 1] << 8);
3156 offset += WPA_IE_SUITE_COUNT_LEN;
3157 /* Check for unicast suite(s) */
3158 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3159 err = -EINVAL;
3160 WL_ERR("no unicast cipher suite\n");
3161 goto exit;
3162 }
3163 for (i = 0; i < count; i++) {
3164 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3165 err = -EINVAL;
3166 WL_ERR("ivalid OUI\n");
3167 goto exit;
3168 }
3169 offset += TLV_OUI_LEN;
3170 switch (data[offset]) {
3171 case WPA_CIPHER_NONE:
3172 break;
3173 case WPA_CIPHER_WEP_40:
3174 case WPA_CIPHER_WEP_104:
3175 pval |= WEP_ENABLED;
3176 break;
3177 case WPA_CIPHER_TKIP:
3178 pval |= TKIP_ENABLED;
3179 break;
3180 case WPA_CIPHER_AES_CCM:
3181 pval |= AES_ENABLED;
3182 break;
3183 default:
3184 WL_ERR("Ivalid unicast security info\n");
3185 }
3186 offset++;
3187 }
3188 /* walk thru auth management suite list and pick up what we recognize */
3189 count = data[offset] + (data[offset + 1] << 8);
3190 offset += WPA_IE_SUITE_COUNT_LEN;
3191 /* Check for auth key management suite(s) */
3192 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3193 err = -EINVAL;
3194 WL_ERR("no auth key mgmt suite\n");
3195 goto exit;
3196 }
3197 for (i = 0; i < count; i++) {
3198 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3199 err = -EINVAL;
3200 WL_ERR("ivalid OUI\n");
3201 goto exit;
3202 }
3203 offset += TLV_OUI_LEN;
3204 switch (data[offset]) {
3205 case RSN_AKM_NONE:
3206 WL_TRACE("RSN_AKM_NONE\n");
3207 wpa_auth |= WPA_AUTH_NONE;
3208 break;
3209 case RSN_AKM_UNSPECIFIED:
3210 WL_TRACE("RSN_AKM_UNSPECIFIED\n");
3211 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3212 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3213 break;
3214 case RSN_AKM_PSK:
3215 WL_TRACE("RSN_AKM_PSK\n");
3216 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3217 (wpa_auth |= WPA_AUTH_PSK);
3218 break;
3219 default:
3220 WL_ERR("Ivalid key mgmt info\n");
3221 }
3222 offset++;
3223 }
3224
3225 if (is_rsn_ie) {
3226 wme_bss_disable = 1;
3227 if ((offset + RSN_CAP_LEN) <= len) {
3228 rsn_cap = data[offset] + (data[offset + 1] << 8);
3229 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3230 wme_bss_disable = 0;
3231 }
3232 /* set wme_bss_disable to sync RSN Capabilities */
ac24be6f 3233 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
81f5dcb8 3234 wme_bss_disable);
1a873342
HM
3235 if (err < 0) {
3236 WL_ERR("wme_bss_disable error %d\n", err);
3237 goto exit;
3238 }
3239 }
3240 /* FOR WPS , set SES_OW_ENABLED */
3241 wsec = (pval | gval | SES_OW_ENABLED);
3242
3243 /* set auth */
ac24be6f 3244 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
1a873342
HM
3245 if (err < 0) {
3246 WL_ERR("auth error %d\n", err);
3247 goto exit;
3248 }
3249 /* set wsec */
ac24be6f 3250 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1a873342
HM
3251 if (err < 0) {
3252 WL_ERR("wsec error %d\n", err);
3253 goto exit;
3254 }
3255 /* set upper-layer auth */
ac24be6f 3256 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
1a873342
HM
3257 if (err < 0) {
3258 WL_ERR("wpa_auth error %d\n", err);
3259 goto exit;
3260 }
3261
3262exit:
3263 return err;
3264}
3265
3266static s32
3082b9be 3267brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
1a873342
HM
3268 struct parsed_vndr_ies *vndr_ies)
3269{
3270 s32 err = 0;
3271 struct brcmf_vs_tlv *vndrie;
3272 struct brcmf_tlv *ie;
3273 struct parsed_vndr_ie_info *parsed_info;
3274 s32 remaining_len;
3275
3276 remaining_len = (s32)vndr_ie_len;
3277 memset(vndr_ies, 0, sizeof(*vndr_ies));
3278
3279 ie = (struct brcmf_tlv *)vndr_ie_buf;
3280 while (ie) {
3281 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3282 goto next;
3283 vndrie = (struct brcmf_vs_tlv *)ie;
3284 /* len should be bigger than OUI length + one */
3285 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
3286 WL_ERR("invalid vndr ie. length is too small %d\n",
3287 vndrie->len);
3288 goto next;
3289 }
3290 /* if wpa or wme ie, do not add ie */
3291 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3292 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3293 (vndrie->oui_type == WME_OUI_TYPE))) {
3294 WL_TRACE("Found WPA/WME oui. Do not add it\n");
3295 goto next;
3296 }
3297
3298 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3299
3300 /* save vndr ie information */
3301 parsed_info->ie_ptr = (char *)vndrie;
3302 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3303 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3304
3305 vndr_ies->count++;
3306
3307 WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n",
3308 parsed_info->vndrie.oui[0],
3309 parsed_info->vndrie.oui[1],
3310 parsed_info->vndrie.oui[2],
3311 parsed_info->vndrie.oui_type);
3312
3313 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3314 break;
3315next:
3316 remaining_len -= ie->len;
3317 if (remaining_len <= 2)
3318 ie = NULL;
3319 else
3320 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len);
3321 }
3322 return err;
3323}
3324
3325static u32
3326brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3327{
3328
3329 __le32 iecount_le;
3330 __le32 pktflag_le;
3331
3332 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3333 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3334
3335 iecount_le = cpu_to_le32(1);
3336 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3337
3338 pktflag_le = cpu_to_le32(pktflag);
3339 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3340
3341 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3342
3343 return ie_len + VNDR_IE_HDR_SIZE;
3344}
3345
3082b9be 3346static
1332e26e
AS
3347s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3348 const u8 *vndr_ie_buf, u32 vndr_ie_len)
1a873342 3349{
1332e26e
AS
3350 struct brcmf_if *ifp;
3351 struct vif_saved_ie *saved_ie;
1a873342
HM
3352 s32 err = 0;
3353 u8 *iovar_ie_buf;
3354 u8 *curr_ie_buf;
3355 u8 *mgmt_ie_buf = NULL;
3e4f319d 3356 int mgmt_ie_buf_len;
81118d16 3357 u32 *mgmt_ie_len;
1a873342
HM
3358 u32 del_add_ie_buf_len = 0;
3359 u32 total_ie_buf_len = 0;
3360 u32 parsed_ie_buf_len = 0;
3361 struct parsed_vndr_ies old_vndr_ies;
3362 struct parsed_vndr_ies new_vndr_ies;
3363 struct parsed_vndr_ie_info *vndrie_info;
3364 s32 i;
3365 u8 *ptr;
3e4f319d 3366 int remained_buf_len;
1a873342 3367
1332e26e
AS
3368 if (!vif)
3369 return -ENODEV;
3370 ifp = vif->ifp;
3371 saved_ie = &vif->saved_ie;
3372
3373 WL_TRACE("bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
1a873342
HM
3374 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3375 if (!iovar_ie_buf)
3376 return -ENOMEM;
3377 curr_ie_buf = iovar_ie_buf;
8ff5dc92 3378 if (ifp->vif->mode == WL_MODE_AP) {
1a873342
HM
3379 switch (pktflag) {
3380 case VNDR_IE_PRBRSP_FLAG:
8ff5dc92
AS
3381 mgmt_ie_buf = saved_ie->probe_res_ie;
3382 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3383 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
1a873342
HM
3384 break;
3385 case VNDR_IE_BEACON_FLAG:
8ff5dc92
AS
3386 mgmt_ie_buf = saved_ie->beacon_ie;
3387 mgmt_ie_len = &saved_ie->beacon_ie_len;
3388 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
1a873342
HM
3389 break;
3390 default:
3391 err = -EPERM;
3392 WL_ERR("not suitable type\n");
3393 goto exit;
3394 }
1a873342
HM
3395 } else {
3396 err = -EPERM;
3397 WL_ERR("not suitable type\n");
3398 goto exit;
3399 }
3400
3401 if (vndr_ie_len > mgmt_ie_buf_len) {
3402 err = -ENOMEM;
3403 WL_ERR("extra IE size too big\n");
3404 goto exit;
3405 }
3406
3407 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3408 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3409 ptr = curr_ie_buf;
3410 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3411 for (i = 0; i < new_vndr_ies.count; i++) {
3412 vndrie_info = &new_vndr_ies.ie_info[i];
3413 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3414 vndrie_info->ie_len);
3415 parsed_ie_buf_len += vndrie_info->ie_len;
3416 }
3417 }
3418
3419 if (mgmt_ie_buf != NULL) {
3420 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3421 (memcmp(mgmt_ie_buf, curr_ie_buf,
3422 parsed_ie_buf_len) == 0)) {
3423 WL_TRACE("Previous mgmt IE is equals to current IE");
3424 goto exit;
3425 }
3426
3427 /* parse old vndr_ie */
3428 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3429
3430 /* make a command to delete old ie */
3431 for (i = 0; i < old_vndr_ies.count; i++) {
3432 vndrie_info = &old_vndr_ies.ie_info[i];
3433
3434 WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3435 vndrie_info->vndrie.id,
3436 vndrie_info->vndrie.len,
3437 vndrie_info->vndrie.oui[0],
3438 vndrie_info->vndrie.oui[1],
3439 vndrie_info->vndrie.oui[2]);
3440
3441 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3442 vndrie_info->ie_ptr,
3443 vndrie_info->ie_len,
3444 "del");
3445 curr_ie_buf += del_add_ie_buf_len;
3446 total_ie_buf_len += del_add_ie_buf_len;
3447 }
3448 }
3449
3450 *mgmt_ie_len = 0;
3451 /* Add if there is any extra IE */
3452 if (mgmt_ie_buf && parsed_ie_buf_len) {
3453 ptr = mgmt_ie_buf;
3454
3455 remained_buf_len = mgmt_ie_buf_len;
3456
3457 /* make a command to add new ie */
3458 for (i = 0; i < new_vndr_ies.count; i++) {
3459 vndrie_info = &new_vndr_ies.ie_info[i];
3460
3461 WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3462 vndrie_info->vndrie.id,
3463 vndrie_info->vndrie.len,
3464 vndrie_info->vndrie.oui[0],
3465 vndrie_info->vndrie.oui[1],
3466 vndrie_info->vndrie.oui[2]);
3467
3468 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3469 vndrie_info->ie_ptr,
3470 vndrie_info->ie_len,
3471 "add");
3472 /* verify remained buf size before copy data */
3473 remained_buf_len -= vndrie_info->ie_len;
3474 if (remained_buf_len < 0) {
3475 WL_ERR("no space in mgmt_ie_buf: len left %d",
3476 remained_buf_len);
3477 break;
3478 }
3479
3480 /* save the parsed IE in wl struct */
3481 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3482 vndrie_info->ie_len);
3483 *mgmt_ie_len += vndrie_info->ie_len;
3484
3485 curr_ie_buf += del_add_ie_buf_len;
3486 total_ie_buf_len += del_add_ie_buf_len;
3487 }
3488 }
3489 if (total_ie_buf_len) {
c1179033 3490 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
81f5dcb8 3491 total_ie_buf_len);
1a873342
HM
3492 if (err)
3493 WL_ERR("vndr ie set error : %d\n", err);
3494 }
3495
3496exit:
3497 kfree(iovar_ie_buf);
3498 return err;
3499}
3500
3501static s32
3502brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3503 struct cfg80211_ap_settings *settings)
3504{
3505 s32 ie_offset;
ac24be6f 3506 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3507 struct brcmf_tlv *ssid_ie;
3508 struct brcmf_ssid_le ssid_le;
1a873342
HM
3509 s32 err = -EPERM;
3510 struct brcmf_tlv *rsn_ie;
3511 struct brcmf_vs_tlv *wpa_ie;
3512 struct brcmf_join_params join_params;
1a873342
HM
3513 s32 bssidx = 0;
3514
3515 WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3516 settings->channel_type, settings->beacon_interval,
3517 settings->dtim_period);
3f40b839 3518 WL_TRACE("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
1a873342
HM
3519 settings->ssid, settings->ssid_len, settings->auth_type,
3520 settings->inactivity_timeout);
3521
c1179033 3522 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
1a873342
HM
3523 WL_ERR("Not in AP creation mode\n");
3524 return -EPERM;
3525 }
3526
3527 memset(&ssid_le, 0, sizeof(ssid_le));
3528 if (settings->ssid == NULL || settings->ssid_len == 0) {
3529 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3530 ssid_ie = brcmf_parse_tlvs(
3531 (u8 *)&settings->beacon.head[ie_offset],
3532 settings->beacon.head_len - ie_offset,
3533 WLAN_EID_SSID);
3534 if (!ssid_ie)
3535 return -EINVAL;
3536
3537 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3538 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
3539 WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID);
3540 } else {
3541 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3542 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3543 }
3544
3545 brcmf_set_mpc(ndev, 0);
ac24be6f 3546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
1a873342
HM
3547 if (err < 0) {
3548 WL_ERR("BRCMF_C_DOWN error %d\n", err);
3549 goto exit;
3550 }
ac24be6f 3551 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
1a873342
HM
3552 if (err < 0) {
3553 WL_ERR("SET INFRA error %d\n", err);
3554 goto exit;
3555 }
ac24be6f 3556 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
1a873342
HM
3557 if (err < 0) {
3558 WL_ERR("setting AP mode failed %d\n", err);
3559 goto exit;
3560 }
3561
3562 /* find the RSN_IE */
3563 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3564 settings->beacon.tail_len, WLAN_EID_RSN);
3565
3566 /* find the WPA_IE */
3567 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3568 settings->beacon.tail_len);
3569
1a873342
HM
3570 if ((wpa_ie != NULL || rsn_ie != NULL)) {
3571 WL_TRACE("WPA(2) IE is found\n");
3572 if (wpa_ie != NULL) {
3573 /* WPA IE */
34778529 3574 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
1a873342
HM
3575 if (err < 0)
3576 goto exit;
1a873342
HM
3577 } else {
3578 /* RSN IE */
3579 err = brcmf_configure_wpaie(ndev,
34778529 3580 (struct brcmf_vs_tlv *)rsn_ie, true);
1a873342
HM
3581 if (err < 0)
3582 goto exit;
1a873342 3583 }
1a873342
HM
3584 } else {
3585 WL_TRACE("No WPA(2) IEs found\n");
3586 brcmf_configure_opensecurity(ndev, bssidx);
1a873342
HM
3587 }
3588 /* Set Beacon IEs to FW */
1332e26e
AS
3589 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3590 VNDR_IE_BEACON_FLAG,
3591 settings->beacon.tail,
3592 settings->beacon.tail_len);
1a873342
HM
3593 if (err)
3594 WL_ERR("Set Beacon IE Failed\n");
3595 else
3596 WL_TRACE("Applied Vndr IEs for Beacon\n");
3597
3598 /* Set Probe Response IEs to FW */
1332e26e
AS
3599 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3600 VNDR_IE_PRBRSP_FLAG,
3601 settings->beacon.proberesp_ies,
3602 settings->beacon.proberesp_ies_len);
1a873342
HM
3603 if (err)
3604 WL_ERR("Set Probe Resp IE Failed\n");
3605 else
3606 WL_TRACE("Applied Vndr IEs for Probe Resp\n");
3607
3608 if (settings->beacon_interval) {
ac24be6f 3609 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
81f5dcb8 3610 settings->beacon_interval);
1a873342
HM
3611 if (err < 0) {
3612 WL_ERR("Beacon Interval Set Error, %d\n", err);
3613 goto exit;
3614 }
3615 }
3616 if (settings->dtim_period) {
ac24be6f 3617 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
81f5dcb8 3618 settings->dtim_period);
1a873342
HM
3619 if (err < 0) {
3620 WL_ERR("DTIM Interval Set Error, %d\n", err);
3621 goto exit;
3622 }
3623 }
ac24be6f 3624 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
1a873342
HM
3625 if (err < 0) {
3626 WL_ERR("BRCMF_C_UP error (%d)\n", err);
3627 goto exit;
3628 }
3629
3630 memset(&join_params, 0, sizeof(join_params));
3631 /* join parameters starts with ssid */
3632 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3633 /* create softap */
ac24be6f
AS
3634 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3635 &join_params, sizeof(join_params));
1a873342
HM
3636 if (err < 0) {
3637 WL_ERR("SET SSID error (%d)\n", err);
3638 goto exit;
3639 }
c1179033
AS
3640 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3641 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
3642
3643exit:
3644 if (err)
3645 brcmf_set_mpc(ndev, 1);
3646 return err;
3647}
3648
3649static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3650{
c1179033 3651 struct brcmf_if *ifp = netdev_priv(ndev);
27a68fe3 3652 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1a873342
HM
3653 s32 err = -EPERM;
3654
3655 WL_TRACE("Enter\n");
3656
27a68fe3 3657 if (cfg->conf->mode == WL_MODE_AP) {
1a873342
HM
3658 /* Due to most likely deauths outstanding we sleep */
3659 /* first to make sure they get processed by fw. */
3660 msleep(400);
ac24be6f
AS
3661 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
3662 BRCMF_C_SET_AP, 0);
1a873342
HM
3663 if (err < 0) {
3664 WL_ERR("setting AP mode failed %d\n", err);
3665 goto exit;
3666 }
ac24be6f 3667 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
1a873342
HM
3668 if (err < 0) {
3669 WL_ERR("BRCMF_C_UP error %d\n", err);
3670 goto exit;
3671 }
3672 brcmf_set_mpc(ndev, 1);
c1179033
AS
3673 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3674 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
1a873342
HM
3675 }
3676exit:
3677 return err;
3678}
3679
3680static int
3681brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3682 u8 *mac)
3683{
3684 struct brcmf_scb_val_le scbval;
0abb5f21 3685 struct brcmf_if *ifp = netdev_priv(ndev);
1a873342
HM
3686 s32 err;
3687
3688 if (!mac)
3689 return -EFAULT;
3690
3691 WL_TRACE("Enter %pM\n", mac);
3692
ce81e317 3693 if (!check_vif_up(ifp->vif))
1a873342
HM
3694 return -EIO;
3695
3696 memcpy(&scbval.ea, mac, ETH_ALEN);
3697 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
0abb5f21 3698 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
81f5dcb8 3699 &scbval, sizeof(scbval));
1a873342
HM
3700 if (err)
3701 WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
3702
3703 WL_TRACE("Exit\n");
3704 return err;
3705}
3706
5b435de0
AS
3707static struct cfg80211_ops wl_cfg80211_ops = {
3708 .change_virtual_intf = brcmf_cfg80211_change_iface,
3709 .scan = brcmf_cfg80211_scan,
3710 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
3711 .join_ibss = brcmf_cfg80211_join_ibss,
3712 .leave_ibss = brcmf_cfg80211_leave_ibss,
3713 .get_station = brcmf_cfg80211_get_station,
3714 .set_tx_power = brcmf_cfg80211_set_tx_power,
3715 .get_tx_power = brcmf_cfg80211_get_tx_power,
3716 .add_key = brcmf_cfg80211_add_key,
3717 .del_key = brcmf_cfg80211_del_key,
3718 .get_key = brcmf_cfg80211_get_key,
3719 .set_default_key = brcmf_cfg80211_config_default_key,
3720 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
3721 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
3722 .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
3723 .connect = brcmf_cfg80211_connect,
3724 .disconnect = brcmf_cfg80211_disconnect,
3725 .suspend = brcmf_cfg80211_suspend,
3726 .resume = brcmf_cfg80211_resume,
3727 .set_pmksa = brcmf_cfg80211_set_pmksa,
3728 .del_pmksa = brcmf_cfg80211_del_pmksa,
cbaa177d 3729 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
1a873342
HM
3730 .start_ap = brcmf_cfg80211_start_ap,
3731 .stop_ap = brcmf_cfg80211_stop_ap,
3732 .del_station = brcmf_cfg80211_del_station,
e5806072
AS
3733 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
3734 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
cbaa177d
AS
3735#ifdef CONFIG_NL80211_TESTMODE
3736 .testmode_cmd = brcmf_cfg80211_testmode
3737#endif
5b435de0
AS
3738};
3739
3740static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
3741{
3742 s32 err = 0;
3743
3744 switch (mode) {
3745 case WL_MODE_BSS:
3746 return NL80211_IFTYPE_STATION;
3747 case WL_MODE_IBSS:
3748 return NL80211_IFTYPE_ADHOC;
3749 default:
3750 return NL80211_IFTYPE_UNSPECIFIED;
3751 }
3752
3753 return err;
3754}
3755
e5806072
AS
3756static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
3757{
e5806072
AS
3758 /* scheduled scan settings */
3759 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
3760 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
3761 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3762 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
e5806072
AS
3763}
3764
3eacf866 3765static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
5b435de0 3766{
3eacf866 3767 struct wiphy *wiphy;
5b435de0
AS
3768 s32 err = 0;
3769
3eacf866
AS
3770 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
3771 if (!wiphy) {
bfeb4dbc 3772 WL_ERR("Could not allocate wiphy device\n");
3eacf866
AS
3773 return ERR_PTR(-ENOMEM);
3774 }
3775 set_wiphy_dev(wiphy, phydev);
3776 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
3777 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
3778 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3779 BIT(NL80211_IFTYPE_ADHOC) |
3780 BIT(NL80211_IFTYPE_AP);
3781 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3782 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
5b435de0
AS
3783 * it as 11a by default.
3784 * This will be updated with
3785 * 11n phy tables in
3786 * "ifconfig up"
3787 * if phy has 11n capability
3788 */
3eacf866
AS
3789 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3790 wiphy->cipher_suites = __wl_cipher_suites;
3791 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
3792 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
5b435de0
AS
3793 * save mode
3794 * by default
3795 */
3eacf866
AS
3796 brcmf_wiphy_pno_params(wiphy);
3797 err = wiphy_register(wiphy);
5b435de0 3798 if (err < 0) {
bfeb4dbc 3799 WL_ERR("Could not register wiphy device (%d)\n", err);
3eacf866
AS
3800 wiphy_free(wiphy);
3801 return ERR_PTR(err);
5b435de0 3802 }
3eacf866
AS
3803 return wiphy;
3804}
3805
3806static
3807struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
3808 struct net_device *netdev,
3809 s32 mode, bool pm_block)
3810{
3811 struct brcmf_cfg80211_vif *vif;
5b435de0 3812
3eacf866
AS
3813 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
3814 return ERR_PTR(-ENOSPC);
5b435de0 3815
3eacf866
AS
3816 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
3817 if (!vif)
3818 return ERR_PTR(-ENOMEM);
3819
3820 vif->wdev.wiphy = cfg->wiphy;
3821 vif->wdev.netdev = netdev;
3822 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
5b435de0 3823
3eacf866
AS
3824 if (netdev) {
3825 vif->ifp = netdev_priv(netdev);
3826 netdev->ieee80211_ptr = &vif->wdev;
3827 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
3828 }
3829
3830 vif->mode = mode;
3831 vif->pm_block = pm_block;
3832 vif->roam_off = -1;
3833
6ac4f4ed
AS
3834 brcmf_init_prof(&vif->profile);
3835
3eacf866
AS
3836 list_add_tail(&vif->list, &cfg->vif_list);
3837 cfg->vif_cnt++;
3838 return vif;
5b435de0
AS
3839}
3840
3eacf866 3841static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
5b435de0 3842{
3eacf866
AS
3843 struct brcmf_cfg80211_info *cfg;
3844 struct wiphy *wiphy;
5b435de0 3845
3eacf866
AS
3846 wiphy = vif->wdev.wiphy;
3847 cfg = wiphy_priv(wiphy);
3848 list_del(&vif->list);
3849 cfg->vif_cnt--;
3850
3851 kfree(vif);
3852 if (!cfg->vif_cnt) {
3853 wiphy_unregister(wiphy);
3854 wiphy_free(wiphy);
5b435de0 3855 }
5b435de0
AS
3856}
3857
27a68fe3 3858static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
3859 const struct brcmf_event_msg *e)
3860{
5c36b99a
AS
3861 u32 event = e->event_code;
3862 u32 status = e->status;
5b435de0
AS
3863
3864 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
3865 WL_CONN("Processing set ssid\n");
27a68fe3 3866 cfg->link_up = true;
5b435de0
AS
3867 return true;
3868 }
3869
3870 return false;
3871}
3872
27a68fe3 3873static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
3874 const struct brcmf_event_msg *e)
3875{
5c36b99a
AS
3876 u32 event = e->event_code;
3877 u16 flags = e->flags;
5b435de0
AS
3878
3879 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
3880 WL_CONN("Processing link down\n");
3881 return true;
3882 }
3883 return false;
3884}
3885
27a68fe3 3886static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
3887 const struct brcmf_event_msg *e)
3888{
5c36b99a
AS
3889 u32 event = e->event_code;
3890 u32 status = e->status;
5b435de0
AS
3891
3892 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
3893 WL_CONN("Processing Link %s & no network found\n",
5c36b99a 3894 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
5b435de0
AS
3895 return true;
3896 }
3897
3898 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
3899 WL_CONN("Processing connecting & no network found\n");
3900 return true;
3901 }
3902
3903 return false;
3904}
3905
27a68fe3 3906static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 3907{
27a68fe3 3908 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
3909
3910 kfree(conn_info->req_ie);
3911 conn_info->req_ie = NULL;
3912 conn_info->req_ie_len = 0;
3913 kfree(conn_info->resp_ie);
3914 conn_info->resp_ie = NULL;
3915 conn_info->resp_ie_len = 0;
3916}
3917
27a68fe3 3918static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
5b435de0 3919{
ac24be6f 3920 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
c4e382d2 3921 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
27a68fe3 3922 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
3923 u32 req_len;
3924 u32 resp_len;
3925 s32 err = 0;
3926
27a68fe3 3927 brcmf_clear_assoc_ies(cfg);
5b435de0 3928
ac24be6f
AS
3929 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
3930 cfg->extra_buf, WL_ASSOC_INFO_MAX);
5b435de0
AS
3931 if (err) {
3932 WL_ERR("could not get assoc info (%d)\n", err);
3933 return err;
3934 }
c4e382d2 3935 assoc_info =
27a68fe3 3936 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
c4e382d2
AS
3937 req_len = le32_to_cpu(assoc_info->req_len);
3938 resp_len = le32_to_cpu(assoc_info->resp_len);
5b435de0 3939 if (req_len) {
ac24be6f 3940 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
81f5dcb8
HM
3941 cfg->extra_buf,
3942 WL_ASSOC_INFO_MAX);
5b435de0
AS
3943 if (err) {
3944 WL_ERR("could not get assoc req (%d)\n", err);
3945 return err;
3946 }
3947 conn_info->req_ie_len = req_len;
3948 conn_info->req_ie =
27a68fe3 3949 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
5b435de0
AS
3950 GFP_KERNEL);
3951 } else {
3952 conn_info->req_ie_len = 0;
3953 conn_info->req_ie = NULL;
3954 }
3955 if (resp_len) {
ac24be6f 3956 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
81f5dcb8
HM
3957 cfg->extra_buf,
3958 WL_ASSOC_INFO_MAX);
5b435de0
AS
3959 if (err) {
3960 WL_ERR("could not get assoc resp (%d)\n", err);
3961 return err;
3962 }
3963 conn_info->resp_ie_len = resp_len;
3964 conn_info->resp_ie =
27a68fe3 3965 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
5b435de0
AS
3966 GFP_KERNEL);
3967 } else {
3968 conn_info->resp_ie_len = 0;
3969 conn_info->resp_ie = NULL;
3970 }
3971 WL_CONN("req len (%d) resp len (%d)\n",
3972 conn_info->req_ie_len, conn_info->resp_ie_len);
3973
3974 return err;
3975}
3976
3977static s32
27a68fe3 3978brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
3979 struct net_device *ndev,
3980 const struct brcmf_event_msg *e)
3981{
c1179033
AS
3982 struct brcmf_if *ifp = netdev_priv(ndev);
3983 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3
AS
3984 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3985 struct wiphy *wiphy = cfg_to_wiphy(cfg);
a180b83b 3986 struct ieee80211_channel *notify_channel = NULL;
5b435de0 3987 struct ieee80211_supported_band *band;
a180b83b 3988 struct brcmf_bss_info_le *bi;
5b435de0
AS
3989 u32 freq;
3990 s32 err = 0;
3991 u32 target_channel;
a180b83b 3992 u8 *buf;
5b435de0
AS
3993
3994 WL_TRACE("Enter\n");
3995
27a68fe3 3996 brcmf_get_assoc_ies(cfg);
6c8c4f72 3997 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 3998 brcmf_update_bss_info(cfg);
5b435de0 3999
a180b83b
FL
4000 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4001 if (buf == NULL) {
4002 err = -ENOMEM;
4003 goto done;
4004 }
4005
4006 /* data sent to dongle has to be little endian */
4007 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
c1179033 4008 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
ac24be6f 4009 buf, WL_BSS_INFO_MAX);
a180b83b
FL
4010
4011 if (err)
4012 goto done;
5b435de0 4013
a180b83b
FL
4014 bi = (struct brcmf_bss_info_le *)(buf + 4);
4015 target_channel = bi->ctl_ch ? bi->ctl_ch :
4016 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
5b435de0
AS
4017
4018 if (target_channel <= CH_MAX_2G_CHANNEL)
4019 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4020 else
4021 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4022
4023 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4024 notify_channel = ieee80211_get_channel(wiphy, freq);
4025
a180b83b
FL
4026done:
4027 kfree(buf);
06bb123e 4028 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
5b435de0
AS
4029 conn_info->req_ie, conn_info->req_ie_len,
4030 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4031 WL_CONN("Report roaming result\n");
4032
c1179033 4033 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
5b435de0
AS
4034 WL_TRACE("Exit\n");
4035 return err;
4036}
4037
4038static s32
27a68fe3 4039brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
5b435de0
AS
4040 struct net_device *ndev, const struct brcmf_event_msg *e,
4041 bool completed)
4042{
c1179033
AS
4043 struct brcmf_if *ifp = netdev_priv(ndev);
4044 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
27a68fe3 4045 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5b435de0
AS
4046 s32 err = 0;
4047
4048 WL_TRACE("Enter\n");
4049
c1179033
AS
4050 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4051 &ifp->vif->sme_state)) {
5b435de0 4052 if (completed) {
27a68fe3 4053 brcmf_get_assoc_ies(cfg);
6c8c4f72 4054 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4055 brcmf_update_bss_info(cfg);
5b435de0
AS
4056 }
4057 cfg80211_connect_result(ndev,
06bb123e 4058 (u8 *)profile->bssid,
5b435de0
AS
4059 conn_info->req_ie,
4060 conn_info->req_ie_len,
4061 conn_info->resp_ie,
4062 conn_info->resp_ie_len,
4063 completed ? WLAN_STATUS_SUCCESS :
4064 WLAN_STATUS_AUTH_TIMEOUT,
4065 GFP_KERNEL);
4066 if (completed)
c1179033
AS
4067 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4068 &ifp->vif->sme_state);
5b435de0
AS
4069 WL_CONN("Report connect result - connection %s\n",
4070 completed ? "succeeded" : "failed");
4071 }
4072 WL_TRACE("Exit\n");
4073 return err;
4074}
4075
4076static s32
27a68fe3 4077brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
1a873342
HM
4078 struct net_device *ndev,
4079 const struct brcmf_event_msg *e, void *data)
4080{
4081 s32 err = 0;
5c36b99a
AS
4082 u32 event = e->event_code;
4083 u32 reason = e->reason;
4084 u32 len = e->datalen;
1a873342
HM
4085 static int generation;
4086
4087 struct station_info sinfo;
4088
4089 WL_CONN("event %d, reason %d\n", event, reason);
4090 memset(&sinfo, 0, sizeof(sinfo));
4091
4092 sinfo.filled = 0;
4093 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4094 reason == BRCMF_E_STATUS_SUCCESS) {
4095 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4096 if (!data) {
4097 WL_ERR("No IEs present in ASSOC/REASSOC_IND");
4098 return -EINVAL;
4099 }
4100 sinfo.assoc_req_ies = data;
4101 sinfo.assoc_req_ies_len = len;
4102 generation++;
4103 sinfo.generation = generation;
4104 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
4105 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4106 (event == BRCMF_E_DEAUTH_IND) ||
4107 (event == BRCMF_E_DEAUTH)) {
4108 generation++;
4109 sinfo.generation = generation;
4110 cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
4111 }
4112 return err;
4113}
4114
5b435de0 4115static s32
1993732e 4116brcmf_notify_connect_status(struct brcmf_if *ifp,
5b435de0
AS
4117 const struct brcmf_event_msg *e, void *data)
4118{
1993732e
AS
4119 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4120 struct net_device *ndev = ifp->ndev;
c1179033 4121 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
5b435de0
AS
4122 s32 err = 0;
4123
27a68fe3
AS
4124 if (cfg->conf->mode == WL_MODE_AP) {
4125 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4126 } else if (brcmf_is_linkup(cfg, e)) {
5b435de0 4127 WL_CONN("Linkup\n");
27a68fe3 4128 if (brcmf_is_ibssmode(cfg)) {
6c8c4f72 4129 memcpy(profile->bssid, e->addr, ETH_ALEN);
27a68fe3 4130 wl_inform_ibss(cfg, ndev, e->addr);
5b435de0 4131 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
c1179033
AS
4132 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4133 &ifp->vif->sme_state);
4134 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4135 &ifp->vif->sme_state);
5b435de0 4136 } else
27a68fe3
AS
4137 brcmf_bss_connect_done(cfg, ndev, e, true);
4138 } else if (brcmf_is_linkdown(cfg, e)) {
5b435de0 4139 WL_CONN("Linkdown\n");
27a68fe3 4140 if (brcmf_is_ibssmode(cfg)) {
c1179033
AS
4141 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4142 &ifp->vif->sme_state);
4143 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4144 &ifp->vif->sme_state))
27a68fe3 4145 brcmf_link_down(cfg);
5b435de0 4146 } else {
27a68fe3 4147 brcmf_bss_connect_done(cfg, ndev, e, false);
c1179033
AS
4148 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4149 &ifp->vif->sme_state)) {
5b435de0 4150 cfg80211_disconnected(ndev, 0, NULL, 0,
c1179033 4151 GFP_KERNEL);
27a68fe3 4152 brcmf_link_down(cfg);
5b435de0
AS
4153 }
4154 }
6ac4f4ed 4155 brcmf_init_prof(ndev_to_prof(ndev));
27a68fe3
AS
4156 } else if (brcmf_is_nonetwork(cfg, e)) {
4157 if (brcmf_is_ibssmode(cfg))
c1179033
AS
4158 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4159 &ifp->vif->sme_state);
5b435de0 4160 else
27a68fe3 4161 brcmf_bss_connect_done(cfg, ndev, e, false);
5b435de0
AS
4162 }
4163
4164 return err;
4165}
4166
4167static s32
1993732e 4168brcmf_notify_roaming_status(struct brcmf_if *ifp,
5b435de0
AS
4169 const struct brcmf_event_msg *e, void *data)
4170{
1993732e 4171 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5b435de0 4172 s32 err = 0;
5c36b99a
AS
4173 u32 event = e->event_code;
4174 u32 status = e->status;
5b435de0
AS
4175
4176 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
c1179033 4177 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
1993732e 4178 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
5b435de0 4179 else
1993732e 4180 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
5b435de0
AS
4181 }
4182
4183 return err;
4184}
4185
4186static s32
1993732e 4187brcmf_notify_mic_status(struct brcmf_if *ifp,
5b435de0
AS
4188 const struct brcmf_event_msg *e, void *data)
4189{
5c36b99a 4190 u16 flags = e->flags;
5b435de0
AS
4191 enum nl80211_key_type key_type;
4192
4193 if (flags & BRCMF_EVENT_MSG_GROUP)
4194 key_type = NL80211_KEYTYPE_GROUP;
4195 else
4196 key_type = NL80211_KEYTYPE_PAIRWISE;
4197
1993732e 4198 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
5b435de0
AS
4199 NULL, GFP_KERNEL);
4200
4201 return 0;
4202}
4203
5b435de0
AS
4204static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4205{
4206 conf->mode = (u32)-1;
4207 conf->frag_threshold = (u32)-1;
4208 conf->rts_threshold = (u32)-1;
4209 conf->retry_short = (u32)-1;
4210 conf->retry_long = (u32)-1;
4211 conf->tx_power = -1;
4212}
4213
5c36b99a 4214static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
5b435de0 4215{
5c36b99a
AS
4216 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4217 brcmf_notify_connect_status);
4218 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4219 brcmf_notify_connect_status);
4220 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4221 brcmf_notify_connect_status);
4222 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4223 brcmf_notify_connect_status);
4224 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4225 brcmf_notify_connect_status);
4226 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4227 brcmf_notify_connect_status);
4228 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4229 brcmf_notify_roaming_status);
4230 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4231 brcmf_notify_mic_status);
4232 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4233 brcmf_notify_connect_status);
4234 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4235 brcmf_notify_sched_scan_results);
5b435de0
AS
4236}
4237
27a68fe3
AS
4238static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
4239{
27a68fe3
AS
4240 kfree(cfg->conf);
4241 cfg->conf = NULL;
27a68fe3
AS
4242 kfree(cfg->escan_ioctl_buf);
4243 cfg->escan_ioctl_buf = NULL;
27a68fe3
AS
4244 kfree(cfg->extra_buf);
4245 cfg->extra_buf = NULL;
27a68fe3
AS
4246 kfree(cfg->pmk_list);
4247 cfg->pmk_list = NULL;
27a68fe3
AS
4248}
4249
4250static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
4251{
27a68fe3
AS
4252 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4253 if (!cfg->conf)
5b435de0 4254 goto init_priv_mem_out;
27a68fe3
AS
4255 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4256 if (!cfg->escan_ioctl_buf)
e756af5b 4257 goto init_priv_mem_out;
27a68fe3
AS
4258 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4259 if (!cfg->extra_buf)
5b435de0 4260 goto init_priv_mem_out;
27a68fe3
AS
4261 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4262 if (!cfg->pmk_list)
5b435de0
AS
4263 goto init_priv_mem_out;
4264
4265 return 0;
4266
4267init_priv_mem_out:
27a68fe3 4268 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4269
4270 return -ENOMEM;
4271}
4272
27a68fe3 4273static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4274{
4275 s32 err = 0;
4276
27a68fe3
AS
4277 cfg->scan_request = NULL;
4278 cfg->pwr_save = true;
27a68fe3 4279 cfg->roam_on = true; /* roam on & off switch.
5b435de0 4280 we enable roam per default */
27a68fe3 4281 cfg->active_scan = true; /* we do active scan for
5b435de0 4282 specific scan per default */
27a68fe3 4283 cfg->dongle_up = false; /* dongle is not up yet */
27a68fe3 4284 err = brcmf_init_priv_mem(cfg);
5b435de0
AS
4285 if (err)
4286 return err;
5c36b99a 4287 brcmf_register_event_handlers(cfg);
27a68fe3 4288 mutex_init(&cfg->usr_sync);
27a68fe3
AS
4289 brcmf_init_escan(cfg);
4290 brcmf_init_conf(cfg->conf);
27a68fe3 4291 brcmf_link_down(cfg);
5b435de0
AS
4292
4293 return err;
4294}
4295
27a68fe3 4296static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
5b435de0 4297{
27a68fe3 4298 cfg->dongle_up = false; /* dongle down */
27a68fe3
AS
4299 brcmf_link_down(cfg);
4300 brcmf_abort_scanning(cfg);
4301 brcmf_deinit_priv_mem(cfg);
5b435de0
AS
4302}
4303
1ed9baf0 4304struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
5b435de0 4305{
1ed9baf0
AS
4306 struct net_device *ndev = drvr->iflist[0]->ndev;
4307 struct device *busdev = drvr->dev;
27a68fe3 4308 struct brcmf_cfg80211_info *cfg;
3eacf866
AS
4309 struct wiphy *wiphy;
4310 struct brcmf_cfg80211_vif *vif;
4311 struct brcmf_if *ifp;
5b435de0
AS
4312 s32 err = 0;
4313
4314 if (!ndev) {
4315 WL_ERR("ndev is invalid\n");
4316 return NULL;
4317 }
5b435de0 4318
3eacf866
AS
4319 ifp = netdev_priv(ndev);
4320 wiphy = brcmf_setup_wiphy(busdev);
4321 if (IS_ERR(wiphy))
5b435de0 4322 return NULL;
5b435de0 4323
3eacf866
AS
4324 cfg = wiphy_priv(wiphy);
4325 cfg->wiphy = wiphy;
27a68fe3 4326 cfg->pub = drvr;
3eacf866
AS
4327 INIT_LIST_HEAD(&cfg->vif_list);
4328
4329 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
4330 if (IS_ERR(vif)) {
4331 wiphy_free(wiphy);
4332 return NULL;
4333 }
4334
27a68fe3 4335 err = wl_init_priv(cfg);
5b435de0
AS
4336 if (err) {
4337 WL_ERR("Failed to init iwm_priv (%d)\n", err);
4338 goto cfg80211_attach_out;
4339 }
5b435de0 4340
3eacf866 4341 ifp->vif = vif;
27a68fe3 4342 return cfg;
5b435de0
AS
4343
4344cfg80211_attach_out:
3eacf866 4345 brcmf_free_vif(vif);
5b435de0
AS
4346 return NULL;
4347}
4348
27a68fe3 4349void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
5b435de0 4350{
3eacf866
AS
4351 struct brcmf_cfg80211_vif *vif;
4352 struct brcmf_cfg80211_vif *tmp;
4353
27a68fe3 4354 wl_deinit_priv(cfg);
3eacf866
AS
4355 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4356 brcmf_free_vif(vif);
4357 }
5b435de0
AS
4358}
4359
5b435de0
AS
4360static s32
4361brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
4362{
ac24be6f 4363 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 4364 s32 err = 0;
f588bc0c
AS
4365 __le32 roamtrigger[2];
4366 __le32 roam_delta[2];
5b435de0
AS
4367
4368 /*
4369 * Setup timeout if Beacons are lost and roam is
4370 * off to report link down
4371 */
4372 if (roamvar) {
ac24be6f 4373 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5b435de0
AS
4374 if (err) {
4375 WL_ERR("bcn_timeout error (%d)\n", err);
4376 goto dongle_rom_out;
4377 }
4378 }
4379
4380 /*
4381 * Enable/Disable built-in roaming to allow supplicant
4382 * to take care of roaming
4383 */
4384 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
ac24be6f 4385 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
5b435de0
AS
4386 if (err) {
4387 WL_ERR("roam_off error (%d)\n", err);
4388 goto dongle_rom_out;
4389 }
4390
f588bc0c
AS
4391 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4392 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4393 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
81f5dcb8 4394 (void *)roamtrigger, sizeof(roamtrigger));
5b435de0
AS
4395 if (err) {
4396 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
4397 goto dongle_rom_out;
4398 }
4399
f588bc0c
AS
4400 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4401 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
ac24be6f 4402 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
81f5dcb8 4403 (void *)roam_delta, sizeof(roam_delta));
5b435de0
AS
4404 if (err) {
4405 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
4406 goto dongle_rom_out;
4407 }
4408
4409dongle_rom_out:
4410 return err;
4411}
4412
4413static s32
4414brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
c68cdc0f 4415 s32 scan_unassoc_time, s32 scan_passive_time)
5b435de0 4416{
ac24be6f 4417 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0
AS
4418 s32 err = 0;
4419
ac24be6f 4420 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
81f5dcb8 4421 scan_assoc_time);
5b435de0
AS
4422 if (err) {
4423 if (err == -EOPNOTSUPP)
4424 WL_INFO("Scan assoc time is not supported\n");
4425 else
4426 WL_ERR("Scan assoc time error (%d)\n", err);
4427 goto dongle_scantime_out;
4428 }
ac24be6f 4429 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
81f5dcb8 4430 scan_unassoc_time);
5b435de0
AS
4431 if (err) {
4432 if (err == -EOPNOTSUPP)
4433 WL_INFO("Scan unassoc time is not supported\n");
4434 else
4435 WL_ERR("Scan unassoc time error (%d)\n", err);
4436 goto dongle_scantime_out;
4437 }
4438
ac24be6f 4439 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
81f5dcb8 4440 scan_passive_time);
5b435de0
AS
4441 if (err) {
4442 if (err == -EOPNOTSUPP)
4443 WL_INFO("Scan passive time is not supported\n");
4444 else
4445 WL_ERR("Scan passive time error (%d)\n", err);
4446 goto dongle_scantime_out;
4447 }
4448
4449dongle_scantime_out:
4450 return err;
4451}
4452
27a68fe3 4453static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
5b435de0 4454{
ac24be6f 4455 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0
AS
4456 struct wiphy *wiphy;
4457 s32 phy_list;
4458 s8 phy;
4459 s32 err = 0;
4460
ac24be6f 4461 err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
81f5dcb8 4462 &phy_list, sizeof(phy_list));
5b435de0
AS
4463 if (err) {
4464 WL_ERR("error (%d)\n", err);
4465 return err;
4466 }
4467
3ba81376 4468 phy = ((char *)&phy_list)[0];
5b435de0
AS
4469 WL_INFO("%c phy\n", phy);
4470 if (phy == 'n' || phy == 'a') {
27a68fe3 4471 wiphy = cfg_to_wiphy(cfg);
5b435de0
AS
4472 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4473 }
4474
4475 return err;
4476}
4477
27a68fe3 4478static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
5b435de0 4479{
27a68fe3 4480 return wl_update_wiphybands(cfg);
5b435de0
AS
4481}
4482
27a68fe3 4483static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5b435de0
AS
4484{
4485 struct net_device *ndev;
4486 struct wireless_dev *wdev;
4487 s32 power_mode;
4488 s32 err = 0;
4489
27a68fe3 4490 if (cfg->dongle_up)
5b435de0
AS
4491 return err;
4492
27a68fe3 4493 ndev = cfg_to_ndev(cfg);
5b435de0
AS
4494 wdev = ndev->ieee80211_ptr;
4495
4496 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
4497 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
4498
27a68fe3 4499 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
ac24be6f
AS
4500 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
4501 power_mode);
5b435de0
AS
4502 if (err)
4503 goto default_conf_out;
4504 WL_INFO("power save set to %s\n",
4505 (power_mode ? "enabled" : "disabled"));
4506
27a68fe3 4507 err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
5b435de0
AS
4508 WL_BEACON_TIMEOUT);
4509 if (err)
4510 goto default_conf_out;
5dd161ff
FL
4511 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4512 NULL, NULL);
5b435de0
AS
4513 if (err && err != -EINPROGRESS)
4514 goto default_conf_out;
27a68fe3 4515 err = brcmf_dongle_probecap(cfg);
5b435de0
AS
4516 if (err)
4517 goto default_conf_out;
4518
4519 /* -EINPROGRESS: Call commit handler */
4520
4521default_conf_out:
4522
27a68fe3 4523 cfg->dongle_up = true;
5b435de0
AS
4524
4525 return err;
4526
4527}
4528
27a68fe3 4529static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 4530{
c1179033 4531 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5b435de0 4532
c1179033 4533 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 4534
f0799895 4535 return brcmf_config_dongle(cfg);
5b435de0
AS
4536}
4537
27a68fe3 4538static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 4539{
c1179033
AS
4540 struct net_device *ndev = cfg_to_ndev(cfg);
4541 struct brcmf_if *ifp = netdev_priv(ndev);
4542
5b435de0
AS
4543 /*
4544 * While going down, if associated with AP disassociate
4545 * from AP to save power
4546 */
c1179033
AS
4547 if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
4548 test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
ce81e317 4549 check_vif_up(ifp->vif)) {
5b435de0 4550 WL_INFO("Disassociating from AP");
27a68fe3 4551 brcmf_link_down(cfg);
5b435de0
AS
4552
4553 /* Make sure WPA_Supplicant receives all the event
4554 generated due to DISASSOC call to the fw to keep
4555 the state fw and WPA_Supplicant state consistent
4556 */
4557 brcmf_delay(500);
4558 }
4559
27a68fe3 4560 brcmf_abort_scanning(cfg);
c1179033 4561 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5b435de0 4562
5b435de0
AS
4563 return 0;
4564}
4565
27a68fe3 4566s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
5b435de0 4567{
5b435de0
AS
4568 s32 err = 0;
4569
27a68fe3
AS
4570 mutex_lock(&cfg->usr_sync);
4571 err = __brcmf_cfg80211_up(cfg);
4572 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
4573
4574 return err;
4575}
4576
27a68fe3 4577s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
5b435de0 4578{
5b435de0
AS
4579 s32 err = 0;
4580
27a68fe3
AS
4581 mutex_lock(&cfg->usr_sync);
4582 err = __brcmf_cfg80211_down(cfg);
4583 mutex_unlock(&cfg->usr_sync);
5b435de0
AS
4584
4585 return err;
4586}
4587
This page took 0.370333 seconds and 5 git commands to generate.