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