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