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