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