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