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