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