blob: be1985296bdc75e725cdc161aa4101cea4a19476 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020022#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020023#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020024
25#include <brcmu_utils.h>
26#include <defs.h>
27#include <brcmu_wifi.h>
28#include "dhd.h"
Arend van Spriel16886732012-12-05 15:26:04 +010029#include "dhd_dbg.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020030#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010031#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010032#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020033#include "btcoex.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020034#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070035#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020036
Arend van Spriele5806072012-09-19 22:21:08 +020037#define BRCMF_SCAN_IE_LEN_MAX 2048
38#define BRCMF_PNO_VERSION 2
39#define BRCMF_PNO_TIME 30
40#define BRCMF_PNO_REPEAT 4
41#define BRCMF_PNO_FREQ_EXPO_MAX 3
42#define BRCMF_PNO_MAX_PFN_COUNT 16
43#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
44#define BRCMF_PNO_HIDDEN_BIT 2
45#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
46#define BRCMF_PNO_SCAN_COMPLETE 1
47#define BRCMF_PNO_SCAN_INCOMPLETE 0
48
Arend van Spriel9f440b72013-02-08 15:53:36 +010049#define BRCMF_IFACE_MAX_CNT 3
Arend van Spriel3eacf862012-10-22 13:55:30 -070050
Hante Meuleman1a873342012-09-27 14:17:54 +020051#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
Hante Meuleman89286dc2013-02-08 15:53:46 +010055#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020056
57#define VS_IE_FIXED_HDR_LEN 6
58#define WPA_IE_VERSION_LEN 2
59#define WPA_IE_MIN_OUI_LEN 4
60#define WPA_IE_SUITE_COUNT_LEN 2
61
62#define WPA_CIPHER_NONE 0 /* None */
63#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
64#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
65#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
66#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
67
68#define RSN_AKM_NONE 0 /* None (IBSS) */
69#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
70#define RSN_AKM_PSK 2 /* Pre-shared Key */
71#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
72#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
73
74#define VNDR_IE_CMD_LEN 4 /* length of the set command
75 * string :"add", "del" (+ NUL)
76 */
77#define VNDR_IE_COUNT_OFFSET 4
78#define VNDR_IE_PKTFLAG_OFFSET 8
79#define VNDR_IE_VSIE_OFFSET 12
80#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010081#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
84#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020085
Hante Meuleman89286dc2013-02-08 15:53:46 +010086#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
87#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
88#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
89
Arend van Spriel5b435de2011-10-05 13:19:03 +020090#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
91 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
92
Arend van Sprielce81e312012-10-22 13:55:37 -070093static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020094{
Arend van Sprielc1179032012-10-22 13:55:33 -070095 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010096 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
97 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020098 return false;
99 }
100 return true;
101}
102
103#define CHAN2G(_channel, _freq, _flags) { \
104 .band = IEEE80211_BAND_2GHZ, \
105 .center_freq = (_freq), \
106 .hw_value = (_channel), \
107 .flags = (_flags), \
108 .max_antenna_gain = 0, \
109 .max_power = 30, \
110}
111
112#define CHAN5G(_channel, _flags) { \
113 .band = IEEE80211_BAND_5GHZ, \
114 .center_freq = 5000 + (5 * (_channel)), \
115 .hw_value = (_channel), \
116 .flags = (_flags), \
117 .max_antenna_gain = 0, \
118 .max_power = 30, \
119}
120
121#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
122#define RATETAB_ENT(_rateid, _flags) \
123 { \
124 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
125 .hw_value = (_rateid), \
126 .flags = (_flags), \
127 }
128
129static struct ieee80211_rate __wl_rates[] = {
130 RATETAB_ENT(BRCM_RATE_1M, 0),
131 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
132 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
133 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
134 RATETAB_ENT(BRCM_RATE_6M, 0),
135 RATETAB_ENT(BRCM_RATE_9M, 0),
136 RATETAB_ENT(BRCM_RATE_12M, 0),
137 RATETAB_ENT(BRCM_RATE_18M, 0),
138 RATETAB_ENT(BRCM_RATE_24M, 0),
139 RATETAB_ENT(BRCM_RATE_36M, 0),
140 RATETAB_ENT(BRCM_RATE_48M, 0),
141 RATETAB_ENT(BRCM_RATE_54M, 0),
142};
143
144#define wl_a_rates (__wl_rates + 4)
145#define wl_a_rates_size 8
146#define wl_g_rates (__wl_rates + 0)
147#define wl_g_rates_size 12
148
149static struct ieee80211_channel __wl_2ghz_channels[] = {
150 CHAN2G(1, 2412, 0),
151 CHAN2G(2, 2417, 0),
152 CHAN2G(3, 2422, 0),
153 CHAN2G(4, 2427, 0),
154 CHAN2G(5, 2432, 0),
155 CHAN2G(6, 2437, 0),
156 CHAN2G(7, 2442, 0),
157 CHAN2G(8, 2447, 0),
158 CHAN2G(9, 2452, 0),
159 CHAN2G(10, 2457, 0),
160 CHAN2G(11, 2462, 0),
161 CHAN2G(12, 2467, 0),
162 CHAN2G(13, 2472, 0),
163 CHAN2G(14, 2484, 0),
164};
165
166static struct ieee80211_channel __wl_5ghz_a_channels[] = {
167 CHAN5G(34, 0), CHAN5G(36, 0),
168 CHAN5G(38, 0), CHAN5G(40, 0),
169 CHAN5G(42, 0), CHAN5G(44, 0),
170 CHAN5G(46, 0), CHAN5G(48, 0),
171 CHAN5G(52, 0), CHAN5G(56, 0),
172 CHAN5G(60, 0), CHAN5G(64, 0),
173 CHAN5G(100, 0), CHAN5G(104, 0),
174 CHAN5G(108, 0), CHAN5G(112, 0),
175 CHAN5G(116, 0), CHAN5G(120, 0),
176 CHAN5G(124, 0), CHAN5G(128, 0),
177 CHAN5G(132, 0), CHAN5G(136, 0),
178 CHAN5G(140, 0), CHAN5G(149, 0),
179 CHAN5G(153, 0), CHAN5G(157, 0),
180 CHAN5G(161, 0), CHAN5G(165, 0),
181 CHAN5G(184, 0), CHAN5G(188, 0),
182 CHAN5G(192, 0), CHAN5G(196, 0),
183 CHAN5G(200, 0), CHAN5G(204, 0),
184 CHAN5G(208, 0), CHAN5G(212, 0),
185 CHAN5G(216, 0),
186};
187
Arend van Spriel5b435de2011-10-05 13:19:03 +0200188static struct ieee80211_supported_band __wl_band_2ghz = {
189 .band = IEEE80211_BAND_2GHZ,
190 .channels = __wl_2ghz_channels,
191 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
192 .bitrates = wl_g_rates,
193 .n_bitrates = wl_g_rates_size,
Daniel Kimd2353672014-03-20 10:18:00 +0100194 .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true},
Arend van Spriel5b435de2011-10-05 13:19:03 +0200195};
196
197static struct ieee80211_supported_band __wl_band_5ghz_a = {
198 .band = IEEE80211_BAND_5GHZ,
199 .channels = __wl_5ghz_a_channels,
200 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
201 .bitrates = wl_a_rates,
202 .n_bitrates = wl_a_rates_size,
203};
204
Hante Meulemand48200b2013-04-03 12:40:29 +0200205/* This is to override regulatory domains defined in cfg80211 module (reg.c)
206 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200207 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
208 * With respect to these flags, wpa_supplicant doesn't * start p2p
209 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200210 * domain are to be done here.
211 */
212static const struct ieee80211_regdomain brcmf_regdom = {
213 .n_reg_rules = 4,
214 .alpha2 = "99",
215 .reg_rules = {
216 /* IEEE 802.11b/g, channels 1..11 */
217 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
218 /* If any */
219 /* IEEE 802.11 channel 14 - Only JP enables
220 * this and for 802.11b only
221 */
222 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
223 /* IEEE 802.11a, channel 36..64 */
224 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
225 /* IEEE 802.11a, channel 100..165 */
226 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200227};
228
229static const u32 __wl_cipher_suites[] = {
230 WLAN_CIPHER_SUITE_WEP40,
231 WLAN_CIPHER_SUITE_WEP104,
232 WLAN_CIPHER_SUITE_TKIP,
233 WLAN_CIPHER_SUITE_CCMP,
234 WLAN_CIPHER_SUITE_AES_CMAC,
235};
236
Hante Meuleman1a873342012-09-27 14:17:54 +0200237/* Vendor specific ie. id = 221, oui and type defines exact ie */
238struct brcmf_vs_tlv {
239 u8 id;
240 u8 len;
241 u8 oui[3];
242 u8 oui_type;
243};
244
245struct parsed_vndr_ie_info {
246 u8 *ie_ptr;
247 u32 ie_len; /* total length including id & length field */
248 struct brcmf_vs_tlv vndrie;
249};
250
251struct parsed_vndr_ies {
252 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100253 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200254};
255
Hante Meuleman68ca3952014-02-25 20:30:26 +0100256static int brcmf_roamoff;
257module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
258MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
259
Alwin Beukersef6ac172011-10-12 20:51:26 +0200260/* Quarter dBm units to mW
261 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
262 * Table is offset so the last entry is largest mW value that fits in
263 * a u16.
264 */
265
266#define QDBM_OFFSET 153 /* Offset for first entry */
267#define QDBM_TABLE_LEN 40 /* Table size */
268
269/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
270 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
271 */
272#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
273
274/* Largest mW value that will round down to the last table entry,
275 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
276 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
277 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
278 */
279#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
280
281static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
282/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
283/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
284/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
285/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
286/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
287/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
288};
289
290static u16 brcmf_qdbm_to_mw(u8 qdbm)
291{
292 uint factor = 1;
293 int idx = qdbm - QDBM_OFFSET;
294
295 if (idx >= QDBM_TABLE_LEN)
296 /* clamp to max u16 mW value */
297 return 0xFFFF;
298
299 /* scale the qdBm index up to the range of the table 0-40
300 * where an offset of 40 qdBm equals a factor of 10 mW.
301 */
302 while (idx < 0) {
303 idx += 40;
304 factor *= 10;
305 }
306
307 /* return the mW value scaled down to the correct factor of 10,
308 * adding in factor/2 to get proper rounding.
309 */
310 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
311}
312
313static u8 brcmf_mw_to_qdbm(u16 mw)
314{
315 u8 qdbm;
316 int offset;
317 uint mw_uint = mw;
318 uint boundary;
319
320 /* handle boundary case */
321 if (mw_uint <= 1)
322 return 0;
323
324 offset = QDBM_OFFSET;
325
326 /* move mw into the range of the table */
327 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
328 mw_uint *= 10;
329 offset -= 40;
330 }
331
332 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
333 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
334 nqdBm_to_mW_map[qdbm]) / 2;
335 if (mw_uint < boundary)
336 break;
337 }
338
339 qdbm += (u8) offset;
340
341 return qdbm;
342}
343
Franky Lin83cf17a2013-04-11 13:28:50 +0200344u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
345 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700346{
Franky Lin83cf17a2013-04-11 13:28:50 +0200347 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700348
Franky Lin83cf17a2013-04-11 13:28:50 +0200349 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
350 ch_inf.bw = BRCMU_CHAN_BW_20;
351 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700352
Franky Lin83cf17a2013-04-11 13:28:50 +0200353 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700354}
355
Hante Meuleman89286dc2013-02-08 15:53:46 +0100356/* Traverse a string of 1-byte tag/1-byte length/variable-length value
357 * triples, returning a pointer to the substring whose first element
358 * matches tag
359 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100360const struct brcmf_tlv *
361brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100362{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100363 const struct brcmf_tlv *elt = buf;
364 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100365
366 /* find tagged parameter */
367 while (totlen >= TLV_HDR_LEN) {
368 int len = elt->len;
369
370 /* validate remaining totlen */
371 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
372 return elt;
373
374 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
375 totlen -= (len + TLV_HDR_LEN);
376 }
377
378 return NULL;
379}
380
381/* Is any of the tlvs the expected entry? If
382 * not update the tlvs buffer pointer/length.
383 */
384static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100385brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
386 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100387{
388 /* If the contents match the OUI and the type */
389 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
390 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
391 type == ie[TLV_BODY_OFF + oui_len]) {
392 return true;
393 }
394
395 if (tlvs == NULL)
396 return false;
397 /* point to the next ie */
398 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
399 /* calculate the length of the rest of the buffer */
400 *tlvs_len -= (int)(ie - *tlvs);
401 /* update the pointer to the start of the buffer */
402 *tlvs = ie;
403
404 return false;
405}
406
407static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100408brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100409{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100410 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100411
412 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100413 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100414 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
415 return (struct brcmf_vs_tlv *)ie;
416 }
417 return NULL;
418}
419
420static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100421brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100422{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100423 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100424
425 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
426 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
427 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
428 return (struct brcmf_vs_tlv *)ie;
429 }
430 return NULL;
431}
432
433
Arend van Spriel5b435de2011-10-05 13:19:03 +0200434static void convert_key_from_CPU(struct brcmf_wsec_key *key,
435 struct brcmf_wsec_key_le *key_le)
436{
437 key_le->index = cpu_to_le32(key->index);
438 key_le->len = cpu_to_le32(key->len);
439 key_le->algo = cpu_to_le32(key->algo);
440 key_le->flags = cpu_to_le32(key->flags);
441 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
442 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
443 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
444 memcpy(key_le->data, key->data, sizeof(key->data));
445 memcpy(key_le->ea, key->ea, sizeof(key->ea));
446}
447
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200448static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700449send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200450{
451 int err;
452 struct brcmf_wsec_key_le key_le;
453
454 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200455
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700456 brcmf_netdev_wait_pend8021x(ndev);
457
Arend van Sprielac24be62012-10-22 10:36:23 -0700458 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700459 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200460
Arend van Spriel5b435de2011-10-05 13:19:03 +0200461 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100462 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200463 return err;
464}
465
Hante Meulemanb3657452013-05-27 21:09:53 +0200466static s32
467brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
468{
469 s32 err;
470 u32 mode;
471
472 if (enable)
473 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
474 else
475 mode = 0;
476
477 /* Try to set and enable ARP offload feature, this may fail, then it */
478 /* is simply not supported and err 0 will be returned */
479 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
480 if (err) {
481 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
482 mode, err);
483 err = 0;
484 } else {
485 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
486 if (err) {
487 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
488 enable, err);
489 err = 0;
490 } else
491 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
492 enable, mode);
493 }
494
495 return err;
496}
497
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100498static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
499{
500 enum nl80211_iftype iftype;
501
502 iftype = vif->wdev.iftype;
503 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
504}
505
506static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
507{
508 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
509}
510
Arend van Spriel9f440b72013-02-08 15:53:36 +0100511static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
512 const char *name,
513 enum nl80211_iftype type,
514 u32 *flags,
515 struct vif_params *params)
516{
517 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
518 switch (type) {
519 case NL80211_IFTYPE_ADHOC:
520 case NL80211_IFTYPE_STATION:
521 case NL80211_IFTYPE_AP:
522 case NL80211_IFTYPE_AP_VLAN:
523 case NL80211_IFTYPE_WDS:
524 case NL80211_IFTYPE_MONITOR:
525 case NL80211_IFTYPE_MESH_POINT:
526 return ERR_PTR(-EOPNOTSUPP);
527 case NL80211_IFTYPE_P2P_CLIENT:
528 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200529 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100530 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
531 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100532 default:
533 return ERR_PTR(-EINVAL);
534 }
535}
536
Arend van Sprielf96aa072013-04-05 10:57:48 +0200537void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100538{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100539 s32 err = 0;
540
541 if (check_vif_up(ifp->vif)) {
542 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
543 if (err) {
544 brcmf_err("fail to set mpc\n");
545 return;
546 }
547 brcmf_dbg(INFO, "MPC : %d\n", mpc);
548 }
549}
550
Arend van Spriela0f472a2013-04-05 10:57:49 +0200551s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
552 struct brcmf_if *ifp, bool aborted,
553 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100554{
555 struct brcmf_scan_params_le params_le;
556 struct cfg80211_scan_request *scan_request;
557 s32 err = 0;
558
559 brcmf_dbg(SCAN, "Enter\n");
560
561 /* clear scan request, because the FW abort can cause a second call */
562 /* to this functon and might cause a double cfg80211_scan_done */
563 scan_request = cfg->scan_request;
564 cfg->scan_request = NULL;
565
566 if (timer_pending(&cfg->escan_timeout))
567 del_timer_sync(&cfg->escan_timeout);
568
569 if (fw_abort) {
570 /* Do a scan abort to stop the driver's scan engine */
571 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
572 memset(&params_le, 0, sizeof(params_le));
573 memset(params_le.bssid, 0xFF, ETH_ALEN);
574 params_le.bss_type = DOT11_BSSTYPE_ANY;
575 params_le.scan_type = 0;
576 params_le.channel_num = cpu_to_le32(1);
577 params_le.nprobes = cpu_to_le32(1);
578 params_le.active_time = cpu_to_le32(-1);
579 params_le.passive_time = cpu_to_le32(-1);
580 params_le.home_time = cpu_to_le32(-1);
581 /* Scan is aborted by setting channel_list[0] to -1 */
582 params_le.channel_list[0] = cpu_to_le16(-1);
583 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200584 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100585 &params_le, sizeof(params_le));
586 if (err)
587 brcmf_err("Scan abort failed\n");
588 }
589 /*
590 * e-scan can be initiated by scheduled scan
591 * which takes precedence.
592 */
593 if (cfg->sched_escan) {
594 brcmf_dbg(SCAN, "scheduled scan completed\n");
595 cfg->sched_escan = false;
596 if (!aborted)
597 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Sprielf96aa072013-04-05 10:57:48 +0200598 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100599 } else if (scan_request) {
600 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
601 aborted ? "Aborted" : "Done");
602 cfg80211_scan_done(scan_request, aborted);
Arend van Sprielf96aa072013-04-05 10:57:48 +0200603 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100604 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100605 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
606 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100607
608 return err;
609}
610
Arend van Spriel9f440b72013-02-08 15:53:36 +0100611static
612int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
613{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100614 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
615 struct net_device *ndev = wdev->netdev;
616
617 /* vif event pending in firmware */
618 if (brcmf_cfg80211_vif_event_armed(cfg))
619 return -EBUSY;
620
621 if (ndev) {
622 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200623 cfg->escan_info.ifp == netdev_priv(ndev))
624 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
625 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100626
627 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
628 }
629
Arend van Spriel9f440b72013-02-08 15:53:36 +0100630 switch (wdev->iftype) {
631 case NL80211_IFTYPE_ADHOC:
632 case NL80211_IFTYPE_STATION:
633 case NL80211_IFTYPE_AP:
634 case NL80211_IFTYPE_AP_VLAN:
635 case NL80211_IFTYPE_WDS:
636 case NL80211_IFTYPE_MONITOR:
637 case NL80211_IFTYPE_MESH_POINT:
638 return -EOPNOTSUPP;
639 case NL80211_IFTYPE_P2P_CLIENT:
640 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200641 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100642 return brcmf_p2p_del_vif(wiphy, wdev);
643 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100644 default:
645 return -EINVAL;
646 }
647 return -EOPNOTSUPP;
648}
649
Arend van Spriel5b435de2011-10-05 13:19:03 +0200650static s32
651brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
652 enum nl80211_iftype type, u32 *flags,
653 struct vif_params *params)
654{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100655 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700656 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100657 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200658 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200659 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200660 s32 err = 0;
661
Arend van Sprield96b8012012-12-05 15:26:02 +0100662 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200663
664 switch (type) {
665 case NL80211_IFTYPE_MONITOR:
666 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100667 brcmf_err("type (%d) : currently we do not support this type\n",
668 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200669 return -EOPNOTSUPP;
670 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200671 infra = 0;
672 break;
673 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100674 /* Ignore change for p2p IF. Unclear why supplicant does this */
675 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
676 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
677 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
678 /* WAR: It is unexpected to get a change of VIF for P2P
679 * IF, but it happens. The request can not be handled
680 * but returning EPERM causes a crash. Returning 0
681 * without setting ieee80211_ptr->iftype causes trace
682 * (WARN_ON) but it works with wpa_supplicant
683 */
684 return 0;
685 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200686 infra = 1;
687 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200688 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100689 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200690 ap = 1;
691 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200692 default:
693 err = -EINVAL;
694 goto done;
695 }
696
Hante Meuleman1a873342012-09-27 14:17:54 +0200697 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100698 if (type == NL80211_IFTYPE_P2P_GO) {
699 brcmf_dbg(INFO, "IF Type = P2P GO\n");
700 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
701 }
702 if (!err) {
703 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
704 brcmf_dbg(INFO, "IF Type = AP\n");
705 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200706 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100707 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200708 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100709 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200710 err = -EAGAIN;
711 goto done;
712 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100713 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100714 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200715 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200716 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200717
718done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100719 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200720
721 return err;
722}
723
Franky Lin83cf17a2013-04-11 13:28:50 +0200724static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
725 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200726 struct cfg80211_scan_request *request)
727{
728 u32 n_ssids;
729 u32 n_channels;
730 s32 i;
731 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200732 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200733 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200734 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200735
Arend van Sprielba40d162012-10-22 13:55:38 -0700736 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200737 params_le->bss_type = DOT11_BSSTYPE_ANY;
738 params_le->scan_type = 0;
739 params_le->channel_num = 0;
740 params_le->nprobes = cpu_to_le32(-1);
741 params_le->active_time = cpu_to_le32(-1);
742 params_le->passive_time = cpu_to_le32(-1);
743 params_le->home_time = cpu_to_le32(-1);
744 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
745
746 /* if request is null exit so it will be all channel broadcast scan */
747 if (!request)
748 return;
749
750 n_ssids = request->n_ssids;
751 n_channels = request->n_channels;
752 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100753 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
754 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200755 if (n_channels > 0) {
756 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200757 chanspec = channel_to_chanspec(&cfg->d11inf,
758 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100759 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
760 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200761 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200762 }
763 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100764 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200765 }
766 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100767 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200768 if (n_ssids > 0) {
769 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
770 n_channels * sizeof(u16);
771 offset = roundup(offset, sizeof(u32));
772 ptr = (char *)params_le + offset;
773 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200774 memset(&ssid_le, 0, sizeof(ssid_le));
775 ssid_le.SSID_len =
776 cpu_to_le32(request->ssids[i].ssid_len);
777 memcpy(ssid_le.SSID, request->ssids[i].ssid,
778 request->ssids[i].ssid_len);
779 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100780 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200781 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100782 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
783 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200784 memcpy(ptr, &ssid_le, sizeof(ssid_le));
785 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200786 }
787 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100788 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200789 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100790 brcmf_dbg(SCAN, "SSID %s len=%d\n",
791 params_le->ssid_le.SSID,
792 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200793 params_le->ssid_le.SSID_len =
794 cpu_to_le32(request->ssids->ssid_len);
795 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
796 request->ssids->ssid_len);
797 }
798 }
799 /* Adding mask to channel numbers */
800 params_le->channel_num =
801 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
802 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
803}
804
805static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200806brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +0200807 struct cfg80211_scan_request *request, u16 action)
808{
809 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
810 offsetof(struct brcmf_escan_params_le, params_le);
811 struct brcmf_escan_params_le *params;
812 s32 err = 0;
813
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100814 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200815
816 if (request != NULL) {
817 /* Allocate space for populating ssids in struct */
818 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
819
820 /* Allocate space for populating ssids in struct */
821 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
822 }
823
824 params = kzalloc(params_size, GFP_KERNEL);
825 if (!params) {
826 err = -ENOMEM;
827 goto exit;
828 }
829 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +0200830 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200831 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
832 params->action = cpu_to_le16(action);
833 params->sync_id = cpu_to_le16(0x1234);
834
Arend van Spriela0f472a2013-04-05 10:57:49 +0200835 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200836 if (err) {
837 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100838 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200839 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100840 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200841 }
842
843 kfree(params);
844exit:
845 return err;
846}
847
848static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200849brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +0200850 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200851{
852 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700853 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200854 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100855 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200856
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100857 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200858 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100859 escan->wiphy = wiphy;
860 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700861 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +0200862 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700863 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200864 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100865 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200866 return err;
867 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200868 brcmf_set_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200869 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200870 results->version = 0;
871 results->count = 0;
872 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
873
Arend van Spriela0f472a2013-04-05 10:57:49 +0200874 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200875 if (err)
Arend van Sprielf96aa072013-04-05 10:57:48 +0200876 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200877 return err;
878}
879
880static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200881brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +0200882 struct cfg80211_scan_request *request,
883 struct cfg80211_ssid *this_ssid)
884{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200885 struct brcmf_if *ifp = vif->ifp;
886 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +0200887 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800888 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700889 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200890 bool escan_req;
891 bool spec_scan;
892 s32 err;
893 u32 SSID_len;
894
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100895 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200896
Arend van Sprielc1179032012-10-22 13:55:33 -0700897 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100898 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200899 return -EAGAIN;
900 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700901 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100902 brcmf_err("Scanning being aborted: status (%lu)\n",
903 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200904 return -EAGAIN;
905 }
Arend van Spriel1687eee2013-04-23 12:53:11 +0200906 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
907 brcmf_err("Scanning suppressed: status (%lu)\n",
908 cfg->scan_status);
909 return -EAGAIN;
910 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700911 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100912 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200913 return -EAGAIN;
914 }
915
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100916 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +0200917 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
918 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100919
Hante Meulemane756af52012-09-11 21:18:52 +0200920 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200921 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200922 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
923
924 escan_req = false;
925 if (request) {
926 /* scan bss */
927 ssids = request->ssids;
928 escan_req = true;
929 } else {
930 /* scan in ibss */
931 /* we don't do escan in ibss */
932 ssids = this_ssid;
933 }
934
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200935 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700936 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200937 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100938 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +0200939 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100940 if (err)
941 goto scan_out;
942
Arend van Spriela0f472a2013-04-05 10:57:49 +0200943 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800944 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200945 goto scan_out;
946 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100947 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
948 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200949 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
950 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
951 sr->ssid_le.SSID_len = cpu_to_le32(0);
952 spec_scan = false;
953 if (SSID_len) {
954 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
955 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
956 spec_scan = true;
957 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100958 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200959
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700960 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700961 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700962 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200963 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100964 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200965 goto scan_out;
966 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200967 brcmf_set_mpc(ifp, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700968 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700969 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200970 if (err) {
971 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100972 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
973 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200974 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100975 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200976
Arend van Sprielf96aa072013-04-05 10:57:48 +0200977 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200978 goto scan_out;
979 }
980 }
981
982 return 0;
983
984scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700985 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200986 if (timer_pending(&cfg->escan_timeout))
987 del_timer_sync(&cfg->escan_timeout);
988 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200989 return err;
990}
991
Arend van Spriel5b435de2011-10-05 13:19:03 +0200992static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700993brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200994{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200995 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200996 s32 err = 0;
997
Arend van Sprield96b8012012-12-05 15:26:02 +0100998 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200999 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1000 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001001 return -EIO;
1002
Arend van Spriela0f472a2013-04-05 10:57:49 +02001003 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001004
Arend van Spriel5b435de2011-10-05 13:19:03 +02001005 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001006 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001007
Arend van Sprield96b8012012-12-05 15:26:02 +01001008 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001009 return err;
1010}
1011
1012static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1013{
1014 s32 err = 0;
1015
Arend van Sprielac24be62012-10-22 10:36:23 -07001016 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1017 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001018 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001019 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001020
1021 return err;
1022}
1023
1024static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1025{
1026 s32 err = 0;
1027
Arend van Sprielac24be62012-10-22 10:36:23 -07001028 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1029 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001030 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001031 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001032
1033 return err;
1034}
1035
1036static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1037{
1038 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001039 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001040
Arend van Sprielac24be62012-10-22 10:36:23 -07001041 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001042 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001043 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001044 return err;
1045 }
1046 return err;
1047}
1048
1049static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1050{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001051 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1052 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001053 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001054 s32 err = 0;
1055
Arend van Sprield96b8012012-12-05 15:26:02 +01001056 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001057 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001058 return -EIO;
1059
1060 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001061 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1062 cfg->conf->rts_threshold = wiphy->rts_threshold;
1063 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001064 if (!err)
1065 goto done;
1066 }
1067 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001068 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1069 cfg->conf->frag_threshold = wiphy->frag_threshold;
1070 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001071 if (!err)
1072 goto done;
1073 }
1074 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001075 && (cfg->conf->retry_long != wiphy->retry_long)) {
1076 cfg->conf->retry_long = wiphy->retry_long;
1077 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001078 if (!err)
1079 goto done;
1080 }
1081 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001082 && (cfg->conf->retry_short != wiphy->retry_short)) {
1083 cfg->conf->retry_short = wiphy->retry_short;
1084 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001085 if (!err)
1086 goto done;
1087 }
1088
1089done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001090 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001091 return err;
1092}
1093
Arend van Spriel5b435de2011-10-05 13:19:03 +02001094static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1095{
1096 memset(prof, 0, sizeof(*prof));
1097}
1098
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001099static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001100{
Piotr Haber61730d42013-04-23 12:53:12 +02001101 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001102 s32 err = 0;
1103
Arend van Sprield96b8012012-12-05 15:26:02 +01001104 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001105
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001106 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001107 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001108 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001109 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001110 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001111 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001112 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001113 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001114 cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
1115
Arend van Spriel5b435de2011-10-05 13:19:03 +02001116 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001117 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001118 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1119 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001120 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001121}
1122
1123static s32
1124brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1125 struct cfg80211_ibss_params *params)
1126{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001127 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001128 struct brcmf_if *ifp = netdev_priv(ndev);
1129 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001130 struct brcmf_join_params join_params;
1131 size_t join_params_size = 0;
1132 s32 err = 0;
1133 s32 wsec = 0;
1134 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001135 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001136
Arend van Sprield96b8012012-12-05 15:26:02 +01001137 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001138 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001139 return -EIO;
1140
1141 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001142 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001143 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001144 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001145 return -EOPNOTSUPP;
1146 }
1147
Arend van Sprielc1179032012-10-22 13:55:33 -07001148 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149
1150 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001151 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152 else
Arend van Spriel16886732012-12-05 15:26:04 +01001153 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154
Johannes Berg683b6d32012-11-08 21:25:48 +01001155 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001156 brcmf_dbg(CONN, "channel: %d\n",
1157 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001158 else
Arend van Spriel16886732012-12-05 15:26:04 +01001159 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160
1161 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001162 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163 else
Arend van Spriel16886732012-12-05 15:26:04 +01001164 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165
1166 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001167 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001168 else
Arend van Spriel16886732012-12-05 15:26:04 +01001169 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170
1171 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001172 brcmf_dbg(CONN, "beacon interval: %d\n",
1173 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001174 else
Arend van Spriel16886732012-12-05 15:26:04 +01001175 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001176
1177 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001178 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179 else
Arend van Spriel16886732012-12-05 15:26:04 +01001180 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001181
1182 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001183 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001184 else
Arend van Spriel16886732012-12-05 15:26:04 +01001185 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001186
1187 /* Configure Privacy for starter */
1188 if (params->privacy)
1189 wsec |= WEP_ENABLED;
1190
Arend van Sprielc1179032012-10-22 13:55:33 -07001191 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001192 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001193 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001194 goto done;
1195 }
1196
1197 /* Configure Beacon Interval for starter */
1198 if (params->beacon_interval)
1199 bcnprd = params->beacon_interval;
1200 else
1201 bcnprd = 100;
1202
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001203 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001204 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001205 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001206 goto done;
1207 }
1208
1209 /* Configure required join parameter */
1210 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1211
1212 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001213 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1214 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1215 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1216 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001217 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001218
1219 /* BSSID */
1220 if (params->bssid) {
1221 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1222 join_params_size = sizeof(join_params.ssid_le) +
1223 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001224 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001225 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001226 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001227 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001228 }
1229
Arend van Spriel5b435de2011-10-05 13:19:03 +02001230 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001231 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001232 u32 target_channel;
1233
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001234 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001236 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237 if (params->channel_fixed) {
1238 /* adding chanspec */
Franky Lin83cf17a2013-04-11 13:28:50 +02001239 chanspec = channel_to_chanspec(&cfg->d11inf,
1240 params->chandef.chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001241 join_params.params_le.chanspec_list[0] =
1242 cpu_to_le16(chanspec);
1243 join_params.params_le.chanspec_num = cpu_to_le32(1);
1244 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001245 }
1246
1247 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001248 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001249 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001250 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001251 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001252 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001253 goto done;
1254 }
1255 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001256 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001257
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001258 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259
1260
Arend van Sprielc1179032012-10-22 13:55:33 -07001261 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001262 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001263 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001264 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001265 goto done;
1266 }
1267
1268done:
1269 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001270 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001271 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 return err;
1273}
1274
1275static s32
1276brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1277{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001278 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001279 s32 err = 0;
1280
Arend van Sprield96b8012012-12-05 15:26:02 +01001281 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001282 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283 return -EIO;
1284
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001285 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001286
Arend van Sprield96b8012012-12-05 15:26:02 +01001287 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288
1289 return err;
1290}
1291
1292static s32 brcmf_set_wpa_version(struct net_device *ndev,
1293 struct cfg80211_connect_params *sme)
1294{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001295 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001296 struct brcmf_cfg80211_security *sec;
1297 s32 val = 0;
1298 s32 err = 0;
1299
1300 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1301 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1302 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1303 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1304 else
1305 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001306 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001307 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001308 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001309 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001310 return err;
1311 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001312 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001313 sec->wpa_versions = sme->crypto.wpa_versions;
1314 return err;
1315}
1316
1317static s32 brcmf_set_auth_type(struct net_device *ndev,
1318 struct cfg80211_connect_params *sme)
1319{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001320 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 struct brcmf_cfg80211_security *sec;
1322 s32 val = 0;
1323 s32 err = 0;
1324
1325 switch (sme->auth_type) {
1326 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1327 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001328 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329 break;
1330 case NL80211_AUTHTYPE_SHARED_KEY:
1331 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001332 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001333 break;
1334 case NL80211_AUTHTYPE_AUTOMATIC:
1335 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001336 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001337 break;
1338 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001339 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001340 default:
1341 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001342 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001343 break;
1344 }
1345
Hante Meuleman89286dc2013-02-08 15:53:46 +01001346 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001347 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001348 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001349 return err;
1350 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001351 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001352 sec->auth_type = sme->auth_type;
1353 return err;
1354}
1355
1356static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001357brcmf_set_wsec_mode(struct net_device *ndev,
1358 struct cfg80211_connect_params *sme, bool mfp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001359{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001360 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001361 struct brcmf_cfg80211_security *sec;
1362 s32 pval = 0;
1363 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001364 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001365 s32 err = 0;
1366
1367 if (sme->crypto.n_ciphers_pairwise) {
1368 switch (sme->crypto.ciphers_pairwise[0]) {
1369 case WLAN_CIPHER_SUITE_WEP40:
1370 case WLAN_CIPHER_SUITE_WEP104:
1371 pval = WEP_ENABLED;
1372 break;
1373 case WLAN_CIPHER_SUITE_TKIP:
1374 pval = TKIP_ENABLED;
1375 break;
1376 case WLAN_CIPHER_SUITE_CCMP:
1377 pval = AES_ENABLED;
1378 break;
1379 case WLAN_CIPHER_SUITE_AES_CMAC:
1380 pval = AES_ENABLED;
1381 break;
1382 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001383 brcmf_err("invalid cipher pairwise (%d)\n",
1384 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001385 return -EINVAL;
1386 }
1387 }
1388 if (sme->crypto.cipher_group) {
1389 switch (sme->crypto.cipher_group) {
1390 case WLAN_CIPHER_SUITE_WEP40:
1391 case WLAN_CIPHER_SUITE_WEP104:
1392 gval = WEP_ENABLED;
1393 break;
1394 case WLAN_CIPHER_SUITE_TKIP:
1395 gval = TKIP_ENABLED;
1396 break;
1397 case WLAN_CIPHER_SUITE_CCMP:
1398 gval = AES_ENABLED;
1399 break;
1400 case WLAN_CIPHER_SUITE_AES_CMAC:
1401 gval = AES_ENABLED;
1402 break;
1403 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001404 brcmf_err("invalid cipher group (%d)\n",
1405 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001406 return -EINVAL;
1407 }
1408 }
1409
Arend van Spriel16886732012-12-05 15:26:04 +01001410 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001411 /* In case of privacy, but no security and WPS then simulate */
1412 /* setting AES. WPS-2.0 allows no security */
1413 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1414 sme->privacy)
1415 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001416
1417 if (mfp)
1418 wsec = pval | gval | MFP_CAPABLE;
1419 else
1420 wsec = pval | gval;
1421 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001422 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001423 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 return err;
1425 }
1426
Arend van Spriel06bb1232012-09-27 14:17:56 +02001427 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001428 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1429 sec->cipher_group = sme->crypto.cipher_group;
1430
1431 return err;
1432}
1433
1434static s32
1435brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1436{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001437 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001438 struct brcmf_cfg80211_security *sec;
1439 s32 val = 0;
1440 s32 err = 0;
1441
1442 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001443 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1444 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001445 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001446 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001447 return err;
1448 }
1449 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1450 switch (sme->crypto.akm_suites[0]) {
1451 case WLAN_AKM_SUITE_8021X:
1452 val = WPA_AUTH_UNSPECIFIED;
1453 break;
1454 case WLAN_AKM_SUITE_PSK:
1455 val = WPA_AUTH_PSK;
1456 break;
1457 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001458 brcmf_err("invalid cipher group (%d)\n",
1459 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001460 return -EINVAL;
1461 }
1462 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1463 switch (sme->crypto.akm_suites[0]) {
1464 case WLAN_AKM_SUITE_8021X:
1465 val = WPA2_AUTH_UNSPECIFIED;
1466 break;
1467 case WLAN_AKM_SUITE_PSK:
1468 val = WPA2_AUTH_PSK;
1469 break;
1470 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001471 brcmf_err("invalid cipher group (%d)\n",
1472 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473 return -EINVAL;
1474 }
1475 }
1476
Arend van Spriel16886732012-12-05 15:26:04 +01001477 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001478 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1479 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001481 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 return err;
1483 }
1484 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001485 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001486 sec->wpa_auth = sme->crypto.akm_suites[0];
1487
1488 return err;
1489}
1490
1491static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001492brcmf_set_sharedkey(struct net_device *ndev,
1493 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001495 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001496 struct brcmf_cfg80211_security *sec;
1497 struct brcmf_wsec_key key;
1498 s32 val;
1499 s32 err = 0;
1500
Arend van Spriel16886732012-12-05 15:26:04 +01001501 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001502
Roland Vossena718e2f2011-10-12 20:51:24 +02001503 if (sme->key_len == 0)
1504 return 0;
1505
Arend van Spriel06bb1232012-09-27 14:17:56 +02001506 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001507 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1508 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001509
1510 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1511 return 0;
1512
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001513 if (!(sec->cipher_pairwise &
1514 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1515 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001516
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001517 memset(&key, 0, sizeof(key));
1518 key.len = (u32) sme->key_len;
1519 key.index = (u32) sme->key_idx;
1520 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001521 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001522 return -EINVAL;
1523 }
1524 memcpy(key.data, sme->key, key.len);
1525 key.flags = BRCMF_PRIMARY_KEY;
1526 switch (sec->cipher_pairwise) {
1527 case WLAN_CIPHER_SUITE_WEP40:
1528 key.algo = CRYPTO_ALGO_WEP1;
1529 break;
1530 case WLAN_CIPHER_SUITE_WEP104:
1531 key.algo = CRYPTO_ALGO_WEP128;
1532 break;
1533 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001534 brcmf_err("Invalid algorithm (%d)\n",
1535 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001536 return -EINVAL;
1537 }
1538 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001539 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1540 key.len, key.index, key.algo);
1541 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001542 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001543 if (err)
1544 return err;
1545
1546 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001547 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001548 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001549 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001550 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001551 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001552 }
1553 return err;
1554}
1555
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001556static
1557enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1558 enum nl80211_auth_type type)
1559{
1560 u32 ci;
1561 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1562 /* shift to ignore chip revision */
1563 ci = brcmf_get_chip_info(ifp) >> 4;
1564 switch (ci) {
1565 case 43236:
1566 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1567 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1568 default:
1569 break;
1570 }
1571 }
1572 return type;
1573}
1574
Arend van Spriel5b435de2011-10-05 13:19:03 +02001575static s32
1576brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001577 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001578{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001579 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001580 struct brcmf_if *ifp = netdev_priv(ndev);
1581 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 struct ieee80211_channel *chan = sme->channel;
1583 struct brcmf_join_params join_params;
1584 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001585 const struct brcmf_tlv *rsn_ie;
1586 const struct brcmf_vs_tlv *wpa_ie;
1587 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001588 u32 ie_len;
1589 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001590 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001591 s32 err = 0;
1592
Arend van Sprield96b8012012-12-05 15:26:02 +01001593 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001594 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001595 return -EIO;
1596
1597 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001598 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 return -EOPNOTSUPP;
1600 }
1601
Hante Meuleman89286dc2013-02-08 15:53:46 +01001602 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1603 /* A normal (non P2P) connection request setup. */
1604 ie = NULL;
1605 ie_len = 0;
1606 /* find the WPA_IE */
1607 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1608 if (wpa_ie) {
1609 ie = wpa_ie;
1610 ie_len = wpa_ie->len + TLV_HDR_LEN;
1611 } else {
1612 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001613 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1614 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001615 WLAN_EID_RSN);
1616 if (rsn_ie) {
1617 ie = rsn_ie;
1618 ie_len = rsn_ie->len + TLV_HDR_LEN;
1619 }
1620 }
1621 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1622 }
1623
1624 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1625 sme->ie, sme->ie_len);
1626 if (err)
1627 brcmf_err("Set Assoc REQ IE Failed\n");
1628 else
1629 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1630
Arend van Sprielc1179032012-10-22 13:55:33 -07001631 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632
1633 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001634 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001635 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001636 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001637 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1638 cfg->channel, chan->center_freq, chanspec);
1639 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001640 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001641 chanspec = 0;
1642 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001643
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001644 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001645
1646 err = brcmf_set_wpa_version(ndev, sme);
1647 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001648 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001649 goto done;
1650 }
1651
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001652 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 err = brcmf_set_auth_type(ndev, sme);
1654 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001655 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001656 goto done;
1657 }
1658
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001659 err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001660 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001661 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001662 goto done;
1663 }
1664
1665 err = brcmf_set_key_mgmt(ndev, sme);
1666 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001667 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001668 goto done;
1669 }
1670
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001671 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001673 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001674 goto done;
1675 }
1676
Hante Meuleman89286dc2013-02-08 15:53:46 +01001677 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1678 (u32)sme->ssid_len);
1679 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1680 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1681 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1682 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1683 profile->ssid.SSID_len);
1684 }
1685
1686 /* Join with specific BSSID and cached SSID
1687 * If SSID is zero join based on BSSID only
1688 */
1689 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1690 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1691 if (cfg->channel)
1692 join_params_size += sizeof(u16);
1693 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1694 if (ext_join_params == NULL) {
1695 err = -ENOMEM;
1696 goto done;
1697 }
1698 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1699 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1700 profile->ssid.SSID_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001701
Hante Meuleman89286dc2013-02-08 15:53:46 +01001702 /* Set up join scan parameters */
1703 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001704 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1705
1706 if (sme->bssid)
1707 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1708 else
1709 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1710
1711 if (cfg->channel) {
1712 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1713
1714 ext_join_params->assoc_le.chanspec_list[0] =
1715 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001716 /* Increase dwell time to receive probe response or detect
1717 * beacon from target AP at a noisy air only during connect
1718 * command.
1719 */
1720 ext_join_params->scan_le.active_time =
1721 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1722 ext_join_params->scan_le.passive_time =
1723 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1724 /* To sync with presence period of VSDB GO send probe request
1725 * more frequently. Probe request will be stopped when it gets
1726 * probe response from target AP/GO.
1727 */
1728 ext_join_params->scan_le.nprobes =
1729 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1730 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1731 } else {
1732 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
1733 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
1734 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001735 }
1736
1737 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1738 join_params_size);
1739 kfree(ext_join_params);
1740 if (!err)
1741 /* This is it. join command worked, we are done */
1742 goto done;
1743
1744 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001745 memset(&join_params, 0, sizeof(join_params));
1746 join_params_size = sizeof(join_params.ssid_le);
1747
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001748 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001749 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001750
Hante Meuleman89286dc2013-02-08 15:53:46 +01001751 if (sme->bssid)
1752 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1753 else
1754 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001755
Hante Meuleman17012612013-02-06 18:40:44 +01001756 if (cfg->channel) {
1757 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1758 join_params.params_le.chanspec_num = cpu_to_le32(1);
1759 join_params_size += sizeof(join_params.params_le);
1760 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001761 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001762 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001764 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001765
1766done:
1767 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001768 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001769 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 return err;
1771}
1772
1773static s32
1774brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1775 u16 reason_code)
1776{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001777 struct brcmf_if *ifp = netdev_priv(ndev);
1778 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001779 struct brcmf_scb_val_le scbval;
1780 s32 err = 0;
1781
Arend van Sprield96b8012012-12-05 15:26:02 +01001782 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001783 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001784 return -EIO;
1785
Arend van Sprielc1179032012-10-22 13:55:33 -07001786 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001787 cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001788
Arend van Spriel06bb1232012-09-27 14:17:56 +02001789 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001790 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001791 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001792 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001793 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001794 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001795
Arend van Sprield96b8012012-12-05 15:26:02 +01001796 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 return err;
1798}
1799
1800static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001801brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001802 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803{
1804
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001805 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001806 struct net_device *ndev = cfg_to_ndev(cfg);
1807 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808 u16 txpwrmw;
1809 s32 err = 0;
1810 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001811 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001812
Arend van Sprield96b8012012-12-05 15:26:02 +01001813 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001814 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001815 return -EIO;
1816
1817 switch (type) {
1818 case NL80211_TX_POWER_AUTOMATIC:
1819 break;
1820 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001821 case NL80211_TX_POWER_FIXED:
1822 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001823 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824 err = -EINVAL;
1825 goto done;
1826 }
1827 break;
1828 }
1829 /* Make sure radio is off or on as far as software is concerned */
1830 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001831 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001832 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001833 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001834
1835 if (dbm > 0xffff)
1836 txpwrmw = 0xffff;
1837 else
1838 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001839 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1840 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001841 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001842 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001843 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844
1845done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001846 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001847 return err;
1848}
1849
Johannes Bergc8442112012-10-24 10:17:18 +02001850static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1851 struct wireless_dev *wdev,
1852 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001853{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001854 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001855 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001856 s32 txpwrdbm;
1857 u8 result;
1858 s32 err = 0;
1859
Arend van Sprield96b8012012-12-05 15:26:02 +01001860 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001861 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001862 return -EIO;
1863
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001864 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001865 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001866 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867 goto done;
1868 }
1869
1870 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001871 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001872
1873done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001874 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001875 return err;
1876}
1877
1878static s32
1879brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1880 u8 key_idx, bool unicast, bool multicast)
1881{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001882 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001883 u32 index;
1884 u32 wsec;
1885 s32 err = 0;
1886
Arend van Sprield96b8012012-12-05 15:26:02 +01001887 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001888 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001889 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 return -EIO;
1891
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001892 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001893 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001894 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001895 goto done;
1896 }
1897
1898 if (wsec & WEP_ENABLED) {
1899 /* Just select a new current key */
1900 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001901 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001902 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001904 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001905 }
1906done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001907 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001908 return err;
1909}
1910
1911static s32
1912brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1913 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1914{
Hante Meuleman992f6062013-04-02 21:06:17 +02001915 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001916 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02001918 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02001919
1920 memset(&key, 0, sizeof(key));
1921 key.index = (u32) key_idx;
1922 /* Instead of bcast for ea address for default wep keys,
1923 driver needs it to be Null */
1924 if (!is_multicast_ether_addr(mac_addr))
1925 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1926 key.len = (u32) params->key_len;
1927 /* check for key index change */
1928 if (key.len == 0) {
1929 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001930 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001931 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001932 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001933 } else {
1934 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001935 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001936 return -EINVAL;
1937 }
1938
Arend van Spriel16886732012-12-05 15:26:04 +01001939 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001940 memcpy(key.data, params->key, key.len);
1941
Arend van Spriel967fe2c2014-03-15 17:18:21 +01001942 if (!brcmf_is_apmode(ifp->vif) &&
Hante Meuleman992f6062013-04-02 21:06:17 +02001943 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1944 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001945 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1946 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1947 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1948 }
1949
1950 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1951 if (params->seq && params->seq_len == 6) {
1952 /* rx iv */
1953 u8 *ivptr;
1954 ivptr = (u8 *) params->seq;
1955 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1956 (ivptr[3] << 8) | ivptr[2];
1957 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1958 key.iv_initialized = true;
1959 }
1960
1961 switch (params->cipher) {
1962 case WLAN_CIPHER_SUITE_WEP40:
1963 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001964 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965 break;
1966 case WLAN_CIPHER_SUITE_WEP104:
1967 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001968 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001969 break;
1970 case WLAN_CIPHER_SUITE_TKIP:
1971 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001972 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001973 break;
1974 case WLAN_CIPHER_SUITE_AES_CMAC:
1975 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001976 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001977 break;
1978 case WLAN_CIPHER_SUITE_CCMP:
1979 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001980 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981 break;
1982 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001983 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001984 return -EINVAL;
1985 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001986 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001987 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001988 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001989 }
1990 return err;
1991}
1992
1993static s32
1994brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1995 u8 key_idx, bool pairwise, const u8 *mac_addr,
1996 struct key_params *params)
1997{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001998 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999 struct brcmf_wsec_key key;
2000 s32 val;
2001 s32 wsec;
2002 s32 err = 0;
2003 u8 keybuf[8];
2004
Arend van Sprield96b8012012-12-05 15:26:02 +01002005 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002006 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002007 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008 return -EIO;
2009
Daniel Kim787eb032014-01-29 15:32:23 +01002010 if (mac_addr &&
2011 (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2012 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01002013 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002014 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
2015 }
2016 memset(&key, 0, sizeof(key));
2017
2018 key.len = (u32) params->key_len;
2019 key.index = (u32) key_idx;
2020
2021 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002022 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002023 err = -EINVAL;
2024 goto done;
2025 }
2026 memcpy(key.data, params->key, key.len);
2027
2028 key.flags = BRCMF_PRIMARY_KEY;
2029 switch (params->cipher) {
2030 case WLAN_CIPHER_SUITE_WEP40:
2031 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002032 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002033 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034 break;
2035 case WLAN_CIPHER_SUITE_WEP104:
2036 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002037 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002038 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002039 break;
2040 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002041 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002042 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002043 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2044 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2045 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2046 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002047 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002048 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002049 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 break;
2051 case WLAN_CIPHER_SUITE_AES_CMAC:
2052 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002053 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002054 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002055 break;
2056 case WLAN_CIPHER_SUITE_CCMP:
2057 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002058 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002059 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002060 break;
2061 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002062 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002063 err = -EINVAL;
2064 goto done;
2065 }
2066
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002067 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002068 if (err)
2069 goto done;
2070
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002071 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002073 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002074 goto done;
2075 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002076 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002077 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002078 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002079 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 goto done;
2081 }
2082
Arend van Spriel5b435de2011-10-05 13:19:03 +02002083done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002084 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002085 return err;
2086}
2087
2088static s32
2089brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2090 u8 key_idx, bool pairwise, const u8 *mac_addr)
2091{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002092 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002093 struct brcmf_wsec_key key;
2094 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095
Arend van Sprield96b8012012-12-05 15:26:02 +01002096 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002097 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002098 return -EIO;
2099
Hante Meuleman256c3742012-11-05 16:22:28 -08002100 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2101 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002102 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002103 return -EINVAL;
2104 }
2105
Arend van Spriel5b435de2011-10-05 13:19:03 +02002106 memset(&key, 0, sizeof(key));
2107
2108 key.index = (u32) key_idx;
2109 key.flags = BRCMF_PRIMARY_KEY;
2110 key.algo = CRYPTO_ALGO_OFF;
2111
Arend van Spriel16886732012-12-05 15:26:04 +01002112 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113
2114 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002115 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002116
Arend van Sprield96b8012012-12-05 15:26:02 +01002117 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002118 return err;
2119}
2120
2121static s32
2122brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2123 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2124 void (*callback) (void *cookie, struct key_params * params))
2125{
2126 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002127 struct brcmf_if *ifp = netdev_priv(ndev);
2128 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129 struct brcmf_cfg80211_security *sec;
2130 s32 wsec;
2131 s32 err = 0;
2132
Arend van Sprield96b8012012-12-05 15:26:02 +01002133 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002134 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002135 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136 return -EIO;
2137
2138 memset(&params, 0, sizeof(params));
2139
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002140 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002142 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002143 /* Ignore this error, may happen during DISASSOC */
2144 err = -EAGAIN;
2145 goto done;
2146 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002147 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002148 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2150 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002151 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2153 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002154 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002156 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002158 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002159 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002161 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002162 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002163 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 err = -EINVAL;
2165 goto done;
2166 }
2167 callback(cookie, &params);
2168
2169done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002170 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002171 return err;
2172}
2173
2174static s32
2175brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2176 struct net_device *ndev, u8 key_idx)
2177{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002178 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002179
2180 return -EOPNOTSUPP;
2181}
2182
2183static s32
2184brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002185 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002186{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002187 struct brcmf_if *ifp = netdev_priv(ndev);
2188 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 struct brcmf_scb_val_le scb_val;
2190 int rssi;
2191 s32 rate;
2192 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002193 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002194 struct brcmf_sta_info_le sta_info_le;
Hante Meuleman9ee66d12014-01-29 15:32:11 +01002195 u32 beacon_period;
2196 u32 dtim_period;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002197
Arend van Sprield96b8012012-12-05 15:26:02 +01002198 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002199 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002200 return -EIO;
2201
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002202 if (brcmf_is_apmode(ifp->vif)) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002203 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002204 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002205 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002206 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002207 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002208 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002209 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002210 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002211 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002212 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2213 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002214 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002215 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002216 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002217 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2218 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002219 } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002220 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002221 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2222 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002223 err = -ENOENT;
2224 goto done;
2225 }
2226 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002227 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002228 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002229 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002230 goto done;
2231 } else {
2232 sinfo->filled |= STATION_INFO_TX_BITRATE;
2233 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002234 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002235 }
2236
Arend van Sprielc1179032012-10-22 13:55:33 -07002237 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2238 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002239 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002240 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2241 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002242 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002243 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002244 goto done;
2245 } else {
2246 rssi = le32_to_cpu(scb_val.val);
2247 sinfo->filled |= STATION_INFO_SIGNAL;
2248 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002249 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002250 }
Hante Meuleman9ee66d12014-01-29 15:32:11 +01002251 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
2252 &beacon_period);
2253 if (err) {
2254 brcmf_err("Could not get beacon period (%d)\n",
2255 err);
2256 goto done;
2257 } else {
2258 sinfo->bss_param.beacon_interval =
2259 beacon_period;
2260 brcmf_dbg(CONN, "Beacon peroid %d\n",
2261 beacon_period);
2262 }
2263 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
2264 &dtim_period);
2265 if (err) {
2266 brcmf_err("Could not get DTIM period (%d)\n",
2267 err);
2268 goto done;
2269 } else {
2270 sinfo->bss_param.dtim_period = dtim_period;
2271 brcmf_dbg(CONN, "DTIM peroid %d\n",
2272 dtim_period);
2273 }
2274 sinfo->filled |= STATION_INFO_BSS_PARAM;
Hante Meuleman1a873342012-09-27 14:17:54 +02002275 }
2276 } else
2277 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002278done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002279 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002280 return err;
2281}
2282
2283static s32
2284brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2285 bool enabled, s32 timeout)
2286{
2287 s32 pm;
2288 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002289 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002290 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002291
Arend van Sprield96b8012012-12-05 15:26:02 +01002292 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002293
2294 /*
2295 * Powersave enable/disable request is coming from the
2296 * cfg80211 even before the interface is up. In that
2297 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002298 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002299 * FW later while initializing the dongle
2300 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002301 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002302 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002303
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002304 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002305 goto done;
2306 }
2307
2308 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002309 /* Do not enable the power save after assoc if it is a p2p interface */
2310 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2311 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2312 pm = PM_OFF;
2313 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002314 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002315
Arend van Sprielc1179032012-10-22 13:55:33 -07002316 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002317 if (err) {
2318 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002319 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002320 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002321 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322 }
2323done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002324 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002325 return err;
2326}
2327
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002328static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002329 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002330{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002331 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332 struct ieee80211_channel *notify_channel;
2333 struct cfg80211_bss *bss;
2334 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002335 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336 s32 err = 0;
2337 u16 channel;
2338 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339 u16 notify_capability;
2340 u16 notify_interval;
2341 u8 *notify_ie;
2342 size_t notify_ielen;
2343 s32 notify_signal;
2344
2345 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002346 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002347 return 0;
2348 }
2349
Franky Lin83cf17a2013-04-11 13:28:50 +02002350 if (!bi->ctl_ch) {
2351 ch.chspec = le16_to_cpu(bi->chanspec);
2352 cfg->d11inf.decchspec(&ch);
2353 bi->ctl_ch = ch.chnum;
2354 }
2355 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356
2357 if (channel <= CH_MAX_2G_CHANNEL)
2358 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2359 else
2360 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2361
2362 freq = ieee80211_channel_to_frequency(channel, band->band);
2363 notify_channel = ieee80211_get_channel(wiphy, freq);
2364
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365 notify_capability = le16_to_cpu(bi->capability);
2366 notify_interval = le16_to_cpu(bi->beacon_period);
2367 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2368 notify_ielen = le32_to_cpu(bi->ie_length);
2369 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2370
Arend van Spriel16886732012-12-05 15:26:04 +01002371 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2372 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2373 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2374 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2375 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376
2377 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002378 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002379 notify_ielen, notify_signal, GFP_KERNEL);
2380
Franky Line78946e2011-11-10 20:30:34 +01002381 if (!bss)
2382 return -ENOMEM;
2383
Johannes Berg5b112d32013-02-01 01:49:58 +01002384 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002385
2386 return err;
2387}
2388
Roland Vossen6f09be02011-10-18 14:03:02 +02002389static struct brcmf_bss_info_le *
2390next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2391{
2392 if (bss == NULL)
2393 return list->bss_info_le;
2394 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2395 le32_to_cpu(bss->length));
2396}
2397
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002398static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399{
2400 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002401 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002402 s32 err = 0;
2403 int i;
2404
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002405 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002406 if (bss_list->count != 0 &&
2407 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002408 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2409 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002410 return -EOPNOTSUPP;
2411 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002412 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002413 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002414 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002415 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002416 if (err)
2417 break;
2418 }
2419 return err;
2420}
2421
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002422static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002423 struct net_device *ndev, const u8 *bssid)
2424{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002425 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002426 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002427 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002429 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002430 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002431 u8 *buf = NULL;
2432 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002433 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434 u16 notify_capability;
2435 u16 notify_interval;
2436 u8 *notify_ie;
2437 size_t notify_ielen;
2438 s32 notify_signal;
2439
Arend van Sprield96b8012012-12-05 15:26:02 +01002440 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002441
2442 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2443 if (buf == NULL) {
2444 err = -ENOMEM;
2445 goto CleanUp;
2446 }
2447
2448 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2449
Arend van Sprielac24be62012-10-22 10:36:23 -07002450 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2451 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002452 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002453 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002454 goto CleanUp;
2455 }
2456
Roland Vossend34bf642011-10-18 14:03:01 +02002457 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002458
Franky Lin83cf17a2013-04-11 13:28:50 +02002459 ch.chspec = le16_to_cpu(bi->chanspec);
2460 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002461
Franky Lin83cf17a2013-04-11 13:28:50 +02002462 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002463 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2464 else
2465 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2466
Franky Lin83cf17a2013-04-11 13:28:50 +02002467 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002468 notify_channel = ieee80211_get_channel(wiphy, freq);
2469
Arend van Spriel5b435de2011-10-05 13:19:03 +02002470 notify_capability = le16_to_cpu(bi->capability);
2471 notify_interval = le16_to_cpu(bi->beacon_period);
2472 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2473 notify_ielen = le32_to_cpu(bi->ie_length);
2474 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2475
Franky Lin83cf17a2013-04-11 13:28:50 +02002476 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002477 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2478 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2479 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002480
Franky Line78946e2011-11-10 20:30:34 +01002481 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002482 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002483 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2484
Franky Line78946e2011-11-10 20:30:34 +01002485 if (!bss) {
2486 err = -ENOMEM;
2487 goto CleanUp;
2488 }
2489
Johannes Berg5b112d32013-02-01 01:49:58 +01002490 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002491
Arend van Spriel5b435de2011-10-05 13:19:03 +02002492CleanUp:
2493
2494 kfree(buf);
2495
Arend van Sprield96b8012012-12-05 15:26:02 +01002496 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497
2498 return err;
2499}
2500
Hante Meuleman89286dc2013-02-08 15:53:46 +01002501static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2502 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002503{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002504 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002505 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002506 struct brcmf_ssid *ssid;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002507 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002508 u16 beacon_interval;
2509 u8 dtim_period;
2510 size_t ie_len;
2511 u8 *ie;
2512 s32 err = 0;
2513
Arend van Sprield96b8012012-12-05 15:26:02 +01002514 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002515 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002516 return err;
2517
Arend van Spriel06bb1232012-09-27 14:17:56 +02002518 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002519
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002520 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002521 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002522 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002523 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002524 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002525 goto update_bss_info_out;
2526 }
2527
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002528 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2529 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002530 if (err)
2531 goto update_bss_info_out;
2532
2533 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2534 ie_len = le32_to_cpu(bi->ie_length);
2535 beacon_interval = le16_to_cpu(bi->beacon_period);
2536
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002537 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002538 if (tim)
2539 dtim_period = tim->data[1];
2540 else {
2541 /*
2542 * active scan was done so we could not get dtim
2543 * information out of probe response.
2544 * so we speficially query dtim information to dongle.
2545 */
2546 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002547 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002548 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002549 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002550 goto update_bss_info_out;
2551 }
2552 dtim_period = (u8)var;
2553 }
2554
Arend van Spriel5b435de2011-10-05 13:19:03 +02002555update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002556 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002557 return err;
2558}
2559
Hante Meuleman18e2f612013-02-08 15:53:49 +01002560void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002561{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002562 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002563
Arend van Sprielc1179032012-10-22 13:55:33 -07002564 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002565 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002566 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002567 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002568 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002569 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2570 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002571}
2572
Hante Meulemane756af52012-09-11 21:18:52 +02002573static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2574{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002575 struct brcmf_cfg80211_info *cfg =
2576 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002577 escan_timeout_work);
2578
Arend van Spriela0f472a2013-04-05 10:57:49 +02002579 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002580}
2581
2582static void brcmf_escan_timeout(unsigned long data)
2583{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002584 struct brcmf_cfg80211_info *cfg =
2585 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002586
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002587 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002588 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002589 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002590 }
2591}
2592
2593static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002594brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2595 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002596 struct brcmf_bss_info_le *bss_info_le)
2597{
Franky Lin83cf17a2013-04-11 13:28:50 +02002598 struct brcmu_chan ch_bss, ch_bss_info_le;
2599
2600 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2601 cfg->d11inf.decchspec(&ch_bss);
2602 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2603 cfg->d11inf.decchspec(&ch_bss_info_le);
2604
Hante Meulemane756af52012-09-11 21:18:52 +02002605 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002606 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002607 bss_info_le->SSID_len == bss->SSID_len &&
2608 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002609 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2610 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002611 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2612 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2613
Hante Meulemane756af52012-09-11 21:18:52 +02002614 /* preserve max RSSI if the measurements are
2615 * both on-channel or both off-channel
2616 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002617 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002618 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002619 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2620 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002621 /* preserve the on-channel rssi measurement
2622 * if the new measurement is off channel
2623 */
2624 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002625 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002626 }
2627 return 1;
2628 }
2629 return 0;
2630}
2631
2632static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002633brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002634 const struct brcmf_event_msg *e, void *data)
2635{
Arend van Spriel19937322012-11-05 16:22:32 -08002636 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002637 s32 status;
2638 s32 err = 0;
2639 struct brcmf_escan_result_le *escan_result_le;
2640 struct brcmf_bss_info_le *bss_info_le;
2641 struct brcmf_bss_info_le *bss = NULL;
2642 u32 bi_length;
2643 struct brcmf_scan_results *list;
2644 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002645 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002646
Arend van Spriel5c36b992012-11-14 18:46:05 -08002647 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002648
Arend van Spriela0f472a2013-04-05 10:57:49 +02002649 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2650 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002651 return -EPERM;
2652 }
2653
2654 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002655 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002656 escan_result_le = (struct brcmf_escan_result_le *) data;
2657 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002658 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002659 goto exit;
2660 }
Hante Meulemane756af52012-09-11 21:18:52 +02002661 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002662 brcmf_err("Invalid bss_count %d: ignoring\n",
2663 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002664 goto exit;
2665 }
2666 bss_info_le = &escan_result_le->bss_info_le;
2667
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002668 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2669 goto exit;
2670
2671 if (!cfg->scan_request) {
2672 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2673 goto exit;
2674 }
2675
Hante Meulemane756af52012-09-11 21:18:52 +02002676 bi_length = le32_to_cpu(bss_info_le->length);
2677 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2678 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002679 brcmf_err("Invalid bss_info length %d: ignoring\n",
2680 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002681 goto exit;
2682 }
2683
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002684 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002685 BIT(NL80211_IFTYPE_ADHOC))) {
2686 if (le16_to_cpu(bss_info_le->capability) &
2687 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002688 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002689 goto exit;
2690 }
2691 }
2692
2693 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002694 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002695 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002696 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002697 goto exit;
2698 }
2699
2700 for (i = 0; i < list->count; i++) {
2701 bss = bss ? (struct brcmf_bss_info_le *)
2702 ((unsigned char *)bss +
2703 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002704 if (brcmf_compare_update_same_bss(cfg, bss,
2705 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002706 goto exit;
2707 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002708 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002709 bss_info_le, bi_length);
2710 list->version = le32_to_cpu(bss_info_le->version);
2711 list->buflen += bi_length;
2712 list->count++;
2713 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002714 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002715 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2716 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002717 if (cfg->scan_request) {
2718 cfg->bss_list = (struct brcmf_scan_results *)
2719 cfg->escan_info.escan_buf;
2720 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002721 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002722 brcmf_notify_escan_complete(cfg, ifp, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002723 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002724 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002725 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2726 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002727 }
2728exit:
2729 return err;
2730}
2731
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002732static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002733{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002734 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2735 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002736 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2737 /* Init scan_timeout timer */
2738 init_timer(&cfg->escan_timeout);
2739 cfg->escan_timeout.data = (unsigned long) cfg;
2740 cfg->escan_timeout.function = brcmf_escan_timeout;
2741 INIT_WORK(&cfg->escan_timeout_work,
2742 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002743}
2744
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002745static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002746{
2747 if (ms < 1000 / HZ) {
2748 cond_resched();
2749 mdelay(ms);
2750 } else {
2751 msleep(ms);
2752 }
2753}
2754
2755static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2756{
Arend van Sprield96b8012012-12-05 15:26:02 +01002757 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002758
Arend van Spriel5b435de2011-10-05 13:19:03 +02002759 return 0;
2760}
2761
2762static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2763 struct cfg80211_wowlan *wow)
2764{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002765 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2766 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002767 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002768
Arend van Sprield96b8012012-12-05 15:26:02 +01002769 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002770
2771 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002772 * if the primary net_device is not READY there is nothing
2773 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002774 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002775 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2776 if (!check_vif_up(vif))
2777 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002778
Arend van Spriel7d641072012-10-22 13:55:39 -07002779 list_for_each_entry(vif, &cfg->vif_list, list) {
2780 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2781 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002782 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002783 * While going to suspend if associated with AP disassociate
2784 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002785 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002786 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002787
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002788 /* Make sure WPA_Supplicant receives all the event
2789 * generated due to DISASSOC call to the fw to keep
2790 * the state fw and WPA_Supplicant state consistent
2791 */
2792 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002793 }
2794
Arend van Spriel7d641072012-10-22 13:55:39 -07002795 /* end any scanning */
2796 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002797 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002798
2799 /* Turn off watchdog timer */
Arend van Sprielf96aa072013-04-05 10:57:48 +02002800 brcmf_set_mpc(netdev_priv(ndev), 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801
Arend van Spriel7d641072012-10-22 13:55:39 -07002802exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002803 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002804 /* clear any scanning activity */
2805 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806 return 0;
2807}
2808
2809static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002810brcmf_update_pmklist(struct net_device *ndev,
2811 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2812{
2813 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002814 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002815
Arend van Spriel40c8e952011-10-12 20:51:20 +02002816 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2817
Arend van Spriel16886732012-12-05 15:26:04 +01002818 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002819 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002820 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2821 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002823 brcmf_dbg(CONN, "%02x\n",
2824 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002825 }
2826
2827 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002828 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2829 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830
2831 return err;
2832}
2833
2834static s32
2835brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2836 struct cfg80211_pmksa *pmksa)
2837{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002838 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002839 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002840 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002841 s32 err = 0;
2842 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002843 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844
Arend van Sprield96b8012012-12-05 15:26:02 +01002845 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002846 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002847 return -EIO;
2848
Arend van Spriel40c8e952011-10-12 20:51:20 +02002849 pmkid_len = le32_to_cpu(pmkids->npmkid);
2850 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2852 break;
2853 if (i < WL_NUM_PMKIDS_MAX) {
2854 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2855 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002856 if (i == pmkid_len) {
2857 pmkid_len++;
2858 pmkids->npmkid = cpu_to_le32(pmkid_len);
2859 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 } else
2861 err = -EINVAL;
2862
Arend van Spriel16886732012-12-05 15:26:04 +01002863 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2864 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002865 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002866 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002867
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002868 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002869
Arend van Sprield96b8012012-12-05 15:26:02 +01002870 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002871 return err;
2872}
2873
2874static s32
2875brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2876 struct cfg80211_pmksa *pmksa)
2877{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002878 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002879 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002880 struct pmkid_list pmkid;
2881 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002882 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002883
Arend van Sprield96b8012012-12-05 15:26:02 +01002884 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002885 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002886 return -EIO;
2887
2888 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2889 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2890
Arend van Spriel16886732012-12-05 15:26:04 +01002891 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2892 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002893 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002894 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002895
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002896 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002897 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002899 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002900 ETH_ALEN))
2901 break;
2902
Arend van Spriel40c8e952011-10-12 20:51:20 +02002903 if ((pmkid_len > 0)
2904 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002905 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002906 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002907 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002908 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2909 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002910 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002911 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2912 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913 WLAN_PMKID_LEN);
2914 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002915 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002916 } else
2917 err = -EINVAL;
2918
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002919 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002920
Arend van Sprield96b8012012-12-05 15:26:02 +01002921 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002922 return err;
2923
2924}
2925
2926static s32
2927brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2928{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002929 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002930 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002931 s32 err = 0;
2932
Arend van Sprield96b8012012-12-05 15:26:02 +01002933 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002934 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002935 return -EIO;
2936
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002937 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2938 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002939
Arend van Sprield96b8012012-12-05 15:26:02 +01002940 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002941 return err;
2942
2943}
2944
Arend van Spriele5806072012-09-19 22:21:08 +02002945/*
2946 * PFN result doesn't have all the info which are
2947 * required by the supplicant
2948 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2949 * via wl_inform_single_bss in the required format. Escan does require the
2950 * scan request in the form of cfg80211_scan_request. For timebeing, create
2951 * cfg80211_scan_request one out of the received PNO event.
2952 */
2953static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002954brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002955 const struct brcmf_event_msg *e, void *data)
2956{
Arend van Spriel19937322012-11-05 16:22:32 -08002957 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02002958 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2959 struct cfg80211_scan_request *request = NULL;
2960 struct cfg80211_ssid *ssid = NULL;
2961 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002962 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002963 int err = 0;
2964 int channel_req = 0;
2965 int band = 0;
2966 struct brcmf_pno_scanresults_le *pfn_result;
2967 u32 result_count;
2968 u32 status;
2969
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002970 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002971
Arend van Spriel5c36b992012-11-14 18:46:05 -08002972 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002973 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002974 return 0;
2975 }
2976
2977 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2978 result_count = le32_to_cpu(pfn_result->count);
2979 status = le32_to_cpu(pfn_result->status);
2980
2981 /*
2982 * PFN event is limited to fit 512 bytes so we may get
2983 * multiple NET_FOUND events. For now place a warning here.
2984 */
2985 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002986 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002987 if (result_count > 0) {
2988 int i;
2989
2990 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002991 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2992 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002993 if (!request || !ssid || !channel) {
2994 err = -ENOMEM;
2995 goto out_err;
2996 }
2997
2998 request->wiphy = wiphy;
2999 data += sizeof(struct brcmf_pno_scanresults_le);
3000 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3001
3002 for (i = 0; i < result_count; i++) {
3003 netinfo = &netinfo_start[i];
3004 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003005 brcmf_err("Invalid netinfo ptr. index: %d\n",
3006 i);
Arend van Spriele5806072012-09-19 22:21:08 +02003007 err = -EINVAL;
3008 goto out_err;
3009 }
3010
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003011 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3012 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02003013 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3014 ssid[i].ssid_len = netinfo->SSID_len;
3015 request->n_ssids++;
3016
3017 channel_req = netinfo->channel;
3018 if (channel_req <= CH_MAX_2G_CHANNEL)
3019 band = NL80211_BAND_2GHZ;
3020 else
3021 band = NL80211_BAND_5GHZ;
3022 channel[i].center_freq =
3023 ieee80211_channel_to_frequency(channel_req,
3024 band);
3025 channel[i].band = band;
3026 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3027 request->channels[i] = &channel[i];
3028 request->n_channels++;
3029 }
3030
3031 /* assign parsed ssid array */
3032 if (request->n_ssids)
3033 request->ssids = &ssid[0];
3034
Arend van Sprielc1179032012-10-22 13:55:33 -07003035 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02003036 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003037 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003038 }
3039
Arend van Sprielc1179032012-10-22 13:55:33 -07003040 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel2668b0b2014-01-13 22:20:28 +01003041 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003042 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02003043 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003044 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003045 goto out_err;
3046 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003047 cfg->sched_escan = true;
3048 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02003049 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003050 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003051 goto out_err;
3052 }
3053
3054 kfree(ssid);
3055 kfree(channel);
3056 kfree(request);
3057 return 0;
3058
3059out_err:
3060 kfree(ssid);
3061 kfree(channel);
3062 kfree(request);
3063 cfg80211_sched_scan_stopped(wiphy);
3064 return err;
3065}
3066
Arend van Spriele5806072012-09-19 22:21:08 +02003067static int brcmf_dev_pno_clean(struct net_device *ndev)
3068{
Arend van Spriele5806072012-09-19 22:21:08 +02003069 int ret;
3070
3071 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003072 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003073 if (ret == 0) {
3074 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003075 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3076 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003077 }
3078 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003079 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003080
3081 return ret;
3082}
3083
3084static int brcmf_dev_pno_config(struct net_device *ndev)
3085{
3086 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003087
3088 memset(&pfn_param, 0, sizeof(pfn_param));
3089 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3090
3091 /* set extra pno params */
3092 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3093 pfn_param.repeat = BRCMF_PNO_REPEAT;
3094 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3095
3096 /* set up pno scan fr */
3097 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3098
Arend van Sprielac24be62012-10-22 10:36:23 -07003099 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3100 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003101}
3102
3103static int
3104brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3105 struct net_device *ndev,
3106 struct cfg80211_sched_scan_request *request)
3107{
Arend van Sprielc1179032012-10-22 13:55:33 -07003108 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003109 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003110 struct brcmf_pno_net_param_le pfn;
3111 int i;
3112 int ret = 0;
3113
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003114 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003115 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003116 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003117 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003118 return -EAGAIN;
3119 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003120 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3121 brcmf_err("Scanning suppressed: status (%lu)\n",
3122 cfg->scan_status);
3123 return -EAGAIN;
3124 }
Arend van Spriele5806072012-09-19 22:21:08 +02003125
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003126 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003127 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003128 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003129 return -EINVAL;
3130 }
3131
3132 if (request->n_ssids > 0) {
3133 for (i = 0; i < request->n_ssids; i++) {
3134 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003135 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3136 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003137
3138 /*
3139 * match_set ssids is a supert set of n_ssid list,
3140 * so we need not add these set seperately.
3141 */
3142 }
3143 }
3144
3145 if (request->n_match_sets > 0) {
3146 /* clean up everything */
3147 ret = brcmf_dev_pno_clean(ndev);
3148 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003149 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003150 return ret;
3151 }
3152
3153 /* configure pno */
3154 ret = brcmf_dev_pno_config(ndev);
3155 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003156 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003157 return -EINVAL;
3158 }
3159
3160 /* configure each match set */
3161 for (i = 0; i < request->n_match_sets; i++) {
3162 struct cfg80211_ssid *ssid;
3163 u32 ssid_len;
3164
3165 ssid = &request->match_sets[i].ssid;
3166 ssid_len = ssid->ssid_len;
3167
3168 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003169 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003170 continue;
3171 }
3172 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3173 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3174 pfn.wsec = cpu_to_le32(0);
3175 pfn.infra = cpu_to_le32(1);
3176 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3177 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3178 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003179 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003180 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003181 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3182 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003183 }
3184 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003185 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003186 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003187 return -EINVAL;
3188 }
3189 } else {
3190 return -EINVAL;
3191 }
3192
3193 return 0;
3194}
3195
3196static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3197 struct net_device *ndev)
3198{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003199 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003200
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003201 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003202 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003203 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003204 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003205 return 0;
3206}
Arend van Spriele5806072012-09-19 22:21:08 +02003207
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003208#ifdef CONFIG_NL80211_TESTMODE
David Spinadelfc73f112013-07-31 18:04:15 +03003209static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3210 struct wireless_dev *wdev,
3211 void *data, int len)
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003212{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003213 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003214 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003215 struct brcmf_dcmd *dcmd = data;
3216 struct sk_buff *reply;
3217 int ret;
3218
Arend van Sprield96b8012012-12-05 15:26:02 +01003219 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3220 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003221
3222 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003223 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3224 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003225 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003226 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3227 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003228 if (ret == 0) {
3229 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3230 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3231 ret = cfg80211_testmode_reply(reply);
3232 }
3233 return ret;
3234}
3235#endif
3236
Hante Meuleman1f170112013-02-06 18:40:38 +01003237static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003238{
3239 s32 err;
3240
3241 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003242 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003243 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003244 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003245 return err;
3246 }
3247 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003248 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003249 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003250 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003251 return err;
3252 }
3253 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003254 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003255 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003256 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003257 return err;
3258 }
3259
3260 return 0;
3261}
3262
3263static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3264{
3265 if (is_rsn_ie)
3266 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3267
3268 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3269}
3270
3271static s32
Johannes Berg4b5800f2014-01-15 14:55:59 +01003272brcmf_configure_wpaie(struct net_device *ndev,
3273 const struct brcmf_vs_tlv *wpa_ie,
3274 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003275{
Arend van Sprielac24be62012-10-22 10:36:23 -07003276 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003277 u32 auth = 0; /* d11 open authentication */
3278 u16 count;
3279 s32 err = 0;
3280 s32 len = 0;
3281 u32 i;
3282 u32 wsec;
3283 u32 pval = 0;
3284 u32 gval = 0;
3285 u32 wpa_auth = 0;
3286 u32 offset;
3287 u8 *data;
3288 u16 rsn_cap;
3289 u32 wme_bss_disable;
3290
Arend van Sprield96b8012012-12-05 15:26:02 +01003291 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003292 if (wpa_ie == NULL)
3293 goto exit;
3294
3295 len = wpa_ie->len + TLV_HDR_LEN;
3296 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003297 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003298 if (!is_rsn_ie)
3299 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003300 else
3301 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003302
3303 /* check for multicast cipher suite */
3304 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3305 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003306 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003307 goto exit;
3308 }
3309
3310 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3311 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003312 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003313 goto exit;
3314 }
3315 offset += TLV_OUI_LEN;
3316
3317 /* pick up multicast cipher */
3318 switch (data[offset]) {
3319 case WPA_CIPHER_NONE:
3320 gval = 0;
3321 break;
3322 case WPA_CIPHER_WEP_40:
3323 case WPA_CIPHER_WEP_104:
3324 gval = WEP_ENABLED;
3325 break;
3326 case WPA_CIPHER_TKIP:
3327 gval = TKIP_ENABLED;
3328 break;
3329 case WPA_CIPHER_AES_CCM:
3330 gval = AES_ENABLED;
3331 break;
3332 default:
3333 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003334 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003335 goto exit;
3336 }
3337
3338 offset++;
3339 /* walk thru unicast cipher list and pick up what we recognize */
3340 count = data[offset] + (data[offset + 1] << 8);
3341 offset += WPA_IE_SUITE_COUNT_LEN;
3342 /* Check for unicast suite(s) */
3343 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3344 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003345 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003346 goto exit;
3347 }
3348 for (i = 0; i < count; i++) {
3349 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3350 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003351 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003352 goto exit;
3353 }
3354 offset += TLV_OUI_LEN;
3355 switch (data[offset]) {
3356 case WPA_CIPHER_NONE:
3357 break;
3358 case WPA_CIPHER_WEP_40:
3359 case WPA_CIPHER_WEP_104:
3360 pval |= WEP_ENABLED;
3361 break;
3362 case WPA_CIPHER_TKIP:
3363 pval |= TKIP_ENABLED;
3364 break;
3365 case WPA_CIPHER_AES_CCM:
3366 pval |= AES_ENABLED;
3367 break;
3368 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003369 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003370 }
3371 offset++;
3372 }
3373 /* walk thru auth management suite list and pick up what we recognize */
3374 count = data[offset] + (data[offset + 1] << 8);
3375 offset += WPA_IE_SUITE_COUNT_LEN;
3376 /* Check for auth key management suite(s) */
3377 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3378 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003379 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003380 goto exit;
3381 }
3382 for (i = 0; i < count; i++) {
3383 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3384 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003385 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003386 goto exit;
3387 }
3388 offset += TLV_OUI_LEN;
3389 switch (data[offset]) {
3390 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003391 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003392 wpa_auth |= WPA_AUTH_NONE;
3393 break;
3394 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003395 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003396 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3397 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3398 break;
3399 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003400 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003401 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3402 (wpa_auth |= WPA_AUTH_PSK);
3403 break;
3404 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003405 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003406 }
3407 offset++;
3408 }
3409
3410 if (is_rsn_ie) {
3411 wme_bss_disable = 1;
3412 if ((offset + RSN_CAP_LEN) <= len) {
3413 rsn_cap = data[offset] + (data[offset + 1] << 8);
3414 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3415 wme_bss_disable = 0;
3416 }
3417 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003418 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003419 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003420 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003421 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003422 goto exit;
3423 }
3424 }
3425 /* FOR WPS , set SES_OW_ENABLED */
3426 wsec = (pval | gval | SES_OW_ENABLED);
3427
3428 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003429 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003430 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003431 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003432 goto exit;
3433 }
3434 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003435 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003436 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003437 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003438 goto exit;
3439 }
3440 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003441 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003442 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003443 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003444 goto exit;
3445 }
3446
3447exit:
3448 return err;
3449}
3450
3451static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003452brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003453 struct parsed_vndr_ies *vndr_ies)
3454{
3455 s32 err = 0;
3456 struct brcmf_vs_tlv *vndrie;
3457 struct brcmf_tlv *ie;
3458 struct parsed_vndr_ie_info *parsed_info;
3459 s32 remaining_len;
3460
3461 remaining_len = (s32)vndr_ie_len;
3462 memset(vndr_ies, 0, sizeof(*vndr_ies));
3463
3464 ie = (struct brcmf_tlv *)vndr_ie_buf;
3465 while (ie) {
3466 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3467 goto next;
3468 vndrie = (struct brcmf_vs_tlv *)ie;
3469 /* len should be bigger than OUI length + one */
3470 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003471 brcmf_err("invalid vndr ie. length is too small %d\n",
3472 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003473 goto next;
3474 }
3475 /* if wpa or wme ie, do not add ie */
3476 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3477 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3478 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003479 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003480 goto next;
3481 }
3482
3483 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3484
3485 /* save vndr ie information */
3486 parsed_info->ie_ptr = (char *)vndrie;
3487 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3488 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3489
3490 vndr_ies->count++;
3491
Arend van Sprield96b8012012-12-05 15:26:02 +01003492 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3493 parsed_info->vndrie.oui[0],
3494 parsed_info->vndrie.oui[1],
3495 parsed_info->vndrie.oui[2],
3496 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003497
Arend van Spriel9f440b72013-02-08 15:53:36 +01003498 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003499 break;
3500next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003501 remaining_len -= (ie->len + TLV_HDR_LEN);
3502 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003503 ie = NULL;
3504 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003505 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3506 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003507 }
3508 return err;
3509}
3510
3511static u32
3512brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3513{
3514
3515 __le32 iecount_le;
3516 __le32 pktflag_le;
3517
3518 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3519 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3520
3521 iecount_le = cpu_to_le32(1);
3522 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3523
3524 pktflag_le = cpu_to_le32(pktflag);
3525 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3526
3527 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3528
3529 return ie_len + VNDR_IE_HDR_SIZE;
3530}
3531
Arend van Spriel1332e262012-11-05 16:22:18 -08003532s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3533 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003534{
Arend van Spriel1332e262012-11-05 16:22:18 -08003535 struct brcmf_if *ifp;
3536 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003537 s32 err = 0;
3538 u8 *iovar_ie_buf;
3539 u8 *curr_ie_buf;
3540 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003541 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003542 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003543 u32 del_add_ie_buf_len = 0;
3544 u32 total_ie_buf_len = 0;
3545 u32 parsed_ie_buf_len = 0;
3546 struct parsed_vndr_ies old_vndr_ies;
3547 struct parsed_vndr_ies new_vndr_ies;
3548 struct parsed_vndr_ie_info *vndrie_info;
3549 s32 i;
3550 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003551 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003552
Arend van Spriel1332e262012-11-05 16:22:18 -08003553 if (!vif)
3554 return -ENODEV;
3555 ifp = vif->ifp;
3556 saved_ie = &vif->saved_ie;
3557
Arend van Sprield96b8012012-12-05 15:26:02 +01003558 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003559 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3560 if (!iovar_ie_buf)
3561 return -ENOMEM;
3562 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003563 switch (pktflag) {
3564 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3565 mgmt_ie_buf = saved_ie->probe_req_ie;
3566 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3567 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3568 break;
3569 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3570 mgmt_ie_buf = saved_ie->probe_res_ie;
3571 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3572 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3573 break;
3574 case BRCMF_VNDR_IE_BEACON_FLAG:
3575 mgmt_ie_buf = saved_ie->beacon_ie;
3576 mgmt_ie_len = &saved_ie->beacon_ie_len;
3577 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3578 break;
3579 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3580 mgmt_ie_buf = saved_ie->assoc_req_ie;
3581 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3582 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3583 break;
3584 default:
3585 err = -EPERM;
3586 brcmf_err("not suitable type\n");
3587 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003588 }
3589
3590 if (vndr_ie_len > mgmt_ie_buf_len) {
3591 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003592 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003593 goto exit;
3594 }
3595
3596 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3597 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3598 ptr = curr_ie_buf;
3599 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3600 for (i = 0; i < new_vndr_ies.count; i++) {
3601 vndrie_info = &new_vndr_ies.ie_info[i];
3602 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3603 vndrie_info->ie_len);
3604 parsed_ie_buf_len += vndrie_info->ie_len;
3605 }
3606 }
3607
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003608 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003609 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3610 (memcmp(mgmt_ie_buf, curr_ie_buf,
3611 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003612 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003613 goto exit;
3614 }
3615
3616 /* parse old vndr_ie */
3617 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3618
3619 /* make a command to delete old ie */
3620 for (i = 0; i < old_vndr_ies.count; i++) {
3621 vndrie_info = &old_vndr_ies.ie_info[i];
3622
Arend van Sprield96b8012012-12-05 15:26:02 +01003623 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3624 vndrie_info->vndrie.id,
3625 vndrie_info->vndrie.len,
3626 vndrie_info->vndrie.oui[0],
3627 vndrie_info->vndrie.oui[1],
3628 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003629
3630 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3631 vndrie_info->ie_ptr,
3632 vndrie_info->ie_len,
3633 "del");
3634 curr_ie_buf += del_add_ie_buf_len;
3635 total_ie_buf_len += del_add_ie_buf_len;
3636 }
3637 }
3638
3639 *mgmt_ie_len = 0;
3640 /* Add if there is any extra IE */
3641 if (mgmt_ie_buf && parsed_ie_buf_len) {
3642 ptr = mgmt_ie_buf;
3643
3644 remained_buf_len = mgmt_ie_buf_len;
3645
3646 /* make a command to add new ie */
3647 for (i = 0; i < new_vndr_ies.count; i++) {
3648 vndrie_info = &new_vndr_ies.ie_info[i];
3649
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003650 /* verify remained buf size before copy data */
3651 if (remained_buf_len < (vndrie_info->vndrie.len +
3652 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003653 brcmf_err("no space in mgmt_ie_buf: len left %d",
3654 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003655 break;
3656 }
3657 remained_buf_len -= (vndrie_info->ie_len +
3658 VNDR_IE_VSIE_OFFSET);
3659
Arend van Sprield96b8012012-12-05 15:26:02 +01003660 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3661 vndrie_info->vndrie.id,
3662 vndrie_info->vndrie.len,
3663 vndrie_info->vndrie.oui[0],
3664 vndrie_info->vndrie.oui[1],
3665 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003666
3667 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3668 vndrie_info->ie_ptr,
3669 vndrie_info->ie_len,
3670 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003671
3672 /* save the parsed IE in wl struct */
3673 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3674 vndrie_info->ie_len);
3675 *mgmt_ie_len += vndrie_info->ie_len;
3676
3677 curr_ie_buf += del_add_ie_buf_len;
3678 total_ie_buf_len += del_add_ie_buf_len;
3679 }
3680 }
3681 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003682 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003683 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003684 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003685 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003686 }
3687
3688exit:
3689 kfree(iovar_ie_buf);
3690 return err;
3691}
3692
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003693s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3694{
3695 s32 pktflags[] = {
3696 BRCMF_VNDR_IE_PRBREQ_FLAG,
3697 BRCMF_VNDR_IE_PRBRSP_FLAG,
3698 BRCMF_VNDR_IE_BEACON_FLAG
3699 };
3700 int i;
3701
3702 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3703 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3704
3705 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3706 return 0;
3707}
3708
Hante Meuleman1a873342012-09-27 14:17:54 +02003709static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003710brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3711 struct cfg80211_beacon_data *beacon)
3712{
3713 s32 err;
3714
3715 /* Set Beacon IEs to FW */
3716 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3717 beacon->tail, beacon->tail_len);
3718 if (err) {
3719 brcmf_err("Set Beacon IE Failed\n");
3720 return err;
3721 }
3722 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3723
3724 /* Set Probe Response IEs to FW */
3725 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3726 beacon->proberesp_ies,
3727 beacon->proberesp_ies_len);
3728 if (err)
3729 brcmf_err("Set Probe Resp IE Failed\n");
3730 else
3731 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3732
3733 return err;
3734}
3735
3736static s32
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003737brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
3738 struct brcmf_if *ifp,
3739 struct ieee80211_channel *channel)
3740{
3741 u16 chanspec;
3742 s32 err;
3743
3744 brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
3745 channel->center_freq);
3746
3747 chanspec = channel_to_chanspec(&cfg->d11inf, channel);
3748 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3749
3750 return err;
3751}
3752
3753static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003754brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3755 struct cfg80211_ap_settings *settings)
3756{
3757 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003758 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07003759 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01003760 const struct brcmf_tlv *ssid_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003761 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003762 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01003763 const struct brcmf_tlv *rsn_ie;
3764 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003765 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003766 enum nl80211_iftype dev_role;
3767 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003768
Arend van Sprield96b8012012-12-05 15:26:02 +01003769 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3770 cfg80211_get_chandef_type(&settings->chandef),
3771 settings->beacon_interval,
3772 settings->dtim_period);
3773 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3774 settings->ssid, settings->ssid_len, settings->auth_type,
3775 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003776
Hante Meuleman426d0a52013-02-08 15:53:53 +01003777 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003778
3779 memset(&ssid_le, 0, sizeof(ssid_le));
3780 if (settings->ssid == NULL || settings->ssid_len == 0) {
3781 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3782 ssid_ie = brcmf_parse_tlvs(
3783 (u8 *)&settings->beacon.head[ie_offset],
3784 settings->beacon.head_len - ie_offset,
3785 WLAN_EID_SSID);
3786 if (!ssid_ie)
3787 return -EINVAL;
3788
3789 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3790 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003791 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003792 } else {
3793 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3794 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3795 }
3796
Arend van Sprielf96aa072013-04-05 10:57:48 +02003797 brcmf_set_mpc(ifp, 0);
Hante Meulemanb3657452013-05-27 21:09:53 +02003798 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003799
3800 /* find the RSN_IE */
3801 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3802 settings->beacon.tail_len, WLAN_EID_RSN);
3803
3804 /* find the WPA_IE */
3805 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3806 settings->beacon.tail_len);
3807
Hante Meuleman1a873342012-09-27 14:17:54 +02003808 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003809 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003810 if (wpa_ie != NULL) {
3811 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003812 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003813 if (err < 0)
3814 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003815 } else {
3816 /* RSN IE */
3817 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003818 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003819 if (err < 0)
3820 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003821 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003822 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003823 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003824 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003825 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003826
Hante Meulemana0f07952013-02-08 15:53:47 +01003827 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003828
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003829 err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
3830 if (err < 0) {
3831 brcmf_err("Set Channel failed, %d\n", err);
3832 goto exit;
3833 }
3834
Hante Meuleman1a873342012-09-27 14:17:54 +02003835 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003836 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003837 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003838 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003839 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003840 goto exit;
3841 }
3842 }
3843 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003844 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003845 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003846 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003847 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003848 goto exit;
3849 }
3850 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003851
3852 if (dev_role == NL80211_IFTYPE_AP) {
3853 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3854 if (err < 0) {
3855 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3856 goto exit;
3857 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003858 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003859 }
3860
Hante Meulemana0f07952013-02-08 15:53:47 +01003861 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003862 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003863 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003864 goto exit;
3865 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003866 if (dev_role == NL80211_IFTYPE_AP) {
3867 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3868 if (err < 0) {
3869 brcmf_err("setting AP mode failed %d\n", err);
3870 goto exit;
3871 }
3872 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3873 if (err < 0) {
3874 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3875 goto exit;
3876 }
3877
3878 memset(&join_params, 0, sizeof(join_params));
3879 /* join parameters starts with ssid */
3880 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3881 /* create softap */
3882 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3883 &join_params, sizeof(join_params));
3884 if (err < 0) {
3885 brcmf_err("SET SSID error (%d)\n", err);
3886 goto exit;
3887 }
3888 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3889 } else {
3890 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3891 sizeof(ssid_le));
3892 if (err < 0) {
3893 brcmf_err("setting ssid failed %d\n", err);
3894 goto exit;
3895 }
3896 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3897 bss_enable.enable = cpu_to_le32(1);
3898 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3899 sizeof(bss_enable));
3900 if (err < 0) {
3901 brcmf_err("bss_enable config failed %d\n", err);
3902 goto exit;
3903 }
3904
3905 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3906 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003907 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3908 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003909
3910exit:
Hante Meulemanb3657452013-05-27 21:09:53 +02003911 if (err) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02003912 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003913 brcmf_configure_arp_offload(ifp, true);
3914 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003915 return err;
3916}
3917
3918static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3919{
Arend van Sprielc1179032012-10-22 13:55:33 -07003920 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003921 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003922 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02003923 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003924
Arend van Sprield96b8012012-12-05 15:26:02 +01003925 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003926
Hante Meuleman426d0a52013-02-08 15:53:53 +01003927 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003928 /* Due to most likely deauths outstanding we sleep */
3929 /* first to make sure they get processed by fw. */
3930 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003931
3932 memset(&join_params, 0, sizeof(join_params));
3933 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3934 &join_params, sizeof(join_params));
3935 if (err < 0)
3936 brcmf_err("SET SSID error (%d)\n", err);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003937 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003938 if (err < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003939 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003940 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3941 if (err < 0)
3942 brcmf_err("setting AP mode failed %d\n", err);
3943 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3944 if (err < 0)
3945 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003946 } else {
3947 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3948 bss_enable.enable = cpu_to_le32(0);
3949 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3950 sizeof(bss_enable));
3951 if (err < 0)
3952 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003953 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02003954 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003955 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003956 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3957 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3958
Hante Meuleman1a873342012-09-27 14:17:54 +02003959 return err;
3960}
3961
Hante Meulemana0f07952013-02-08 15:53:47 +01003962static s32
3963brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3964 struct cfg80211_beacon_data *info)
3965{
Hante Meulemana0f07952013-02-08 15:53:47 +01003966 struct brcmf_if *ifp = netdev_priv(ndev);
3967 s32 err;
3968
3969 brcmf_dbg(TRACE, "Enter\n");
3970
Hante Meulemana0f07952013-02-08 15:53:47 +01003971 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3972
3973 return err;
3974}
3975
Hante Meuleman1a873342012-09-27 14:17:54 +02003976static int
3977brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3978 u8 *mac)
3979{
Hante Meulemana0f07952013-02-08 15:53:47 +01003980 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003981 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003982 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003983 s32 err;
3984
3985 if (!mac)
3986 return -EFAULT;
3987
Arend van Sprield96b8012012-12-05 15:26:02 +01003988 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003989
Hante Meulemana0f07952013-02-08 15:53:47 +01003990 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3991 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003992 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003993 return -EIO;
3994
3995 memcpy(&scbval.ea, mac, ETH_ALEN);
3996 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003997 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003998 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003999 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004000 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004001
Arend van Sprield96b8012012-12-05 15:26:02 +01004002 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004003 return err;
4004}
4005
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004006
4007static void
4008brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4009 struct wireless_dev *wdev,
4010 u16 frame_type, bool reg)
4011{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004012 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004013 u16 mgmt_type;
4014
4015 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4016
4017 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004018 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004019 if (reg)
4020 vif->mgmt_rx_reg |= BIT(mgmt_type);
4021 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004022 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004023}
4024
4025
4026static int
4027brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004028 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004029{
4030 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004031 struct ieee80211_channel *chan = params->chan;
4032 const u8 *buf = params->buf;
4033 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004034 const struct ieee80211_mgmt *mgmt;
4035 struct brcmf_cfg80211_vif *vif;
4036 s32 err = 0;
4037 s32 ie_offset;
4038 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004039 struct brcmf_fil_action_frame_le *action_frame;
4040 struct brcmf_fil_af_params_le *af_params;
4041 bool ack;
4042 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004043 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004044
4045 brcmf_dbg(TRACE, "Enter\n");
4046
4047 *cookie = 0;
4048
4049 mgmt = (const struct ieee80211_mgmt *)buf;
4050
Hante Meulemana0f07952013-02-08 15:53:47 +01004051 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4052 brcmf_err("Driver only allows MGMT packet type\n");
4053 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004054 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004055
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004056 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4057
Hante Meulemana0f07952013-02-08 15:53:47 +01004058 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4059 /* Right now the only reason to get a probe response */
4060 /* is for p2p listen response or for p2p GO from */
4061 /* wpa_supplicant. Unfortunately the probe is send */
4062 /* on primary ndev, while dongle wants it on the p2p */
4063 /* vif. Since this is only reason for a probe */
4064 /* response to be sent, the vif is taken from cfg. */
4065 /* If ever desired to send proberesp for non p2p */
4066 /* response then data should be checked for */
4067 /* "DIRECT-". Note in future supplicant will take */
4068 /* dedicated p2p wdev to do this and then this 'hack'*/
4069 /* is not needed anymore. */
4070 ie_offset = DOT11_MGMT_HDR_LEN +
4071 DOT11_BCN_PRB_FIXED_LEN;
4072 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004073 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4074 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4075 err = brcmf_vif_set_mgmt_ie(vif,
4076 BRCMF_VNDR_IE_PRBRSP_FLAG,
4077 &buf[ie_offset],
4078 ie_len);
4079 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4080 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004081 } else if (ieee80211_is_action(mgmt->frame_control)) {
4082 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4083 if (af_params == NULL) {
4084 brcmf_err("unable to allocate frame\n");
4085 err = -ENOMEM;
4086 goto exit;
4087 }
4088 action_frame = &af_params->action_frame;
4089 /* Add the packet Id */
4090 action_frame->packet_id = cpu_to_le32(*cookie);
4091 /* Add BSSID */
4092 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4093 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4094 /* Add the length exepted for 802.11 header */
4095 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004096 /* Add the channel. Use the one specified as parameter if any or
4097 * the current one (got from the firmware) otherwise
4098 */
4099 if (chan)
4100 freq = chan->center_freq;
4101 else
4102 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4103 &freq);
4104 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004105 af_params->channel = cpu_to_le32(chan_nr);
4106
4107 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4108 le16_to_cpu(action_frame->len));
4109
4110 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004111 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004112
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004113 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004114 af_params);
4115
4116 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4117 GFP_KERNEL);
4118 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004119 } else {
4120 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4121 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4122 }
4123
Hante Meuleman18e2f612013-02-08 15:53:49 +01004124exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004125 return err;
4126}
4127
4128
4129static int
4130brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4131 struct wireless_dev *wdev,
4132 u64 cookie)
4133{
4134 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4135 struct brcmf_cfg80211_vif *vif;
4136 int err = 0;
4137
4138 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4139
4140 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4141 if (vif == NULL) {
4142 brcmf_err("No p2p device available for probe response\n");
4143 err = -ENODEV;
4144 goto exit;
4145 }
4146 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4147exit:
4148 return err;
4149}
4150
Piotr Haber61730d42013-04-23 12:53:12 +02004151static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4152 struct wireless_dev *wdev,
4153 enum nl80211_crit_proto_id proto,
4154 u16 duration)
4155{
4156 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4157 struct brcmf_cfg80211_vif *vif;
4158
4159 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4160
4161 /* only DHCP support for now */
4162 if (proto != NL80211_CRIT_PROTO_DHCP)
4163 return -EINVAL;
4164
4165 /* suppress and abort scanning */
4166 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4167 brcmf_abort_scanning(cfg);
4168
4169 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4170}
4171
4172static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4173 struct wireless_dev *wdev)
4174{
4175 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4176 struct brcmf_cfg80211_vif *vif;
4177
4178 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4179
4180 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4181 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4182}
4183
Arend van Spriel89c2f382013-08-10 12:27:25 +02004184static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4185{
4186 int ret;
4187
4188 switch (oper) {
4189 case NL80211_TDLS_DISCOVERY_REQ:
4190 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4191 break;
4192 case NL80211_TDLS_SETUP:
4193 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4194 break;
4195 case NL80211_TDLS_TEARDOWN:
4196 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4197 break;
4198 default:
4199 brcmf_err("unsupported operation: %d\n", oper);
4200 ret = -EOPNOTSUPP;
4201 }
4202 return ret;
4203}
4204
4205static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4206 struct net_device *ndev, u8 *peer,
4207 enum nl80211_tdls_operation oper)
4208{
4209 struct brcmf_if *ifp;
4210 struct brcmf_tdls_iovar_le info;
4211 int ret = 0;
4212
4213 ret = brcmf_convert_nl80211_tdls_oper(oper);
4214 if (ret < 0)
4215 return ret;
4216
4217 ifp = netdev_priv(ndev);
4218 memset(&info, 0, sizeof(info));
4219 info.mode = (u8)ret;
4220 if (peer)
4221 memcpy(info.ea, peer, ETH_ALEN);
4222
4223 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4224 &info, sizeof(info));
4225 if (ret < 0)
4226 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4227
4228 return ret;
4229}
4230
Arend van Spriel5b435de2011-10-05 13:19:03 +02004231static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004232 .add_virtual_intf = brcmf_cfg80211_add_iface,
4233 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004234 .change_virtual_intf = brcmf_cfg80211_change_iface,
4235 .scan = brcmf_cfg80211_scan,
4236 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4237 .join_ibss = brcmf_cfg80211_join_ibss,
4238 .leave_ibss = brcmf_cfg80211_leave_ibss,
4239 .get_station = brcmf_cfg80211_get_station,
4240 .set_tx_power = brcmf_cfg80211_set_tx_power,
4241 .get_tx_power = brcmf_cfg80211_get_tx_power,
4242 .add_key = brcmf_cfg80211_add_key,
4243 .del_key = brcmf_cfg80211_del_key,
4244 .get_key = brcmf_cfg80211_get_key,
4245 .set_default_key = brcmf_cfg80211_config_default_key,
4246 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4247 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004248 .connect = brcmf_cfg80211_connect,
4249 .disconnect = brcmf_cfg80211_disconnect,
4250 .suspend = brcmf_cfg80211_suspend,
4251 .resume = brcmf_cfg80211_resume,
4252 .set_pmksa = brcmf_cfg80211_set_pmksa,
4253 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004254 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004255 .start_ap = brcmf_cfg80211_start_ap,
4256 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004257 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004258 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004259 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4260 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004261 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4262 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4263 .remain_on_channel = brcmf_p2p_remain_on_channel,
4264 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004265 .start_p2p_device = brcmf_p2p_start_device,
4266 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004267 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4268 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004269 .tdls_oper = brcmf_cfg80211_tdls_oper,
Johannes Berge3335472013-08-06 11:13:19 +02004270 CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004271};
4272
Arend van Spriele5806072012-09-19 22:21:08 +02004273static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4274{
Arend van Spriele5806072012-09-19 22:21:08 +02004275 /* scheduled scan settings */
4276 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4277 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4278 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4279 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004280}
4281
Arend van Spriel9f440b72013-02-08 15:53:36 +01004282static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4283 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004284 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004285 .types = BIT(NL80211_IFTYPE_STATION) |
4286 BIT(NL80211_IFTYPE_ADHOC) |
4287 BIT(NL80211_IFTYPE_AP)
4288 },
4289 {
4290 .max = 1,
4291 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4292 BIT(NL80211_IFTYPE_P2P_GO)
4293 },
Arend van Spriel9af221b2013-05-14 20:52:36 +02004294 {
4295 .max = 1,
4296 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4297 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004298};
4299static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4300 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004301 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004302 .num_different_channels = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004303 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4304 .limits = brcmf_iface_limits
4305 }
4306};
4307
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004308static const struct ieee80211_txrx_stypes
4309brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4310 [NL80211_IFTYPE_STATION] = {
4311 .tx = 0xffff,
4312 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4313 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4314 },
4315 [NL80211_IFTYPE_P2P_CLIENT] = {
4316 .tx = 0xffff,
4317 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4318 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4319 },
4320 [NL80211_IFTYPE_P2P_GO] = {
4321 .tx = 0xffff,
4322 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4323 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4324 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4325 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4326 BIT(IEEE80211_STYPE_AUTH >> 4) |
4327 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4328 BIT(IEEE80211_STYPE_ACTION >> 4)
Arend van Sprielbffc61c2013-04-05 10:57:52 +02004329 },
4330 [NL80211_IFTYPE_P2P_DEVICE] = {
4331 .tx = 0xffff,
4332 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4333 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004334 }
4335};
4336
Arend van Spriel3eacf862012-10-22 13:55:30 -07004337static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004338{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004339 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004340 s32 err = 0;
4341
Arend van Spriel3eacf862012-10-22 13:55:30 -07004342 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4343 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004344 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004345 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004346 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004347 set_wiphy_dev(wiphy, phydev);
4348 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004349 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004350 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4351 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4352 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004353 BIT(NL80211_IFTYPE_AP) |
4354 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Arend van Spriel9af221b2013-05-14 20:52:36 +02004355 BIT(NL80211_IFTYPE_P2P_GO) |
4356 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004357 wiphy->iface_combinations = brcmf_iface_combos;
4358 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004359 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004360 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4361 wiphy->cipher_suites = __wl_cipher_suites;
4362 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004363 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004364 WIPHY_FLAG_OFFCHAN_TX |
Arend van Spriel89c2f382013-08-10 12:27:25 +02004365 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4366 WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004367 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4368 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004369 brcmf_wiphy_pno_params(wiphy);
Hante Meulemand48200b2013-04-03 12:40:29 +02004370 brcmf_dbg(INFO, "Registering custom regulatory\n");
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +01004371 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Hante Meulemand48200b2013-04-03 12:40:29 +02004372 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004373 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004374 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004375 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004376 wiphy_free(wiphy);
4377 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004378 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004379 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004380}
4381
Arend van Spriel3eacf862012-10-22 13:55:30 -07004382struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004383 enum nl80211_iftype type,
4384 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004385{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004386 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004387
Arend van Spriel33a6b152013-02-08 15:53:39 +01004388 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004389 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004390 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4391 if (!vif)
4392 return ERR_PTR(-ENOMEM);
4393
4394 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004395 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004396
Arend van Spriel3eacf862012-10-22 13:55:30 -07004397 vif->pm_block = pm_block;
4398 vif->roam_off = -1;
4399
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004400 brcmf_init_prof(&vif->profile);
4401
Arend van Spriel3eacf862012-10-22 13:55:30 -07004402 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004403 return vif;
4404}
4405
Arend van Spriel427dec52014-01-06 12:40:47 +01004406void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004407{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004408 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004409 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004410}
4411
Arend van Spriel9df4d542014-01-06 12:40:49 +01004412void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4413{
4414 struct brcmf_cfg80211_vif *vif;
4415 struct brcmf_if *ifp;
4416
4417 ifp = netdev_priv(ndev);
4418 vif = ifp->vif;
4419
4420 brcmf_free_vif(vif);
4421 free_netdev(ndev);
4422}
4423
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004424static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004425{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004426 u32 event = e->event_code;
4427 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004428
4429 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004430 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004431 return true;
4432 }
4433
4434 return false;
4435}
4436
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004437static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004438{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004439 u32 event = e->event_code;
4440 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004441
Hante Meuleman68ca3952014-02-25 20:30:26 +01004442 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
4443 (event == BRCMF_E_DISASSOC_IND) ||
4444 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004445 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004446 return true;
4447 }
4448 return false;
4449}
4450
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004451static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004452 const struct brcmf_event_msg *e)
4453{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004454 u32 event = e->event_code;
4455 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004456
4457 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004458 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4459 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004460 return true;
4461 }
4462
4463 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004464 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004465 return true;
4466 }
4467
4468 return false;
4469}
4470
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004471static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004472{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004473 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004474
4475 kfree(conn_info->req_ie);
4476 conn_info->req_ie = NULL;
4477 conn_info->req_ie_len = 0;
4478 kfree(conn_info->resp_ie);
4479 conn_info->resp_ie = NULL;
4480 conn_info->resp_ie_len = 0;
4481}
4482
Hante Meuleman89286dc2013-02-08 15:53:46 +01004483static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4484 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004485{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004486 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004487 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004488 u32 req_len;
4489 u32 resp_len;
4490 s32 err = 0;
4491
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004492 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004493
Arend van Sprielac24be62012-10-22 10:36:23 -07004494 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4495 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004496 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004497 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004498 return err;
4499 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004500 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004501 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004502 req_len = le32_to_cpu(assoc_info->req_len);
4503 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004504 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004505 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004506 cfg->extra_buf,
4507 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004508 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004509 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004510 return err;
4511 }
4512 conn_info->req_ie_len = req_len;
4513 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004514 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004515 GFP_KERNEL);
4516 } else {
4517 conn_info->req_ie_len = 0;
4518 conn_info->req_ie = NULL;
4519 }
4520 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004521 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004522 cfg->extra_buf,
4523 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004524 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004525 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004526 return err;
4527 }
4528 conn_info->resp_ie_len = resp_len;
4529 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004530 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004531 GFP_KERNEL);
4532 } else {
4533 conn_info->resp_ie_len = 0;
4534 conn_info->resp_ie = NULL;
4535 }
Arend van Spriel16886732012-12-05 15:26:04 +01004536 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4537 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004538
4539 return err;
4540}
4541
4542static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004543brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004544 struct net_device *ndev,
4545 const struct brcmf_event_msg *e)
4546{
Arend van Sprielc1179032012-10-22 13:55:33 -07004547 struct brcmf_if *ifp = netdev_priv(ndev);
4548 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004549 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4550 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004551 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004552 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004553 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004554 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004555 u32 freq;
4556 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004557 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004558
Arend van Sprield96b8012012-12-05 15:26:02 +01004559 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004560
Hante Meuleman89286dc2013-02-08 15:53:46 +01004561 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004562 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004563 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004564
Franky Lina180b832012-10-10 11:13:09 -07004565 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4566 if (buf == NULL) {
4567 err = -ENOMEM;
4568 goto done;
4569 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004570
Franky Lina180b832012-10-10 11:13:09 -07004571 /* data sent to dongle has to be little endian */
4572 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004573 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004574 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004575
4576 if (err)
4577 goto done;
4578
4579 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004580 ch.chspec = le16_to_cpu(bi->chanspec);
4581 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004582
Franky Lin83cf17a2013-04-11 13:28:50 +02004583 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004584 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4585 else
4586 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4587
Franky Lin83cf17a2013-04-11 13:28:50 +02004588 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004589 notify_channel = ieee80211_get_channel(wiphy, freq);
4590
Franky Lina180b832012-10-10 11:13:09 -07004591done:
4592 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004593 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004594 conn_info->req_ie, conn_info->req_ie_len,
4595 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004596 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004597
Arend van Sprielc1179032012-10-22 13:55:33 -07004598 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004599 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004600 return err;
4601}
4602
4603static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004604brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004605 struct net_device *ndev, const struct brcmf_event_msg *e,
4606 bool completed)
4607{
Arend van Sprielc1179032012-10-22 13:55:33 -07004608 struct brcmf_if *ifp = netdev_priv(ndev);
4609 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004610 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004611 s32 err = 0;
4612
Arend van Sprield96b8012012-12-05 15:26:02 +01004613 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004614
Arend van Sprielc1179032012-10-22 13:55:33 -07004615 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4616 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004617 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004618 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004619 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004620 brcmf_update_bss_info(cfg, ifp);
4621 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4622 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004623 }
4624 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004625 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004626 conn_info->req_ie,
4627 conn_info->req_ie_len,
4628 conn_info->resp_ie,
4629 conn_info->resp_ie_len,
4630 completed ? WLAN_STATUS_SUCCESS :
4631 WLAN_STATUS_AUTH_TIMEOUT,
4632 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004633 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4634 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004635 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004636 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004637 return err;
4638}
4639
4640static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004641brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004642 struct net_device *ndev,
4643 const struct brcmf_event_msg *e, void *data)
4644{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004645 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004646 u32 event = e->event_code;
4647 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004648 struct station_info sinfo;
4649
Arend van Spriel16886732012-12-05 15:26:04 +01004650 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004651 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4652 ndev != cfg_to_ndev(cfg)) {
4653 brcmf_dbg(CONN, "AP mode link down\n");
4654 complete(&cfg->vif_disabled);
4655 return 0;
4656 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004657
Hante Meuleman1a873342012-09-27 14:17:54 +02004658 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004659 (reason == BRCMF_E_STATUS_SUCCESS)) {
4660 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004661 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4662 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004663 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004664 return -EINVAL;
4665 }
4666 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004667 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004668 generation++;
4669 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004670 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004671 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4672 (event == BRCMF_E_DEAUTH_IND) ||
4673 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004674 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004675 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004676 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004677}
4678
4679static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004680brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004681 const struct brcmf_event_msg *e, void *data)
4682{
Arend van Spriel19937322012-11-05 16:22:32 -08004683 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4684 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004685 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004686 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004687 s32 err = 0;
Hante Meuleman68ca3952014-02-25 20:30:26 +01004688 u16 reason;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004689
Arend van Spriel967fe2c2014-03-15 17:18:21 +01004690 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004691 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004692 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004693 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004694 if (brcmf_is_ibssmode(ifp->vif)) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004695 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004696 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004697 wl_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004698 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004699 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4700 &ifp->vif->sme_state);
4701 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4702 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004703 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004704 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004705 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004706 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004707 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004708 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004709 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Hante Meuleman68ca3952014-02-25 20:30:26 +01004710 &ifp->vif->sme_state)) {
4711 reason = 0;
4712 if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
4713 (e->event_code == BRCMF_E_DISASSOC_IND)) &&
4714 (e->reason != WLAN_REASON_UNSPECIFIED))
4715 reason = e->reason;
4716 cfg80211_disconnected(ndev, reason, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004717 GFP_KERNEL);
Hante Meuleman68ca3952014-02-25 20:30:26 +01004718 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004719 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004720 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004721 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004722 if (ndev != cfg_to_ndev(cfg))
4723 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004724 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004725 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004726 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4727 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004728 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004729 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004730 }
4731
4732 return err;
4733}
4734
4735static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004736brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004737 const struct brcmf_event_msg *e, void *data)
4738{
Arend van Spriel19937322012-11-05 16:22:32 -08004739 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004740 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004741 u32 event = e->event_code;
4742 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004743
4744 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004745 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004746 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004747 else
Arend van Spriel19937322012-11-05 16:22:32 -08004748 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004749 }
4750
4751 return err;
4752}
4753
4754static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004755brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004756 const struct brcmf_event_msg *e, void *data)
4757{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004758 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004759 enum nl80211_key_type key_type;
4760
4761 if (flags & BRCMF_EVENT_MSG_GROUP)
4762 key_type = NL80211_KEYTYPE_GROUP;
4763 else
4764 key_type = NL80211_KEYTYPE_PAIRWISE;
4765
Arend van Spriel19937322012-11-05 16:22:32 -08004766 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004767 NULL, GFP_KERNEL);
4768
4769 return 0;
4770}
4771
Arend van Sprield3c0b632013-02-08 15:53:37 +01004772static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4773 const struct brcmf_event_msg *e, void *data)
4774{
4775 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4776 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4777 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4778 struct brcmf_cfg80211_vif *vif;
4779
4780 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4781 ifevent->action, ifevent->flags, ifevent->ifidx,
4782 ifevent->bssidx);
4783
Arend van Sprield3c0b632013-02-08 15:53:37 +01004784 mutex_lock(&event->vif_event_lock);
4785 event->action = ifevent->action;
4786 vif = event->vif;
4787
4788 switch (ifevent->action) {
4789 case BRCMF_E_IF_ADD:
4790 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004791 if (!cfg->vif_event.vif) {
4792 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004793 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004794 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004795
4796 ifp->vif = vif;
4797 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02004798 if (ifp->ndev) {
4799 vif->wdev.netdev = ifp->ndev;
4800 ifp->ndev->ieee80211_ptr = &vif->wdev;
4801 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4802 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004803 mutex_unlock(&event->vif_event_lock);
4804 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004805 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004806
4807 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01004808 mutex_unlock(&event->vif_event_lock);
4809 /* event may not be upon user request */
4810 if (brcmf_cfg80211_vif_event_armed(cfg))
4811 wake_up(&event->vif_wq);
4812 return 0;
4813
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004814 case BRCMF_E_IF_CHANGE:
4815 mutex_unlock(&event->vif_event_lock);
4816 wake_up(&event->vif_wq);
4817 return 0;
4818
Arend van Sprield3c0b632013-02-08 15:53:37 +01004819 default:
4820 mutex_unlock(&event->vif_event_lock);
4821 break;
4822 }
4823 return -EINVAL;
4824}
4825
Arend van Spriel5b435de2011-10-05 13:19:03 +02004826static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4827{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004828 conf->frag_threshold = (u32)-1;
4829 conf->rts_threshold = (u32)-1;
4830 conf->retry_short = (u32)-1;
4831 conf->retry_long = (u32)-1;
4832 conf->tx_power = -1;
4833}
4834
Arend van Spriel5c36b992012-11-14 18:46:05 -08004835static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004836{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004837 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4838 brcmf_notify_connect_status);
4839 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4840 brcmf_notify_connect_status);
4841 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4842 brcmf_notify_connect_status);
4843 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4844 brcmf_notify_connect_status);
4845 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4846 brcmf_notify_connect_status);
4847 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4848 brcmf_notify_connect_status);
4849 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4850 brcmf_notify_roaming_status);
4851 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4852 brcmf_notify_mic_status);
4853 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4854 brcmf_notify_connect_status);
4855 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4856 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004857 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4858 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004859 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004860 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004861 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4862 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004863 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4864 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004865 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4866 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004867 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4868 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004869}
4870
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004871static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004872{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004873 kfree(cfg->conf);
4874 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004875 kfree(cfg->escan_ioctl_buf);
4876 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004877 kfree(cfg->extra_buf);
4878 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004879 kfree(cfg->pmk_list);
4880 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004881}
4882
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004883static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004884{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004885 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4886 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004887 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004888 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4889 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004890 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004891 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4892 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004893 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004894 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4895 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004896 goto init_priv_mem_out;
4897
4898 return 0;
4899
4900init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004901 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004902
4903 return -ENOMEM;
4904}
4905
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004906static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004907{
4908 s32 err = 0;
4909
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004910 cfg->scan_request = NULL;
4911 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01004912 cfg->active_scan = true; /* we do active scan per default */
4913 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004914 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004915 if (err)
4916 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004917 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004918 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004919 brcmf_init_escan(cfg);
4920 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004921 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004922 return err;
4923}
4924
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004925static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004926{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004927 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004928 brcmf_abort_scanning(cfg);
4929 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004930}
4931
Arend van Sprield3c0b632013-02-08 15:53:37 +01004932static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4933{
4934 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004935 mutex_init(&event->vif_event_lock);
4936}
4937
Arend van Spriel67b3bd42014-03-20 10:18:03 +01004938static int brcmf_enable_bw40_2g(struct brcmf_if *ifp)
Daniel Kimd2353672014-03-20 10:18:00 +01004939{
4940 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Spriel67b3bd42014-03-20 10:18:03 +01004941 u32 val;
Daniel Kimd2353672014-03-20 10:18:00 +01004942 int err;
4943
Arend van Spriel67b3bd42014-03-20 10:18:03 +01004944 /* verify support for bw_cap command */
4945 val = WLC_BAND_5G;
4946 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
Daniel Kimd2353672014-03-20 10:18:00 +01004947
Arend van Spriel67b3bd42014-03-20 10:18:03 +01004948 if (!err) {
4949 /* only set 2G bandwidth using bw_cap command */
4950 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
Daniel Kim03e5da12014-05-09 12:37:05 +02004951 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
Arend van Spriel67b3bd42014-03-20 10:18:03 +01004952 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
4953 sizeof(band_bwcap));
4954 } else {
4955 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
4956 val = WLC_N_BW_40ALL;
4957 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
4958 }
Daniel Kimd2353672014-03-20 10:18:00 +01004959 return err;
4960}
4961
Arend van Sprield9cb2592012-12-05 15:25:54 +01004962struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4963 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004964{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004965 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004966 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004967 struct wiphy *wiphy;
4968 struct brcmf_cfg80211_vif *vif;
4969 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004970 s32 err = 0;
Franky Lin83cf17a2013-04-11 13:28:50 +02004971 s32 io_type;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004972
4973 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004974 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004975 return NULL;
4976 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004977
Arend van Spriel3eacf862012-10-22 13:55:30 -07004978 ifp = netdev_priv(ndev);
4979 wiphy = brcmf_setup_wiphy(busdev);
4980 if (IS_ERR(wiphy))
4981 return NULL;
4982
4983 cfg = wiphy_priv(wiphy);
4984 cfg->wiphy = wiphy;
4985 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004986 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004987 INIT_LIST_HEAD(&cfg->vif_list);
4988
Arend van Sprield3c0b632013-02-08 15:53:37 +01004989 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004990 if (IS_ERR(vif)) {
4991 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004992 return NULL;
4993 }
4994
Arend van Sprield3c0b632013-02-08 15:53:37 +01004995 vif->ifp = ifp;
4996 vif->wdev.netdev = ndev;
4997 ndev->ieee80211_ptr = &vif->wdev;
4998 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4999
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005000 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005001 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005002 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005003 goto cfg80211_attach_out;
5004 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07005005 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01005006
5007 err = brcmf_p2p_attach(cfg);
5008 if (err) {
5009 brcmf_err("P2P initilisation failed (%d)\n", err);
5010 goto cfg80211_p2p_attach_out;
5011 }
Piotr Haber61730d42013-04-23 12:53:12 +02005012 err = brcmf_btcoex_attach(cfg);
5013 if (err) {
5014 brcmf_err("BT-coex initialisation failed (%d)\n", err);
5015 brcmf_p2p_detach(&cfg->p2p);
5016 goto cfg80211_p2p_attach_out;
5017 }
Hante Meuleman2fde59d2013-02-08 15:53:52 +01005018
Daniel Kimd2353672014-03-20 10:18:00 +01005019 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
5020 * setup 40MHz in 2GHz band and enable OBSS scanning.
5021 */
5022 if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap &
5023 IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
Arend van Spriel67b3bd42014-03-20 10:18:03 +01005024 err = brcmf_enable_bw40_2g(ifp);
5025 if (!err)
Daniel Kimd2353672014-03-20 10:18:00 +01005026 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
5027 BRCMF_OBSS_COEX_AUTO);
Daniel Kimd2353672014-03-20 10:18:00 +01005028 }
5029
Arend van Spriel89c2f382013-08-10 12:27:25 +02005030 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
5031 if (err) {
5032 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
5033 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
5034 }
5035
Franky Lin83cf17a2013-04-11 13:28:50 +02005036 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
5037 &io_type);
5038 if (err) {
5039 brcmf_err("Failed to get D11 version (%d)\n", err);
5040 goto cfg80211_p2p_attach_out;
5041 }
5042 cfg->d11inf.io_type = (u8)io_type;
5043 brcmu_d11_attach(&cfg->d11inf);
5044
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005045 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005046
Hante Meuleman2fde59d2013-02-08 15:53:52 +01005047cfg80211_p2p_attach_out:
5048 wl_deinit_priv(cfg);
5049
Arend van Spriel5b435de2011-10-05 13:19:03 +02005050cfg80211_attach_out:
Arend van Spriel427dec52014-01-06 12:40:47 +01005051 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005052 return NULL;
5053}
5054
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005055void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005056{
Arend van Spriele1479952014-01-06 12:40:48 +01005057 if (!cfg)
5058 return;
5059
Arend van Spriel427dec52014-01-06 12:40:47 +01005060 WARN_ON(!list_empty(&cfg->vif_list));
5061 wiphy_unregister(cfg->wiphy);
Piotr Haber61730d42013-04-23 12:53:12 +02005062 brcmf_btcoex_detach(cfg);
Arend van Spriel427dec52014-01-06 12:40:47 +01005063 wl_deinit_priv(cfg);
5064 wiphy_free(cfg->wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005065}
5066
Arend van Spriel5b435de2011-10-05 13:19:03 +02005067static s32
Hante Meuleman68ca3952014-02-25 20:30:26 +01005068brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005069{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005070 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005071 __le32 roamtrigger[2];
5072 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005073
5074 /*
5075 * Setup timeout if Beacons are lost and roam is
5076 * off to report link down
5077 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005078 if (brcmf_roamoff) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005079 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005080 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005081 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005082 goto dongle_rom_out;
5083 }
5084 }
5085
5086 /*
5087 * Enable/Disable built-in roaming to allow supplicant
5088 * to take care of roaming
5089 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005090 brcmf_dbg(INFO, "Internal Roaming = %s\n",
5091 brcmf_roamoff ? "Off" : "On");
5092 err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005093 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005094 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005095 goto dongle_rom_out;
5096 }
5097
Arend van Sprielf588bc02011-10-12 20:51:22 +02005098 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5099 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005100 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005101 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005102 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005103 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005104 goto dongle_rom_out;
5105 }
5106
Arend van Sprielf588bc02011-10-12 20:51:22 +02005107 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5108 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005109 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005110 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005111 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005112 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005113 goto dongle_rom_out;
5114 }
5115
5116dongle_rom_out:
5117 return err;
5118}
5119
5120static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005121brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005122 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005123{
5124 s32 err = 0;
5125
Arend van Sprielac24be62012-10-22 10:36:23 -07005126 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005127 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005128 if (err) {
5129 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005130 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005131 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005132 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005133 goto dongle_scantime_out;
5134 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005135 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005136 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005137 if (err) {
5138 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005139 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005140 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005141 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005142 goto dongle_scantime_out;
5143 }
5144
Arend van Sprielac24be62012-10-22 10:36:23 -07005145 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005146 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005147 if (err) {
5148 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005149 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005150 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005151 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005152 goto dongle_scantime_out;
5153 }
5154
5155dongle_scantime_out:
5156 return err;
5157}
5158
Hante Meulemand48200b2013-04-03 12:40:29 +02005159
Arend van Spriel2375d972014-01-06 12:40:41 +01005160static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
5161 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005162{
5163 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5164 struct ieee80211_channel *band_chan_arr;
5165 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005166 struct brcmu_chan ch;
Hante Meulemand48200b2013-04-03 12:40:29 +02005167 s32 err;
5168 u8 *pbuf;
5169 u32 i, j;
5170 u32 total;
Hante Meulemand48200b2013-04-03 12:40:29 +02005171 enum ieee80211_band band;
5172 u32 channel;
5173 u32 *n_cnt;
Hante Meulemand48200b2013-04-03 12:40:29 +02005174 u32 index;
5175 u32 ht40_flag;
5176 bool update;
5177 u32 array_size;
5178
5179 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5180
5181 if (pbuf == NULL)
5182 return -ENOMEM;
5183
5184 list = (struct brcmf_chanspec_list *)pbuf;
5185
5186 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5187 BRCMF_DCMD_MEDLEN);
5188 if (err) {
5189 brcmf_err("get chanspecs error (%d)\n", err);
5190 goto exit;
5191 }
5192
5193 __wl_band_2ghz.n_channels = 0;
5194 __wl_band_5ghz_a.n_channels = 0;
5195
5196 total = le32_to_cpu(list->count);
5197 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005198 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5199 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005200
Franky Lin83cf17a2013-04-11 13:28:50 +02005201 if (ch.band == BRCMU_CHAN_BAND_2G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005202 band_chan_arr = __wl_2ghz_channels;
5203 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5204 n_cnt = &__wl_band_2ghz.n_channels;
5205 band = IEEE80211_BAND_2GHZ;
Franky Lin83cf17a2013-04-11 13:28:50 +02005206 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005207 band_chan_arr = __wl_5ghz_a_channels;
5208 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
5209 n_cnt = &__wl_band_5ghz_a.n_channels;
5210 band = IEEE80211_BAND_5GHZ;
Hante Meulemand48200b2013-04-03 12:40:29 +02005211 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005212 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005213 continue;
5214 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005215 if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
5216 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005217 continue;
5218 update = false;
5219 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005220 if (band_chan_arr[j].hw_value == ch.chnum) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005221 update = true;
5222 break;
5223 }
5224 }
5225 if (update)
5226 index = j;
5227 else
5228 index = *n_cnt;
5229 if (index < array_size) {
5230 band_chan_arr[index].center_freq =
Franky Lin83cf17a2013-04-11 13:28:50 +02005231 ieee80211_channel_to_frequency(ch.chnum, band);
5232 band_chan_arr[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005233
Arend van Spriel2375d972014-01-06 12:40:41 +01005234 if (ch.bw == BRCMU_CHAN_BW_40) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005235 /* assuming the order is HT20, HT40 Upper,
5236 * HT40 lower from chanspecs
5237 */
5238 ht40_flag = band_chan_arr[index].flags &
5239 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005240 if (ch.sb == BRCMU_CHAN_SB_U) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005241 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5242 band_chan_arr[index].flags &=
5243 ~IEEE80211_CHAN_NO_HT40;
5244 band_chan_arr[index].flags |=
5245 IEEE80211_CHAN_NO_HT40PLUS;
5246 } else {
5247 /* It should be one of
5248 * IEEE80211_CHAN_NO_HT40 or
5249 * IEEE80211_CHAN_NO_HT40PLUS
5250 */
5251 band_chan_arr[index].flags &=
5252 ~IEEE80211_CHAN_NO_HT40;
5253 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5254 band_chan_arr[index].flags |=
5255 IEEE80211_CHAN_NO_HT40MINUS;
5256 }
5257 } else {
5258 band_chan_arr[index].flags =
5259 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005260 ch.bw = BRCMU_CHAN_BW_20;
5261 cfg->d11inf.encchspec(&ch);
5262 channel = ch.chspec;
Hante Meulemand48200b2013-04-03 12:40:29 +02005263 err = brcmf_fil_bsscfg_int_get(ifp,
5264 "per_chan_info",
5265 &channel);
5266 if (!err) {
5267 if (channel & WL_CHAN_RADAR)
5268 band_chan_arr[index].flags |=
5269 (IEEE80211_CHAN_RADAR |
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005270 IEEE80211_CHAN_NO_IR);
Hante Meulemand48200b2013-04-03 12:40:29 +02005271 if (channel & WL_CHAN_PASSIVE)
5272 band_chan_arr[index].flags |=
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005273 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005274 }
5275 }
5276 if (!update)
5277 (*n_cnt)++;
5278 }
5279 }
5280exit:
5281 kfree(pbuf);
5282 return err;
5283}
5284
Arend van Spriel2375d972014-01-06 12:40:41 +01005285static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5286{
5287 u32 band, mimo_bwcap;
5288 int err;
5289
5290 band = WLC_BAND_2G;
5291 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5292 if (!err) {
5293 bw_cap[IEEE80211_BAND_2GHZ] = band;
5294 band = WLC_BAND_5G;
5295 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5296 if (!err) {
5297 bw_cap[IEEE80211_BAND_5GHZ] = band;
5298 return;
5299 }
5300 WARN_ON(1);
5301 return;
5302 }
5303 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5304 mimo_bwcap = 0;
5305 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5306 if (err)
5307 /* assume 20MHz if firmware does not give a clue */
5308 mimo_bwcap = WLC_N_BW_20ALL;
5309
5310 switch (mimo_bwcap) {
5311 case WLC_N_BW_40ALL:
5312 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5313 /* fall-thru */
5314 case WLC_N_BW_20IN2G_40IN5G:
5315 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5316 /* fall-thru */
5317 case WLC_N_BW_20ALL:
5318 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5319 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5320 break;
5321 default:
5322 brcmf_err("invalid mimo_bw_cap value\n");
5323 }
5324}
Hante Meulemand48200b2013-04-03 12:40:29 +02005325
5326static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005327{
Arend van Sprielac24be62012-10-22 10:36:23 -07005328 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005329 struct wiphy *wiphy;
5330 s32 phy_list;
Hante Meulemand48200b2013-04-03 12:40:29 +02005331 u32 band_list[3];
5332 u32 nmode;
Arend van Spriel2375d972014-01-06 12:40:41 +01005333 u32 bw_cap[2] = { 0, 0 };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005334 u32 rxchain;
5335 u32 nchain;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005336 s8 phy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005337 s32 err;
5338 u32 nband;
5339 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005340 struct ieee80211_supported_band *bands[2] = { NULL, NULL };
5341 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005342
Hante Meulemanb87e2c42012-11-14 18:46:23 -08005343 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005344 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005345 if (err) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005346 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005347 return err;
5348 }
5349
Hante Meuleman3ba81372012-09-19 22:21:13 +02005350 phy = ((char *)&phy_list)[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005351 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5352
5353
5354 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5355 &band_list, sizeof(band_list));
5356 if (err) {
5357 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5358 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005359 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005360 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5361 band_list[0], band_list[1], band_list[2]);
5362
5363 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5364 if (err) {
5365 brcmf_err("nmode error (%d)\n", err);
5366 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005367 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005368 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005369 brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
5370 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005371
Daniel Kim4aca7a12014-02-25 20:30:36 +01005372 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5373 if (err) {
5374 brcmf_err("rxchain error (%d)\n", err);
5375 nchain = 1;
5376 } else {
5377 for (nchain = 0; rxchain; nchain++)
5378 rxchain = rxchain & (rxchain - 1);
5379 }
5380 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5381
Hante Meulemand48200b2013-04-03 12:40:29 +02005382 err = brcmf_construct_reginfo(cfg, bw_cap);
5383 if (err) {
5384 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5385 return err;
5386 }
5387
5388 nband = band_list[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005389
5390 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
Arend van Spriel2375d972014-01-06 12:40:41 +01005391 band = NULL;
Hante Meulemand48200b2013-04-03 12:40:29 +02005392 if ((band_list[i] == WLC_BAND_5G) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005393 (__wl_band_5ghz_a.n_channels > 0))
5394 band = &__wl_band_5ghz_a;
5395 else if ((band_list[i] == WLC_BAND_2G) &&
5396 (__wl_band_2ghz.n_channels > 0))
5397 band = &__wl_band_2ghz;
5398 else
5399 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005400
Arend van Spriel2375d972014-01-06 12:40:41 +01005401 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5402 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5403 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Hante Meulemand48200b2013-04-03 12:40:29 +02005404 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005405 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5406 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5407 band->ht_cap.ht_supported = true;
5408 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5409 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
Daniel Kim4aca7a12014-02-25 20:30:36 +01005410 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
Arend van Spriel2375d972014-01-06 12:40:41 +01005411 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5412 bands[band->band] = band;
Hante Meulemand48200b2013-04-03 12:40:29 +02005413 }
5414
5415 wiphy = cfg_to_wiphy(cfg);
5416 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5417 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5418 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419
5420 return err;
5421}
5422
Hante Meulemand48200b2013-04-03 12:40:29 +02005423
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005424static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005425{
Hante Meulemand48200b2013-04-03 12:40:29 +02005426 return brcmf_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005427}
5428
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005429static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005430{
5431 struct net_device *ndev;
5432 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01005433 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434 s32 power_mode;
5435 s32 err = 0;
5436
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005437 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005438 return err;
5439
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005440 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005441 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01005442 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005443
Hante Meuleman40a23292013-01-02 15:22:51 +01005444 /* make sure RF is ready for work */
5445 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5446
5447 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5448 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005450 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01005451 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005452 if (err)
5453 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005454 brcmf_dbg(INFO, "power save set to %s\n",
5455 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005456
Hante Meuleman68ca3952014-02-25 20:30:26 +01005457 err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005458 if (err)
5459 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005460 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5461 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01005462 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005463 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005464 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005465 if (err)
5466 goto default_conf_out;
5467
Hante Meulemanb3657452013-05-27 21:09:53 +02005468 brcmf_configure_arp_offload(ifp, true);
5469
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005470 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005471default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005472
5473 return err;
5474
5475}
5476
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005477static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005478{
Arend van Sprielc1179032012-10-22 13:55:33 -07005479 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005480
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005481 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005482}
5483
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005484static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005485{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005486 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005487
Arend van Spriel5b435de2011-10-05 13:19:03 +02005488 /*
5489 * While going down, if associated with AP disassociate
5490 * from AP to save power
5491 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005492 if (check_vif_up(ifp->vif)) {
5493 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005494
5495 /* Make sure WPA_Supplicant receives all the event
5496 generated due to DISASSOC call to the fw to keep
5497 the state fw and WPA_Supplicant state consistent
5498 */
5499 brcmf_delay(500);
5500 }
5501
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005502 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005503 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005504
Arend van Spriel5b435de2011-10-05 13:19:03 +02005505 return 0;
5506}
5507
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005508s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005509{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005510 struct brcmf_if *ifp = netdev_priv(ndev);
5511 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005512 s32 err = 0;
5513
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005514 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005515 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005516 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005517
5518 return err;
5519}
5520
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005521s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005522{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005523 struct brcmf_if *ifp = netdev_priv(ndev);
5524 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005525 s32 err = 0;
5526
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005527 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005528 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005529 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005530
5531 return err;
5532}
5533
Arend van Spriela7965fb2013-04-11 17:08:37 +02005534enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5535{
5536 struct wireless_dev *wdev = &ifp->vif->wdev;
5537
5538 return wdev->iftype;
5539}
5540
Arend van Spriel9f440b72013-02-08 15:53:36 +01005541u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5542{
5543 struct brcmf_cfg80211_vif *vif;
5544 bool result = 0;
5545
5546 list_for_each_entry(vif, &cfg->vif_list, list) {
5547 if (test_bit(state, &vif->sme_state))
5548 result++;
5549 }
5550 return result;
5551}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005552
5553static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5554 u8 action)
5555{
5556 u8 evt_action;
5557
5558 mutex_lock(&event->vif_event_lock);
5559 evt_action = event->action;
5560 mutex_unlock(&event->vif_event_lock);
5561 return evt_action == action;
5562}
5563
5564void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5565 struct brcmf_cfg80211_vif *vif)
5566{
5567 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5568
5569 mutex_lock(&event->vif_event_lock);
5570 event->vif = vif;
5571 event->action = 0;
5572 mutex_unlock(&event->vif_event_lock);
5573}
5574
5575bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5576{
5577 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5578 bool armed;
5579
5580 mutex_lock(&event->vif_event_lock);
5581 armed = event->vif != NULL;
5582 mutex_unlock(&event->vif_event_lock);
5583
5584 return armed;
5585}
5586int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5587 u8 action, ulong timeout)
5588{
5589 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5590
5591 return wait_event_timeout(event->vif_wq,
5592 vif_event_equals(event, action), timeout);
5593}
5594