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