blob: adbd5b7331470cfa229ff83a0958a2db7b48e21b [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,
194};
195
196static struct ieee80211_supported_band __wl_band_5ghz_a = {
197 .band = IEEE80211_BAND_5GHZ,
198 .channels = __wl_5ghz_a_channels,
199 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
200 .bitrates = wl_a_rates,
201 .n_bitrates = wl_a_rates_size,
202};
203
Hante Meulemand48200b2013-04-03 12:40:29 +0200204/* This is to override regulatory domains defined in cfg80211 module (reg.c)
205 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200206 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
207 * With respect to these flags, wpa_supplicant doesn't * start p2p
208 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200209 * domain are to be done here.
210 */
211static const struct ieee80211_regdomain brcmf_regdom = {
212 .n_reg_rules = 4,
213 .alpha2 = "99",
214 .reg_rules = {
215 /* IEEE 802.11b/g, channels 1..11 */
216 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
217 /* If any */
218 /* IEEE 802.11 channel 14 - Only JP enables
219 * this and for 802.11b only
220 */
221 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
222 /* IEEE 802.11a, channel 36..64 */
223 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
224 /* IEEE 802.11a, channel 100..165 */
225 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200226};
227
228static const u32 __wl_cipher_suites[] = {
229 WLAN_CIPHER_SUITE_WEP40,
230 WLAN_CIPHER_SUITE_WEP104,
231 WLAN_CIPHER_SUITE_TKIP,
232 WLAN_CIPHER_SUITE_CCMP,
233 WLAN_CIPHER_SUITE_AES_CMAC,
234};
235
Hante Meuleman1a873342012-09-27 14:17:54 +0200236/* Vendor specific ie. id = 221, oui and type defines exact ie */
237struct brcmf_vs_tlv {
238 u8 id;
239 u8 len;
240 u8 oui[3];
241 u8 oui_type;
242};
243
244struct parsed_vndr_ie_info {
245 u8 *ie_ptr;
246 u32 ie_len; /* total length including id & length field */
247 struct brcmf_vs_tlv vndrie;
248};
249
250struct parsed_vndr_ies {
251 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100252 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200253};
254
Hante Meuleman68ca3952014-02-25 20:30:26 +0100255static int brcmf_roamoff;
256module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
257MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
258
Alwin Beukersef6ac172011-10-12 20:51:26 +0200259/* Quarter dBm units to mW
260 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
261 * Table is offset so the last entry is largest mW value that fits in
262 * a u16.
263 */
264
265#define QDBM_OFFSET 153 /* Offset for first entry */
266#define QDBM_TABLE_LEN 40 /* Table size */
267
268/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
269 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
270 */
271#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
272
273/* Largest mW value that will round down to the last table entry,
274 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
275 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
276 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
277 */
278#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
279
280static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
281/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
282/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
283/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
284/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
285/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
286/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
287};
288
289static u16 brcmf_qdbm_to_mw(u8 qdbm)
290{
291 uint factor = 1;
292 int idx = qdbm - QDBM_OFFSET;
293
294 if (idx >= QDBM_TABLE_LEN)
295 /* clamp to max u16 mW value */
296 return 0xFFFF;
297
298 /* scale the qdBm index up to the range of the table 0-40
299 * where an offset of 40 qdBm equals a factor of 10 mW.
300 */
301 while (idx < 0) {
302 idx += 40;
303 factor *= 10;
304 }
305
306 /* return the mW value scaled down to the correct factor of 10,
307 * adding in factor/2 to get proper rounding.
308 */
309 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
310}
311
312static u8 brcmf_mw_to_qdbm(u16 mw)
313{
314 u8 qdbm;
315 int offset;
316 uint mw_uint = mw;
317 uint boundary;
318
319 /* handle boundary case */
320 if (mw_uint <= 1)
321 return 0;
322
323 offset = QDBM_OFFSET;
324
325 /* move mw into the range of the table */
326 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
327 mw_uint *= 10;
328 offset -= 40;
329 }
330
331 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
332 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
333 nqdBm_to_mW_map[qdbm]) / 2;
334 if (mw_uint < boundary)
335 break;
336 }
337
338 qdbm += (u8) offset;
339
340 return qdbm;
341}
342
Franky Lin83cf17a2013-04-11 13:28:50 +0200343u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
344 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700345{
Franky Lin83cf17a2013-04-11 13:28:50 +0200346 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700347
Franky Lin83cf17a2013-04-11 13:28:50 +0200348 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
349 ch_inf.bw = BRCMU_CHAN_BW_20;
350 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700351
Franky Lin83cf17a2013-04-11 13:28:50 +0200352 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700353}
354
Hante Meuleman89286dc2013-02-08 15:53:46 +0100355/* Traverse a string of 1-byte tag/1-byte length/variable-length value
356 * triples, returning a pointer to the substring whose first element
357 * matches tag
358 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100359const struct brcmf_tlv *
360brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100361{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100362 const struct brcmf_tlv *elt = buf;
363 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100364
365 /* find tagged parameter */
366 while (totlen >= TLV_HDR_LEN) {
367 int len = elt->len;
368
369 /* validate remaining totlen */
370 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
371 return elt;
372
373 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
374 totlen -= (len + TLV_HDR_LEN);
375 }
376
377 return NULL;
378}
379
380/* Is any of the tlvs the expected entry? If
381 * not update the tlvs buffer pointer/length.
382 */
383static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100384brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
385 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100386{
387 /* If the contents match the OUI and the type */
388 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
389 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
390 type == ie[TLV_BODY_OFF + oui_len]) {
391 return true;
392 }
393
394 if (tlvs == NULL)
395 return false;
396 /* point to the next ie */
397 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
398 /* calculate the length of the rest of the buffer */
399 *tlvs_len -= (int)(ie - *tlvs);
400 /* update the pointer to the start of the buffer */
401 *tlvs = ie;
402
403 return false;
404}
405
406static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100407brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100408{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100409 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100410
411 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100412 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100413 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
414 return (struct brcmf_vs_tlv *)ie;
415 }
416 return NULL;
417}
418
419static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100420brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100421{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100422 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100423
424 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
425 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
426 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
427 return (struct brcmf_vs_tlv *)ie;
428 }
429 return NULL;
430}
431
432
Arend van Spriel5b435de2011-10-05 13:19:03 +0200433static void convert_key_from_CPU(struct brcmf_wsec_key *key,
434 struct brcmf_wsec_key_le *key_le)
435{
436 key_le->index = cpu_to_le32(key->index);
437 key_le->len = cpu_to_le32(key->len);
438 key_le->algo = cpu_to_le32(key->algo);
439 key_le->flags = cpu_to_le32(key->flags);
440 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
441 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
442 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
443 memcpy(key_le->data, key->data, sizeof(key->data));
444 memcpy(key_le->ea, key->ea, sizeof(key->ea));
445}
446
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200447static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700448send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200449{
450 int err;
451 struct brcmf_wsec_key_le key_le;
452
453 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200454
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700455 brcmf_netdev_wait_pend8021x(ndev);
456
Arend van Sprielac24be62012-10-22 10:36:23 -0700457 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700458 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200459
Arend van Spriel5b435de2011-10-05 13:19:03 +0200460 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100461 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200462 return err;
463}
464
Hante Meulemanb3657452013-05-27 21:09:53 +0200465static s32
466brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
467{
468 s32 err;
469 u32 mode;
470
471 if (enable)
472 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
473 else
474 mode = 0;
475
476 /* Try to set and enable ARP offload feature, this may fail, then it */
477 /* is simply not supported and err 0 will be returned */
478 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
479 if (err) {
480 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
481 mode, err);
482 err = 0;
483 } else {
484 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
485 if (err) {
486 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
487 enable, err);
488 err = 0;
489 } else
490 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
491 enable, mode);
492 }
493
494 return err;
495}
496
Arend van Spriel9f440b72013-02-08 15:53:36 +0100497static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
498 const char *name,
499 enum nl80211_iftype type,
500 u32 *flags,
501 struct vif_params *params)
502{
503 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
504 switch (type) {
505 case NL80211_IFTYPE_ADHOC:
506 case NL80211_IFTYPE_STATION:
507 case NL80211_IFTYPE_AP:
508 case NL80211_IFTYPE_AP_VLAN:
509 case NL80211_IFTYPE_WDS:
510 case NL80211_IFTYPE_MONITOR:
511 case NL80211_IFTYPE_MESH_POINT:
512 return ERR_PTR(-EOPNOTSUPP);
513 case NL80211_IFTYPE_P2P_CLIENT:
514 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200515 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100516 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
517 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100518 default:
519 return ERR_PTR(-EINVAL);
520 }
521}
522
Arend van Sprielf96aa072013-04-05 10:57:48 +0200523void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100524{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100525 s32 err = 0;
526
527 if (check_vif_up(ifp->vif)) {
528 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
529 if (err) {
530 brcmf_err("fail to set mpc\n");
531 return;
532 }
533 brcmf_dbg(INFO, "MPC : %d\n", mpc);
534 }
535}
536
Arend van Spriela0f472a2013-04-05 10:57:49 +0200537s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
538 struct brcmf_if *ifp, bool aborted,
539 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100540{
541 struct brcmf_scan_params_le params_le;
542 struct cfg80211_scan_request *scan_request;
543 s32 err = 0;
544
545 brcmf_dbg(SCAN, "Enter\n");
546
547 /* clear scan request, because the FW abort can cause a second call */
548 /* to this functon and might cause a double cfg80211_scan_done */
549 scan_request = cfg->scan_request;
550 cfg->scan_request = NULL;
551
552 if (timer_pending(&cfg->escan_timeout))
553 del_timer_sync(&cfg->escan_timeout);
554
555 if (fw_abort) {
556 /* Do a scan abort to stop the driver's scan engine */
557 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
558 memset(&params_le, 0, sizeof(params_le));
559 memset(params_le.bssid, 0xFF, ETH_ALEN);
560 params_le.bss_type = DOT11_BSSTYPE_ANY;
561 params_le.scan_type = 0;
562 params_le.channel_num = cpu_to_le32(1);
563 params_le.nprobes = cpu_to_le32(1);
564 params_le.active_time = cpu_to_le32(-1);
565 params_le.passive_time = cpu_to_le32(-1);
566 params_le.home_time = cpu_to_le32(-1);
567 /* Scan is aborted by setting channel_list[0] to -1 */
568 params_le.channel_list[0] = cpu_to_le16(-1);
569 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200570 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100571 &params_le, sizeof(params_le));
572 if (err)
573 brcmf_err("Scan abort failed\n");
574 }
575 /*
576 * e-scan can be initiated by scheduled scan
577 * which takes precedence.
578 */
579 if (cfg->sched_escan) {
580 brcmf_dbg(SCAN, "scheduled scan completed\n");
581 cfg->sched_escan = false;
582 if (!aborted)
583 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Sprielf96aa072013-04-05 10:57:48 +0200584 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100585 } else if (scan_request) {
586 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
587 aborted ? "Aborted" : "Done");
588 cfg80211_scan_done(scan_request, aborted);
Arend van Sprielf96aa072013-04-05 10:57:48 +0200589 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100590 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100591 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
592 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100593
594 return err;
595}
596
Arend van Spriel9f440b72013-02-08 15:53:36 +0100597static
598int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
599{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100600 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
601 struct net_device *ndev = wdev->netdev;
602
603 /* vif event pending in firmware */
604 if (brcmf_cfg80211_vif_event_armed(cfg))
605 return -EBUSY;
606
607 if (ndev) {
608 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200609 cfg->escan_info.ifp == netdev_priv(ndev))
610 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
611 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100612
613 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
614 }
615
Arend van Spriel9f440b72013-02-08 15:53:36 +0100616 switch (wdev->iftype) {
617 case NL80211_IFTYPE_ADHOC:
618 case NL80211_IFTYPE_STATION:
619 case NL80211_IFTYPE_AP:
620 case NL80211_IFTYPE_AP_VLAN:
621 case NL80211_IFTYPE_WDS:
622 case NL80211_IFTYPE_MONITOR:
623 case NL80211_IFTYPE_MESH_POINT:
624 return -EOPNOTSUPP;
625 case NL80211_IFTYPE_P2P_CLIENT:
626 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200627 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100628 return brcmf_p2p_del_vif(wiphy, wdev);
629 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100630 default:
631 return -EINVAL;
632 }
633 return -EOPNOTSUPP;
634}
635
Arend van Spriel5b435de2011-10-05 13:19:03 +0200636static s32
637brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
638 enum nl80211_iftype type, u32 *flags,
639 struct vif_params *params)
640{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100641 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700642 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100643 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200644 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200645 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200646 s32 err = 0;
647
Arend van Sprield96b8012012-12-05 15:26:02 +0100648 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200649
650 switch (type) {
651 case NL80211_IFTYPE_MONITOR:
652 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100653 brcmf_err("type (%d) : currently we do not support this type\n",
654 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200655 return -EOPNOTSUPP;
656 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100657 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200658 infra = 0;
659 break;
660 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100661 /* Ignore change for p2p IF. Unclear why supplicant does this */
662 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
663 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
664 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
665 /* WAR: It is unexpected to get a change of VIF for P2P
666 * IF, but it happens. The request can not be handled
667 * but returning EPERM causes a crash. Returning 0
668 * without setting ieee80211_ptr->iftype causes trace
669 * (WARN_ON) but it works with wpa_supplicant
670 */
671 return 0;
672 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100673 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200674 infra = 1;
675 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200676 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100677 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100678 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200679 ap = 1;
680 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200681 default:
682 err = -EINVAL;
683 goto done;
684 }
685
Hante Meuleman1a873342012-09-27 14:17:54 +0200686 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100687 if (type == NL80211_IFTYPE_P2P_GO) {
688 brcmf_dbg(INFO, "IF Type = P2P GO\n");
689 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
690 }
691 if (!err) {
692 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
693 brcmf_dbg(INFO, "IF Type = AP\n");
694 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200695 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100696 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200697 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100698 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200699 err = -EAGAIN;
700 goto done;
701 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100702 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
703 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200704 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200705 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200706
707done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100708 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200709
710 return err;
711}
712
Franky Lin83cf17a2013-04-11 13:28:50 +0200713static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
714 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200715 struct cfg80211_scan_request *request)
716{
717 u32 n_ssids;
718 u32 n_channels;
719 s32 i;
720 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200721 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200722 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200723 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200724
Arend van Sprielba40d162012-10-22 13:55:38 -0700725 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200726 params_le->bss_type = DOT11_BSSTYPE_ANY;
727 params_le->scan_type = 0;
728 params_le->channel_num = 0;
729 params_le->nprobes = cpu_to_le32(-1);
730 params_le->active_time = cpu_to_le32(-1);
731 params_le->passive_time = cpu_to_le32(-1);
732 params_le->home_time = cpu_to_le32(-1);
733 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
734
735 /* if request is null exit so it will be all channel broadcast scan */
736 if (!request)
737 return;
738
739 n_ssids = request->n_ssids;
740 n_channels = request->n_channels;
741 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100742 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
743 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200744 if (n_channels > 0) {
745 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200746 chanspec = channel_to_chanspec(&cfg->d11inf,
747 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100748 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
749 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200750 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200751 }
752 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100753 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200754 }
755 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100756 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200757 if (n_ssids > 0) {
758 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
759 n_channels * sizeof(u16);
760 offset = roundup(offset, sizeof(u32));
761 ptr = (char *)params_le + offset;
762 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200763 memset(&ssid_le, 0, sizeof(ssid_le));
764 ssid_le.SSID_len =
765 cpu_to_le32(request->ssids[i].ssid_len);
766 memcpy(ssid_le.SSID, request->ssids[i].ssid,
767 request->ssids[i].ssid_len);
768 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100769 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200770 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100771 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
772 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200773 memcpy(ptr, &ssid_le, sizeof(ssid_le));
774 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200775 }
776 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100777 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200778 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100779 brcmf_dbg(SCAN, "SSID %s len=%d\n",
780 params_le->ssid_le.SSID,
781 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200782 params_le->ssid_le.SSID_len =
783 cpu_to_le32(request->ssids->ssid_len);
784 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
785 request->ssids->ssid_len);
786 }
787 }
788 /* Adding mask to channel numbers */
789 params_le->channel_num =
790 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
791 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
792}
793
794static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200795brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +0200796 struct cfg80211_scan_request *request, u16 action)
797{
798 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
799 offsetof(struct brcmf_escan_params_le, params_le);
800 struct brcmf_escan_params_le *params;
801 s32 err = 0;
802
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100803 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200804
805 if (request != NULL) {
806 /* Allocate space for populating ssids in struct */
807 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
808
809 /* Allocate space for populating ssids in struct */
810 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
811 }
812
813 params = kzalloc(params_size, GFP_KERNEL);
814 if (!params) {
815 err = -ENOMEM;
816 goto exit;
817 }
818 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +0200819 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200820 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
821 params->action = cpu_to_le16(action);
822 params->sync_id = cpu_to_le16(0x1234);
823
Arend van Spriela0f472a2013-04-05 10:57:49 +0200824 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200825 if (err) {
826 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100827 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200828 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100829 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200830 }
831
832 kfree(params);
833exit:
834 return err;
835}
836
837static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200838brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +0200839 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200840{
841 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700842 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200843 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100844 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200845
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100846 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200847 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100848 escan->wiphy = wiphy;
849 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700850 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +0200851 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700852 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200853 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100854 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200855 return err;
856 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200857 brcmf_set_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200858 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200859 results->version = 0;
860 results->count = 0;
861 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
862
Arend van Spriela0f472a2013-04-05 10:57:49 +0200863 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200864 if (err)
Arend van Sprielf96aa072013-04-05 10:57:48 +0200865 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200866 return err;
867}
868
869static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200870brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +0200871 struct cfg80211_scan_request *request,
872 struct cfg80211_ssid *this_ssid)
873{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200874 struct brcmf_if *ifp = vif->ifp;
875 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +0200876 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800877 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700878 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200879 bool escan_req;
880 bool spec_scan;
881 s32 err;
882 u32 SSID_len;
883
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100884 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200885
Arend van Sprielc1179032012-10-22 13:55:33 -0700886 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100887 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200888 return -EAGAIN;
889 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700890 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100891 brcmf_err("Scanning being aborted: status (%lu)\n",
892 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200893 return -EAGAIN;
894 }
Arend van Spriel1687eee2013-04-23 12:53:11 +0200895 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
896 brcmf_err("Scanning suppressed: status (%lu)\n",
897 cfg->scan_status);
898 return -EAGAIN;
899 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700900 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100901 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200902 return -EAGAIN;
903 }
904
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100905 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +0200906 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
907 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100908
Hante Meulemane756af52012-09-11 21:18:52 +0200909 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200910 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200911 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
912
913 escan_req = false;
914 if (request) {
915 /* scan bss */
916 ssids = request->ssids;
917 escan_req = true;
918 } else {
919 /* scan in ibss */
920 /* we don't do escan in ibss */
921 ssids = this_ssid;
922 }
923
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200924 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700925 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200926 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100927 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +0200928 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100929 if (err)
930 goto scan_out;
931
Arend van Spriela0f472a2013-04-05 10:57:49 +0200932 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800933 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200934 goto scan_out;
935 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100936 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
937 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200938 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
939 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
940 sr->ssid_le.SSID_len = cpu_to_le32(0);
941 spec_scan = false;
942 if (SSID_len) {
943 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
944 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
945 spec_scan = true;
946 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100947 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200948
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700949 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700950 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700951 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200952 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100953 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200954 goto scan_out;
955 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200956 brcmf_set_mpc(ifp, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700957 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700958 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200959 if (err) {
960 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100961 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
962 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200963 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100964 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200965
Arend van Sprielf96aa072013-04-05 10:57:48 +0200966 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200967 goto scan_out;
968 }
969 }
970
971 return 0;
972
973scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700974 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200975 if (timer_pending(&cfg->escan_timeout))
976 del_timer_sync(&cfg->escan_timeout);
977 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200978 return err;
979}
980
Arend van Spriel5b435de2011-10-05 13:19:03 +0200981static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700982brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200983{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200984 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200985 s32 err = 0;
986
Arend van Sprield96b8012012-12-05 15:26:02 +0100987 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200988 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
989 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200990 return -EIO;
991
Arend van Spriela0f472a2013-04-05 10:57:49 +0200992 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200993
Arend van Spriel5b435de2011-10-05 13:19:03 +0200994 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100995 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200996
Arend van Sprield96b8012012-12-05 15:26:02 +0100997 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200998 return err;
999}
1000
1001static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1002{
1003 s32 err = 0;
1004
Arend van Sprielac24be62012-10-22 10:36:23 -07001005 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1006 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001007 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001008 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001009
1010 return err;
1011}
1012
1013static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1014{
1015 s32 err = 0;
1016
Arend van Sprielac24be62012-10-22 10:36:23 -07001017 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1018 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001019 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001020 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001021
1022 return err;
1023}
1024
1025static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1026{
1027 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001028 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001029
Arend van Sprielac24be62012-10-22 10:36:23 -07001030 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001031 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001032 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001033 return err;
1034 }
1035 return err;
1036}
1037
1038static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1039{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001040 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1041 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001042 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001043 s32 err = 0;
1044
Arend van Sprield96b8012012-12-05 15:26:02 +01001045 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001046 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001047 return -EIO;
1048
1049 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001050 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1051 cfg->conf->rts_threshold = wiphy->rts_threshold;
1052 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001053 if (!err)
1054 goto done;
1055 }
1056 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001057 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1058 cfg->conf->frag_threshold = wiphy->frag_threshold;
1059 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001060 if (!err)
1061 goto done;
1062 }
1063 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001064 && (cfg->conf->retry_long != wiphy->retry_long)) {
1065 cfg->conf->retry_long = wiphy->retry_long;
1066 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001067 if (!err)
1068 goto done;
1069 }
1070 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001071 && (cfg->conf->retry_short != wiphy->retry_short)) {
1072 cfg->conf->retry_short = wiphy->retry_short;
1073 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001074 if (!err)
1075 goto done;
1076 }
1077
1078done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001079 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001080 return err;
1081}
1082
Arend van Spriel5b435de2011-10-05 13:19:03 +02001083static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1084{
1085 memset(prof, 0, sizeof(*prof));
1086}
1087
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001088static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001089{
Piotr Haber61730d42013-04-23 12:53:12 +02001090 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001091 s32 err = 0;
1092
Arend van Sprield96b8012012-12-05 15:26:02 +01001093 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001094
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001095 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001096 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001097 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001098 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001099 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001100 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001101 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001102 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001103 cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
1104
Arend van Spriel5b435de2011-10-05 13:19:03 +02001105 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001106 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001107 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1108 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001109 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001110}
1111
1112static s32
1113brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1114 struct cfg80211_ibss_params *params)
1115{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001116 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001117 struct brcmf_if *ifp = netdev_priv(ndev);
1118 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001119 struct brcmf_join_params join_params;
1120 size_t join_params_size = 0;
1121 s32 err = 0;
1122 s32 wsec = 0;
1123 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001124 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001125
Arend van Sprield96b8012012-12-05 15:26:02 +01001126 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001127 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001128 return -EIO;
1129
1130 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001131 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001132 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001133 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001134 return -EOPNOTSUPP;
1135 }
1136
Arend van Sprielc1179032012-10-22 13:55:33 -07001137 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138
1139 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001140 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001141 else
Arend van Spriel16886732012-12-05 15:26:04 +01001142 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001143
Johannes Berg683b6d32012-11-08 21:25:48 +01001144 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001145 brcmf_dbg(CONN, "channel: %d\n",
1146 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147 else
Arend van Spriel16886732012-12-05 15:26:04 +01001148 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149
1150 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001151 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152 else
Arend van Spriel16886732012-12-05 15:26:04 +01001153 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154
1155 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001156 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001157 else
Arend van Spriel16886732012-12-05 15:26:04 +01001158 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001159
1160 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001161 brcmf_dbg(CONN, "beacon interval: %d\n",
1162 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163 else
Arend van Spriel16886732012-12-05 15:26:04 +01001164 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165
1166 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001167 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001168 else
Arend van Spriel16886732012-12-05 15:26:04 +01001169 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170
1171 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001172 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001173 else
Arend van Spriel16886732012-12-05 15:26:04 +01001174 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001175
1176 /* Configure Privacy for starter */
1177 if (params->privacy)
1178 wsec |= WEP_ENABLED;
1179
Arend van Sprielc1179032012-10-22 13:55:33 -07001180 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001181 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001182 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001183 goto done;
1184 }
1185
1186 /* Configure Beacon Interval for starter */
1187 if (params->beacon_interval)
1188 bcnprd = params->beacon_interval;
1189 else
1190 bcnprd = 100;
1191
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001192 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001193 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001194 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001195 goto done;
1196 }
1197
1198 /* Configure required join parameter */
1199 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1200
1201 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001202 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1203 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1204 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1205 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001206 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001207
1208 /* BSSID */
1209 if (params->bssid) {
1210 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1211 join_params_size = sizeof(join_params.ssid_le) +
1212 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001213 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001214 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001215 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001216 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001217 }
1218
Arend van Spriel5b435de2011-10-05 13:19:03 +02001219 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001220 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001221 u32 target_channel;
1222
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001223 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001224 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001225 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226 if (params->channel_fixed) {
1227 /* adding chanspec */
Franky Lin83cf17a2013-04-11 13:28:50 +02001228 chanspec = channel_to_chanspec(&cfg->d11inf,
1229 params->chandef.chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001230 join_params.params_le.chanspec_list[0] =
1231 cpu_to_le16(chanspec);
1232 join_params.params_le.chanspec_num = cpu_to_le32(1);
1233 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001234 }
1235
1236 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001237 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001238 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001239 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001240 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001241 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001242 goto done;
1243 }
1244 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001245 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001246
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001247 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248
1249
Arend van Sprielc1179032012-10-22 13:55:33 -07001250 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001251 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001252 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001253 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001254 goto done;
1255 }
1256
1257done:
1258 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001259 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001260 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001261 return err;
1262}
1263
1264static s32
1265brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1266{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001267 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001268 s32 err = 0;
1269
Arend van Sprield96b8012012-12-05 15:26:02 +01001270 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001271 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 return -EIO;
1273
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001274 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275
Arend van Sprield96b8012012-12-05 15:26:02 +01001276 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001277
1278 return err;
1279}
1280
1281static s32 brcmf_set_wpa_version(struct net_device *ndev,
1282 struct cfg80211_connect_params *sme)
1283{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001284 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 struct brcmf_cfg80211_security *sec;
1286 s32 val = 0;
1287 s32 err = 0;
1288
1289 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1290 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1291 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1292 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1293 else
1294 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001295 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001296 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001297 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001298 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001299 return err;
1300 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001301 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001302 sec->wpa_versions = sme->crypto.wpa_versions;
1303 return err;
1304}
1305
1306static s32 brcmf_set_auth_type(struct net_device *ndev,
1307 struct cfg80211_connect_params *sme)
1308{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001309 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001310 struct brcmf_cfg80211_security *sec;
1311 s32 val = 0;
1312 s32 err = 0;
1313
1314 switch (sme->auth_type) {
1315 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1316 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001317 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318 break;
1319 case NL80211_AUTHTYPE_SHARED_KEY:
1320 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001321 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001322 break;
1323 case NL80211_AUTHTYPE_AUTOMATIC:
1324 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001325 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326 break;
1327 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001328 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329 default:
1330 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001331 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001332 break;
1333 }
1334
Hante Meuleman89286dc2013-02-08 15:53:46 +01001335 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001336 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001337 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001338 return err;
1339 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001340 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001341 sec->auth_type = sme->auth_type;
1342 return err;
1343}
1344
1345static s32
1346brcmf_set_set_cipher(struct net_device *ndev,
1347 struct cfg80211_connect_params *sme)
1348{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001349 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350 struct brcmf_cfg80211_security *sec;
1351 s32 pval = 0;
1352 s32 gval = 0;
1353 s32 err = 0;
1354
1355 if (sme->crypto.n_ciphers_pairwise) {
1356 switch (sme->crypto.ciphers_pairwise[0]) {
1357 case WLAN_CIPHER_SUITE_WEP40:
1358 case WLAN_CIPHER_SUITE_WEP104:
1359 pval = WEP_ENABLED;
1360 break;
1361 case WLAN_CIPHER_SUITE_TKIP:
1362 pval = TKIP_ENABLED;
1363 break;
1364 case WLAN_CIPHER_SUITE_CCMP:
1365 pval = AES_ENABLED;
1366 break;
1367 case WLAN_CIPHER_SUITE_AES_CMAC:
1368 pval = AES_ENABLED;
1369 break;
1370 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001371 brcmf_err("invalid cipher pairwise (%d)\n",
1372 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001373 return -EINVAL;
1374 }
1375 }
1376 if (sme->crypto.cipher_group) {
1377 switch (sme->crypto.cipher_group) {
1378 case WLAN_CIPHER_SUITE_WEP40:
1379 case WLAN_CIPHER_SUITE_WEP104:
1380 gval = WEP_ENABLED;
1381 break;
1382 case WLAN_CIPHER_SUITE_TKIP:
1383 gval = TKIP_ENABLED;
1384 break;
1385 case WLAN_CIPHER_SUITE_CCMP:
1386 gval = AES_ENABLED;
1387 break;
1388 case WLAN_CIPHER_SUITE_AES_CMAC:
1389 gval = AES_ENABLED;
1390 break;
1391 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001392 brcmf_err("invalid cipher group (%d)\n",
1393 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001394 return -EINVAL;
1395 }
1396 }
1397
Arend van Spriel16886732012-12-05 15:26:04 +01001398 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001399 /* In case of privacy, but no security and WPS then simulate */
1400 /* setting AES. WPS-2.0 allows no security */
1401 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1402 sme->privacy)
1403 pval = AES_ENABLED;
1404 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001405 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001406 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001407 return err;
1408 }
1409
Arend van Spriel06bb1232012-09-27 14:17:56 +02001410 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001411 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1412 sec->cipher_group = sme->crypto.cipher_group;
1413
1414 return err;
1415}
1416
1417static s32
1418brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1419{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001420 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001421 struct brcmf_cfg80211_security *sec;
1422 s32 val = 0;
1423 s32 err = 0;
1424
1425 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001426 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1427 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001428 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001429 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430 return err;
1431 }
1432 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1433 switch (sme->crypto.akm_suites[0]) {
1434 case WLAN_AKM_SUITE_8021X:
1435 val = WPA_AUTH_UNSPECIFIED;
1436 break;
1437 case WLAN_AKM_SUITE_PSK:
1438 val = WPA_AUTH_PSK;
1439 break;
1440 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001441 brcmf_err("invalid cipher group (%d)\n",
1442 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001443 return -EINVAL;
1444 }
1445 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1446 switch (sme->crypto.akm_suites[0]) {
1447 case WLAN_AKM_SUITE_8021X:
1448 val = WPA2_AUTH_UNSPECIFIED;
1449 break;
1450 case WLAN_AKM_SUITE_PSK:
1451 val = WPA2_AUTH_PSK;
1452 break;
1453 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001454 brcmf_err("invalid cipher group (%d)\n",
1455 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 return -EINVAL;
1457 }
1458 }
1459
Arend van Spriel16886732012-12-05 15:26:04 +01001460 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001461 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1462 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001463 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001464 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001465 return err;
1466 }
1467 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001468 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001469 sec->wpa_auth = sme->crypto.akm_suites[0];
1470
1471 return err;
1472}
1473
1474static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001475brcmf_set_sharedkey(struct net_device *ndev,
1476 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001477{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001478 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479 struct brcmf_cfg80211_security *sec;
1480 struct brcmf_wsec_key key;
1481 s32 val;
1482 s32 err = 0;
1483
Arend van Spriel16886732012-12-05 15:26:04 +01001484 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001485
Roland Vossena718e2f2011-10-12 20:51:24 +02001486 if (sme->key_len == 0)
1487 return 0;
1488
Arend van Spriel06bb1232012-09-27 14:17:56 +02001489 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001490 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1491 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001492
1493 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1494 return 0;
1495
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001496 if (!(sec->cipher_pairwise &
1497 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1498 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001499
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001500 memset(&key, 0, sizeof(key));
1501 key.len = (u32) sme->key_len;
1502 key.index = (u32) sme->key_idx;
1503 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001504 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001505 return -EINVAL;
1506 }
1507 memcpy(key.data, sme->key, key.len);
1508 key.flags = BRCMF_PRIMARY_KEY;
1509 switch (sec->cipher_pairwise) {
1510 case WLAN_CIPHER_SUITE_WEP40:
1511 key.algo = CRYPTO_ALGO_WEP1;
1512 break;
1513 case WLAN_CIPHER_SUITE_WEP104:
1514 key.algo = CRYPTO_ALGO_WEP128;
1515 break;
1516 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001517 brcmf_err("Invalid algorithm (%d)\n",
1518 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001519 return -EINVAL;
1520 }
1521 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001522 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1523 key.len, key.index, key.algo);
1524 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001525 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001526 if (err)
1527 return err;
1528
1529 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001530 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001531 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001532 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001533 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001534 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001535 }
1536 return err;
1537}
1538
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001539static
1540enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1541 enum nl80211_auth_type type)
1542{
1543 u32 ci;
1544 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1545 /* shift to ignore chip revision */
1546 ci = brcmf_get_chip_info(ifp) >> 4;
1547 switch (ci) {
1548 case 43236:
1549 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1550 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1551 default:
1552 break;
1553 }
1554 }
1555 return type;
1556}
1557
Arend van Spriel5b435de2011-10-05 13:19:03 +02001558static s32
1559brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001560 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001561{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001562 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001563 struct brcmf_if *ifp = netdev_priv(ndev);
1564 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565 struct ieee80211_channel *chan = sme->channel;
1566 struct brcmf_join_params join_params;
1567 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001568 const struct brcmf_tlv *rsn_ie;
1569 const struct brcmf_vs_tlv *wpa_ie;
1570 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001571 u32 ie_len;
1572 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001573 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574
1575 s32 err = 0;
1576
Arend van Sprield96b8012012-12-05 15:26:02 +01001577 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001578 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001579 return -EIO;
1580
1581 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001582 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001583 return -EOPNOTSUPP;
1584 }
1585
Hante Meuleman89286dc2013-02-08 15:53:46 +01001586 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1587 /* A normal (non P2P) connection request setup. */
1588 ie = NULL;
1589 ie_len = 0;
1590 /* find the WPA_IE */
1591 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1592 if (wpa_ie) {
1593 ie = wpa_ie;
1594 ie_len = wpa_ie->len + TLV_HDR_LEN;
1595 } else {
1596 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001597 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1598 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001599 WLAN_EID_RSN);
1600 if (rsn_ie) {
1601 ie = rsn_ie;
1602 ie_len = rsn_ie->len + TLV_HDR_LEN;
1603 }
1604 }
1605 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1606 }
1607
1608 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1609 sme->ie, sme->ie_len);
1610 if (err)
1611 brcmf_err("Set Assoc REQ IE Failed\n");
1612 else
1613 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1614
Arend van Sprielc1179032012-10-22 13:55:33 -07001615 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001616
1617 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001618 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001619 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001620 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001621 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1622 cfg->channel, chan->center_freq, chanspec);
1623 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001624 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001625 chanspec = 0;
1626 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001627
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001628 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629
1630 err = brcmf_set_wpa_version(ndev, sme);
1631 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001632 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001633 goto done;
1634 }
1635
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001636 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001637 err = brcmf_set_auth_type(ndev, sme);
1638 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001639 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001640 goto done;
1641 }
1642
1643 err = brcmf_set_set_cipher(ndev, sme);
1644 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001645 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 goto done;
1647 }
1648
1649 err = brcmf_set_key_mgmt(ndev, sme);
1650 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001651 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001652 goto done;
1653 }
1654
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001655 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001656 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001657 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001658 goto done;
1659 }
1660
Hante Meuleman89286dc2013-02-08 15:53:46 +01001661 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1662 (u32)sme->ssid_len);
1663 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1664 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1665 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1666 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1667 profile->ssid.SSID_len);
1668 }
1669
1670 /* Join with specific BSSID and cached SSID
1671 * If SSID is zero join based on BSSID only
1672 */
1673 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1674 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1675 if (cfg->channel)
1676 join_params_size += sizeof(u16);
1677 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1678 if (ext_join_params == NULL) {
1679 err = -ENOMEM;
1680 goto done;
1681 }
1682 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1683 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1684 profile->ssid.SSID_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001685
Hante Meuleman89286dc2013-02-08 15:53:46 +01001686 /* Set up join scan parameters */
1687 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001688 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1689
1690 if (sme->bssid)
1691 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1692 else
1693 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1694
1695 if (cfg->channel) {
1696 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1697
1698 ext_join_params->assoc_le.chanspec_list[0] =
1699 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001700 /* Increase dwell time to receive probe response or detect
1701 * beacon from target AP at a noisy air only during connect
1702 * command.
1703 */
1704 ext_join_params->scan_le.active_time =
1705 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1706 ext_join_params->scan_le.passive_time =
1707 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1708 /* To sync with presence period of VSDB GO send probe request
1709 * more frequently. Probe request will be stopped when it gets
1710 * probe response from target AP/GO.
1711 */
1712 ext_join_params->scan_le.nprobes =
1713 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1714 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1715 } else {
1716 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
1717 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
1718 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001719 }
1720
1721 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1722 join_params_size);
1723 kfree(ext_join_params);
1724 if (!err)
1725 /* This is it. join command worked, we are done */
1726 goto done;
1727
1728 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001729 memset(&join_params, 0, sizeof(join_params));
1730 join_params_size = sizeof(join_params.ssid_le);
1731
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001732 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001733 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001734
Hante Meuleman89286dc2013-02-08 15:53:46 +01001735 if (sme->bssid)
1736 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1737 else
1738 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001739
Hante Meuleman17012612013-02-06 18:40:44 +01001740 if (cfg->channel) {
1741 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1742 join_params.params_le.chanspec_num = cpu_to_le32(1);
1743 join_params_size += sizeof(join_params.params_le);
1744 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001745 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001746 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001747 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001748 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001749
1750done:
1751 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001752 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001753 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001754 return err;
1755}
1756
1757static s32
1758brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1759 u16 reason_code)
1760{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001761 struct brcmf_if *ifp = netdev_priv(ndev);
1762 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763 struct brcmf_scb_val_le scbval;
1764 s32 err = 0;
1765
Arend van Sprield96b8012012-12-05 15:26:02 +01001766 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001767 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001768 return -EIO;
1769
Arend van Sprielc1179032012-10-22 13:55:33 -07001770 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001771 cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001772
Arend van Spriel06bb1232012-09-27 14:17:56 +02001773 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001774 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001775 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001776 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001777 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001778 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001779
Arend van Sprield96b8012012-12-05 15:26:02 +01001780 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001781 return err;
1782}
1783
1784static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001785brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001786 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001787{
1788
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001789 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001790 struct net_device *ndev = cfg_to_ndev(cfg);
1791 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001792 u16 txpwrmw;
1793 s32 err = 0;
1794 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001795 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001796
Arend van Sprield96b8012012-12-05 15:26:02 +01001797 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001798 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001799 return -EIO;
1800
1801 switch (type) {
1802 case NL80211_TX_POWER_AUTOMATIC:
1803 break;
1804 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001805 case NL80211_TX_POWER_FIXED:
1806 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001807 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808 err = -EINVAL;
1809 goto done;
1810 }
1811 break;
1812 }
1813 /* Make sure radio is off or on as far as software is concerned */
1814 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001815 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001816 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001817 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001818
1819 if (dbm > 0xffff)
1820 txpwrmw = 0xffff;
1821 else
1822 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001823 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1824 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001825 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001826 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001827 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001828
1829done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001830 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001831 return err;
1832}
1833
Johannes Bergc8442112012-10-24 10:17:18 +02001834static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1835 struct wireless_dev *wdev,
1836 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001837{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001838 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001839 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 s32 txpwrdbm;
1841 u8 result;
1842 s32 err = 0;
1843
Arend van Sprield96b8012012-12-05 15:26:02 +01001844 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001845 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846 return -EIO;
1847
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001848 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001849 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001850 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001851 goto done;
1852 }
1853
1854 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001855 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001856
1857done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001858 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001859 return err;
1860}
1861
1862static s32
1863brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1864 u8 key_idx, bool unicast, bool multicast)
1865{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001866 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867 u32 index;
1868 u32 wsec;
1869 s32 err = 0;
1870
Arend van Sprield96b8012012-12-05 15:26:02 +01001871 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001872 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001873 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001874 return -EIO;
1875
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001876 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001877 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001878 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001879 goto done;
1880 }
1881
1882 if (wsec & WEP_ENABLED) {
1883 /* Just select a new current key */
1884 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001885 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001886 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001887 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001888 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 }
1890done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001891 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001892 return err;
1893}
1894
1895static s32
1896brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1897 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1898{
Hante Meuleman992f6062013-04-02 21:06:17 +02001899 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001901 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02001902 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903
1904 memset(&key, 0, sizeof(key));
1905 key.index = (u32) key_idx;
1906 /* Instead of bcast for ea address for default wep keys,
1907 driver needs it to be Null */
1908 if (!is_multicast_ether_addr(mac_addr))
1909 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1910 key.len = (u32) params->key_len;
1911 /* check for key index change */
1912 if (key.len == 0) {
1913 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001914 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001915 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001916 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917 } else {
1918 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001919 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001920 return -EINVAL;
1921 }
1922
Arend van Spriel16886732012-12-05 15:26:04 +01001923 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001924 memcpy(key.data, params->key, key.len);
1925
Hante Meuleman992f6062013-04-02 21:06:17 +02001926 if ((ifp->vif->mode != WL_MODE_AP) &&
1927 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1928 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001929 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1930 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1931 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1932 }
1933
1934 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1935 if (params->seq && params->seq_len == 6) {
1936 /* rx iv */
1937 u8 *ivptr;
1938 ivptr = (u8 *) params->seq;
1939 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1940 (ivptr[3] << 8) | ivptr[2];
1941 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1942 key.iv_initialized = true;
1943 }
1944
1945 switch (params->cipher) {
1946 case WLAN_CIPHER_SUITE_WEP40:
1947 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001948 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001949 break;
1950 case WLAN_CIPHER_SUITE_WEP104:
1951 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001952 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001953 break;
1954 case WLAN_CIPHER_SUITE_TKIP:
1955 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001956 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 break;
1958 case WLAN_CIPHER_SUITE_AES_CMAC:
1959 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001960 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001961 break;
1962 case WLAN_CIPHER_SUITE_CCMP:
1963 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001964 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965 break;
1966 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001967 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968 return -EINVAL;
1969 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001970 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001971 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001972 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001973 }
1974 return err;
1975}
1976
1977static s32
1978brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1979 u8 key_idx, bool pairwise, const u8 *mac_addr,
1980 struct key_params *params)
1981{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001982 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001983 struct brcmf_wsec_key key;
1984 s32 val;
1985 s32 wsec;
1986 s32 err = 0;
1987 u8 keybuf[8];
1988
Arend van Sprield96b8012012-12-05 15:26:02 +01001989 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001990 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001991 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001992 return -EIO;
1993
Daniel Kim787eb032014-01-29 15:32:23 +01001994 if (mac_addr &&
1995 (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
1996 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001997 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001998 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1999 }
2000 memset(&key, 0, sizeof(key));
2001
2002 key.len = (u32) params->key_len;
2003 key.index = (u32) key_idx;
2004
2005 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002006 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002007 err = -EINVAL;
2008 goto done;
2009 }
2010 memcpy(key.data, params->key, key.len);
2011
2012 key.flags = BRCMF_PRIMARY_KEY;
2013 switch (params->cipher) {
2014 case WLAN_CIPHER_SUITE_WEP40:
2015 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002016 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002017 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002018 break;
2019 case WLAN_CIPHER_SUITE_WEP104:
2020 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002021 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002022 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002023 break;
2024 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002025 if (ifp->vif->mode != WL_MODE_AP) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002026 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002027 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2028 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2029 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2030 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002031 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002032 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002033 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034 break;
2035 case WLAN_CIPHER_SUITE_AES_CMAC:
2036 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002037 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002038 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002039 break;
2040 case WLAN_CIPHER_SUITE_CCMP:
2041 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002042 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002043 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002044 break;
2045 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002046 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002047 err = -EINVAL;
2048 goto done;
2049 }
2050
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002051 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002052 if (err)
2053 goto done;
2054
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002055 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002057 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002058 goto done;
2059 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002060 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002061 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002062 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002063 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 goto done;
2065 }
2066
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002068 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 return err;
2070}
2071
2072static s32
2073brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2074 u8 key_idx, bool pairwise, const u8 *mac_addr)
2075{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002076 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002077 struct brcmf_wsec_key key;
2078 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002079
Arend van Sprield96b8012012-12-05 15:26:02 +01002080 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002081 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002082 return -EIO;
2083
Hante Meuleman256c3742012-11-05 16:22:28 -08002084 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2085 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002086 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002087 return -EINVAL;
2088 }
2089
Arend van Spriel5b435de2011-10-05 13:19:03 +02002090 memset(&key, 0, sizeof(key));
2091
2092 key.index = (u32) key_idx;
2093 key.flags = BRCMF_PRIMARY_KEY;
2094 key.algo = CRYPTO_ALGO_OFF;
2095
Arend van Spriel16886732012-12-05 15:26:04 +01002096 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002097
2098 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002099 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100
Arend van Sprield96b8012012-12-05 15:26:02 +01002101 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002102 return err;
2103}
2104
2105static s32
2106brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2107 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2108 void (*callback) (void *cookie, struct key_params * params))
2109{
2110 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002111 struct brcmf_if *ifp = netdev_priv(ndev);
2112 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113 struct brcmf_cfg80211_security *sec;
2114 s32 wsec;
2115 s32 err = 0;
2116
Arend van Sprield96b8012012-12-05 15:26:02 +01002117 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002118 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002119 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120 return -EIO;
2121
2122 memset(&params, 0, sizeof(params));
2123
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002124 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002125 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002126 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127 /* Ignore this error, may happen during DISASSOC */
2128 err = -EAGAIN;
2129 goto done;
2130 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002131 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002132 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002133 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2134 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002135 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2137 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002138 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002140 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002142 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002143 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002145 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002146 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002147 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002148 err = -EINVAL;
2149 goto done;
2150 }
2151 callback(cookie, &params);
2152
2153done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002154 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155 return err;
2156}
2157
2158static s32
2159brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2160 struct net_device *ndev, u8 key_idx)
2161{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002162 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002163
2164 return -EOPNOTSUPP;
2165}
2166
2167static s32
2168brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002169 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002171 struct brcmf_if *ifp = netdev_priv(ndev);
2172 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173 struct brcmf_scb_val_le scb_val;
2174 int rssi;
2175 s32 rate;
2176 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002177 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002178 struct brcmf_sta_info_le sta_info_le;
Hante Meuleman9ee66d12014-01-29 15:32:11 +01002179 u32 beacon_period;
2180 u32 dtim_period;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181
Arend van Sprield96b8012012-12-05 15:26:02 +01002182 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002183 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002184 return -EIO;
2185
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002186 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002187 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002188 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002189 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002190 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002191 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002192 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002193 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002194 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002195 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002196 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2197 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002198 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002199 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002200 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002201 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2202 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002203 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002204 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002205 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2206 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002207 err = -ENOENT;
2208 goto done;
2209 }
2210 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002211 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002212 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002213 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002214 goto done;
2215 } else {
2216 sinfo->filled |= STATION_INFO_TX_BITRATE;
2217 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002218 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002219 }
2220
Arend van Sprielc1179032012-10-22 13:55:33 -07002221 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2222 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002223 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002224 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2225 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002226 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002227 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002228 goto done;
2229 } else {
2230 rssi = le32_to_cpu(scb_val.val);
2231 sinfo->filled |= STATION_INFO_SIGNAL;
2232 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002233 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002234 }
Hante Meuleman9ee66d12014-01-29 15:32:11 +01002235 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
2236 &beacon_period);
2237 if (err) {
2238 brcmf_err("Could not get beacon period (%d)\n",
2239 err);
2240 goto done;
2241 } else {
2242 sinfo->bss_param.beacon_interval =
2243 beacon_period;
2244 brcmf_dbg(CONN, "Beacon peroid %d\n",
2245 beacon_period);
2246 }
2247 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
2248 &dtim_period);
2249 if (err) {
2250 brcmf_err("Could not get DTIM period (%d)\n",
2251 err);
2252 goto done;
2253 } else {
2254 sinfo->bss_param.dtim_period = dtim_period;
2255 brcmf_dbg(CONN, "DTIM peroid %d\n",
2256 dtim_period);
2257 }
2258 sinfo->filled |= STATION_INFO_BSS_PARAM;
Hante Meuleman1a873342012-09-27 14:17:54 +02002259 }
2260 } else
2261 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002262done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002263 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002264 return err;
2265}
2266
2267static s32
2268brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2269 bool enabled, s32 timeout)
2270{
2271 s32 pm;
2272 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002273 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002274 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275
Arend van Sprield96b8012012-12-05 15:26:02 +01002276 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277
2278 /*
2279 * Powersave enable/disable request is coming from the
2280 * cfg80211 even before the interface is up. In that
2281 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002282 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002283 * FW later while initializing the dongle
2284 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002285 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002286 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002287
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002288 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289 goto done;
2290 }
2291
2292 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002293 /* Do not enable the power save after assoc if it is a p2p interface */
2294 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2295 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2296 pm = PM_OFF;
2297 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002298 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002299
Arend van Sprielc1179032012-10-22 13:55:33 -07002300 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 if (err) {
2302 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002303 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002304 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002305 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306 }
2307done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002308 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002309 return err;
2310}
2311
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002312static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002313 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002315 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002316 struct ieee80211_channel *notify_channel;
2317 struct cfg80211_bss *bss;
2318 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002319 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002320 s32 err = 0;
2321 u16 channel;
2322 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 u16 notify_capability;
2324 u16 notify_interval;
2325 u8 *notify_ie;
2326 size_t notify_ielen;
2327 s32 notify_signal;
2328
2329 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002330 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002331 return 0;
2332 }
2333
Franky Lin83cf17a2013-04-11 13:28:50 +02002334 if (!bi->ctl_ch) {
2335 ch.chspec = le16_to_cpu(bi->chanspec);
2336 cfg->d11inf.decchspec(&ch);
2337 bi->ctl_ch = ch.chnum;
2338 }
2339 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002340
2341 if (channel <= CH_MAX_2G_CHANNEL)
2342 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2343 else
2344 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2345
2346 freq = ieee80211_channel_to_frequency(channel, band->band);
2347 notify_channel = ieee80211_get_channel(wiphy, freq);
2348
Arend van Spriel5b435de2011-10-05 13:19:03 +02002349 notify_capability = le16_to_cpu(bi->capability);
2350 notify_interval = le16_to_cpu(bi->beacon_period);
2351 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2352 notify_ielen = le32_to_cpu(bi->ie_length);
2353 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2354
Arend van Spriel16886732012-12-05 15:26:04 +01002355 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2356 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2357 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2358 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2359 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360
2361 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002362 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 notify_ielen, notify_signal, GFP_KERNEL);
2364
Franky Line78946e2011-11-10 20:30:34 +01002365 if (!bss)
2366 return -ENOMEM;
2367
Johannes Berg5b112d32013-02-01 01:49:58 +01002368 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369
2370 return err;
2371}
2372
Roland Vossen6f09be02011-10-18 14:03:02 +02002373static struct brcmf_bss_info_le *
2374next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2375{
2376 if (bss == NULL)
2377 return list->bss_info_le;
2378 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2379 le32_to_cpu(bss->length));
2380}
2381
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002382static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002383{
2384 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002385 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 s32 err = 0;
2387 int i;
2388
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002389 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002390 if (bss_list->count != 0 &&
2391 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002392 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2393 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 return -EOPNOTSUPP;
2395 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002396 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002397 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002398 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002399 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400 if (err)
2401 break;
2402 }
2403 return err;
2404}
2405
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002406static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002407 struct net_device *ndev, const u8 *bssid)
2408{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002409 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002410 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002411 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002412 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002413 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002414 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 u8 *buf = NULL;
2416 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002417 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002418 u16 notify_capability;
2419 u16 notify_interval;
2420 u8 *notify_ie;
2421 size_t notify_ielen;
2422 s32 notify_signal;
2423
Arend van Sprield96b8012012-12-05 15:26:02 +01002424 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425
2426 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2427 if (buf == NULL) {
2428 err = -ENOMEM;
2429 goto CleanUp;
2430 }
2431
2432 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2433
Arend van Sprielac24be62012-10-22 10:36:23 -07002434 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2435 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002436 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002437 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002438 goto CleanUp;
2439 }
2440
Roland Vossend34bf642011-10-18 14:03:01 +02002441 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002442
Franky Lin83cf17a2013-04-11 13:28:50 +02002443 ch.chspec = le16_to_cpu(bi->chanspec);
2444 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002445
Franky Lin83cf17a2013-04-11 13:28:50 +02002446 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002447 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2448 else
2449 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2450
Franky Lin83cf17a2013-04-11 13:28:50 +02002451 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002452 notify_channel = ieee80211_get_channel(wiphy, freq);
2453
Arend van Spriel5b435de2011-10-05 13:19:03 +02002454 notify_capability = le16_to_cpu(bi->capability);
2455 notify_interval = le16_to_cpu(bi->beacon_period);
2456 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2457 notify_ielen = le32_to_cpu(bi->ie_length);
2458 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2459
Franky Lin83cf17a2013-04-11 13:28:50 +02002460 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002461 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2462 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2463 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002464
Franky Line78946e2011-11-10 20:30:34 +01002465 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002466 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002467 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2468
Franky Line78946e2011-11-10 20:30:34 +01002469 if (!bss) {
2470 err = -ENOMEM;
2471 goto CleanUp;
2472 }
2473
Johannes Berg5b112d32013-02-01 01:49:58 +01002474 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002475
Arend van Spriel5b435de2011-10-05 13:19:03 +02002476CleanUp:
2477
2478 kfree(buf);
2479
Arend van Sprield96b8012012-12-05 15:26:02 +01002480 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002481
2482 return err;
2483}
2484
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002485static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002486{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002487 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488}
2489
Hante Meuleman89286dc2013-02-08 15:53:46 +01002490static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2491 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002492{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002493 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002494 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002495 struct brcmf_ssid *ssid;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002496 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497 u16 beacon_interval;
2498 u8 dtim_period;
2499 size_t ie_len;
2500 u8 *ie;
2501 s32 err = 0;
2502
Arend van Sprield96b8012012-12-05 15:26:02 +01002503 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002504 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002505 return err;
2506
Arend van Spriel06bb1232012-09-27 14:17:56 +02002507 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002508
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002509 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002510 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002511 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002512 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002513 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002514 goto update_bss_info_out;
2515 }
2516
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002517 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2518 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002519 if (err)
2520 goto update_bss_info_out;
2521
2522 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2523 ie_len = le32_to_cpu(bi->ie_length);
2524 beacon_interval = le16_to_cpu(bi->beacon_period);
2525
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002526 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002527 if (tim)
2528 dtim_period = tim->data[1];
2529 else {
2530 /*
2531 * active scan was done so we could not get dtim
2532 * information out of probe response.
2533 * so we speficially query dtim information to dongle.
2534 */
2535 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002536 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002537 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002538 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002539 goto update_bss_info_out;
2540 }
2541 dtim_period = (u8)var;
2542 }
2543
Arend van Spriel5b435de2011-10-05 13:19:03 +02002544update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002545 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002546 return err;
2547}
2548
Hante Meuleman18e2f612013-02-08 15:53:49 +01002549void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002550{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002551 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002552
Arend van Sprielc1179032012-10-22 13:55:33 -07002553 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002554 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002555 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002556 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002557 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002558 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2559 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002560}
2561
Hante Meulemane756af52012-09-11 21:18:52 +02002562static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2563{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002564 struct brcmf_cfg80211_info *cfg =
2565 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002566 escan_timeout_work);
2567
Arend van Spriela0f472a2013-04-05 10:57:49 +02002568 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002569}
2570
2571static void brcmf_escan_timeout(unsigned long data)
2572{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002573 struct brcmf_cfg80211_info *cfg =
2574 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002575
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002576 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002577 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002578 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002579 }
2580}
2581
2582static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002583brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2584 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002585 struct brcmf_bss_info_le *bss_info_le)
2586{
Franky Lin83cf17a2013-04-11 13:28:50 +02002587 struct brcmu_chan ch_bss, ch_bss_info_le;
2588
2589 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2590 cfg->d11inf.decchspec(&ch_bss);
2591 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2592 cfg->d11inf.decchspec(&ch_bss_info_le);
2593
Hante Meulemane756af52012-09-11 21:18:52 +02002594 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002595 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002596 bss_info_le->SSID_len == bss->SSID_len &&
2597 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002598 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2599 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002600 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2601 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2602
Hante Meulemane756af52012-09-11 21:18:52 +02002603 /* preserve max RSSI if the measurements are
2604 * both on-channel or both off-channel
2605 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002606 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002607 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002608 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2609 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002610 /* preserve the on-channel rssi measurement
2611 * if the new measurement is off channel
2612 */
2613 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002614 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002615 }
2616 return 1;
2617 }
2618 return 0;
2619}
2620
2621static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002622brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002623 const struct brcmf_event_msg *e, void *data)
2624{
Arend van Spriel19937322012-11-05 16:22:32 -08002625 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002626 s32 status;
2627 s32 err = 0;
2628 struct brcmf_escan_result_le *escan_result_le;
2629 struct brcmf_bss_info_le *bss_info_le;
2630 struct brcmf_bss_info_le *bss = NULL;
2631 u32 bi_length;
2632 struct brcmf_scan_results *list;
2633 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002634 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002635
Arend van Spriel5c36b992012-11-14 18:46:05 -08002636 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002637
Arend van Spriela0f472a2013-04-05 10:57:49 +02002638 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2639 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002640 return -EPERM;
2641 }
2642
2643 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002644 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002645 escan_result_le = (struct brcmf_escan_result_le *) data;
2646 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002647 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002648 goto exit;
2649 }
Hante Meulemane756af52012-09-11 21:18:52 +02002650 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002651 brcmf_err("Invalid bss_count %d: ignoring\n",
2652 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002653 goto exit;
2654 }
2655 bss_info_le = &escan_result_le->bss_info_le;
2656
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002657 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2658 goto exit;
2659
2660 if (!cfg->scan_request) {
2661 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2662 goto exit;
2663 }
2664
Hante Meulemane756af52012-09-11 21:18:52 +02002665 bi_length = le32_to_cpu(bss_info_le->length);
2666 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2667 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002668 brcmf_err("Invalid bss_info length %d: ignoring\n",
2669 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002670 goto exit;
2671 }
2672
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002673 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002674 BIT(NL80211_IFTYPE_ADHOC))) {
2675 if (le16_to_cpu(bss_info_le->capability) &
2676 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002677 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002678 goto exit;
2679 }
2680 }
2681
2682 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002683 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002684 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002685 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002686 goto exit;
2687 }
2688
2689 for (i = 0; i < list->count; i++) {
2690 bss = bss ? (struct brcmf_bss_info_le *)
2691 ((unsigned char *)bss +
2692 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002693 if (brcmf_compare_update_same_bss(cfg, bss,
2694 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002695 goto exit;
2696 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002697 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002698 bss_info_le, bi_length);
2699 list->version = le32_to_cpu(bss_info_le->version);
2700 list->buflen += bi_length;
2701 list->count++;
2702 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002703 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002704 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2705 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002706 if (cfg->scan_request) {
2707 cfg->bss_list = (struct brcmf_scan_results *)
2708 cfg->escan_info.escan_buf;
2709 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002710 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002711 brcmf_notify_escan_complete(cfg, ifp, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002712 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002713 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002714 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2715 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002716 }
2717exit:
2718 return err;
2719}
2720
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002721static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002722{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002723 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2724 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002725 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2726 /* Init scan_timeout timer */
2727 init_timer(&cfg->escan_timeout);
2728 cfg->escan_timeout.data = (unsigned long) cfg;
2729 cfg->escan_timeout.function = brcmf_escan_timeout;
2730 INIT_WORK(&cfg->escan_timeout_work,
2731 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002732}
2733
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002734static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002735{
2736 if (ms < 1000 / HZ) {
2737 cond_resched();
2738 mdelay(ms);
2739 } else {
2740 msleep(ms);
2741 }
2742}
2743
2744static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2745{
Arend van Sprield96b8012012-12-05 15:26:02 +01002746 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002747
Arend van Spriel5b435de2011-10-05 13:19:03 +02002748 return 0;
2749}
2750
2751static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2752 struct cfg80211_wowlan *wow)
2753{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002754 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2755 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002756 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002757
Arend van Sprield96b8012012-12-05 15:26:02 +01002758 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002759
2760 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002761 * if the primary net_device is not READY there is nothing
2762 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002763 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002764 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2765 if (!check_vif_up(vif))
2766 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002767
Arend van Spriel7d641072012-10-22 13:55:39 -07002768 list_for_each_entry(vif, &cfg->vif_list, list) {
2769 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2770 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002771 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002772 * While going to suspend if associated with AP disassociate
2773 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002774 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002775 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002776
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002777 /* Make sure WPA_Supplicant receives all the event
2778 * generated due to DISASSOC call to the fw to keep
2779 * the state fw and WPA_Supplicant state consistent
2780 */
2781 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002782 }
2783
Arend van Spriel7d641072012-10-22 13:55:39 -07002784 /* end any scanning */
2785 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002786 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002787
2788 /* Turn off watchdog timer */
Arend van Sprielf96aa072013-04-05 10:57:48 +02002789 brcmf_set_mpc(netdev_priv(ndev), 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002790
Arend van Spriel7d641072012-10-22 13:55:39 -07002791exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002792 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002793 /* clear any scanning activity */
2794 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002795 return 0;
2796}
2797
2798static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002799brcmf_update_pmklist(struct net_device *ndev,
2800 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2801{
2802 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002803 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002804
Arend van Spriel40c8e952011-10-12 20:51:20 +02002805 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2806
Arend van Spriel16886732012-12-05 15:26:04 +01002807 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002808 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002809 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2810 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002812 brcmf_dbg(CONN, "%02x\n",
2813 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814 }
2815
2816 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002817 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2818 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819
2820 return err;
2821}
2822
2823static s32
2824brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2825 struct cfg80211_pmksa *pmksa)
2826{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002827 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002828 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002829 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 s32 err = 0;
2831 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002832 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002833
Arend van Sprield96b8012012-12-05 15:26:02 +01002834 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002835 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002836 return -EIO;
2837
Arend van Spriel40c8e952011-10-12 20:51:20 +02002838 pmkid_len = le32_to_cpu(pmkids->npmkid);
2839 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002840 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2841 break;
2842 if (i < WL_NUM_PMKIDS_MAX) {
2843 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2844 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002845 if (i == pmkid_len) {
2846 pmkid_len++;
2847 pmkids->npmkid = cpu_to_le32(pmkid_len);
2848 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002849 } else
2850 err = -EINVAL;
2851
Arend van Spriel16886732012-12-05 15:26:04 +01002852 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2853 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002854 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002855 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002857 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002858
Arend van Sprield96b8012012-12-05 15:26:02 +01002859 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 return err;
2861}
2862
2863static s32
2864brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2865 struct cfg80211_pmksa *pmksa)
2866{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002867 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002868 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002869 struct pmkid_list pmkid;
2870 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002871 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872
Arend van Sprield96b8012012-12-05 15:26:02 +01002873 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002874 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002875 return -EIO;
2876
2877 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2878 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2879
Arend van Spriel16886732012-12-05 15:26:04 +01002880 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2881 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002882 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002883 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002884
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002885 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002886 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002887 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002888 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002889 ETH_ALEN))
2890 break;
2891
Arend van Spriel40c8e952011-10-12 20:51:20 +02002892 if ((pmkid_len > 0)
2893 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002894 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002895 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002896 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002897 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2898 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002899 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002900 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2901 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002902 WLAN_PMKID_LEN);
2903 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002904 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002905 } else
2906 err = -EINVAL;
2907
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002908 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002909
Arend van Sprield96b8012012-12-05 15:26:02 +01002910 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002911 return err;
2912
2913}
2914
2915static s32
2916brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2917{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002918 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002919 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002920 s32 err = 0;
2921
Arend van Sprield96b8012012-12-05 15:26:02 +01002922 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002923 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002924 return -EIO;
2925
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002926 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2927 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928
Arend van Sprield96b8012012-12-05 15:26:02 +01002929 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002930 return err;
2931
2932}
2933
Arend van Spriele5806072012-09-19 22:21:08 +02002934/*
2935 * PFN result doesn't have all the info which are
2936 * required by the supplicant
2937 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2938 * via wl_inform_single_bss in the required format. Escan does require the
2939 * scan request in the form of cfg80211_scan_request. For timebeing, create
2940 * cfg80211_scan_request one out of the received PNO event.
2941 */
2942static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002943brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002944 const struct brcmf_event_msg *e, void *data)
2945{
Arend van Spriel19937322012-11-05 16:22:32 -08002946 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02002947 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2948 struct cfg80211_scan_request *request = NULL;
2949 struct cfg80211_ssid *ssid = NULL;
2950 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002951 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002952 int err = 0;
2953 int channel_req = 0;
2954 int band = 0;
2955 struct brcmf_pno_scanresults_le *pfn_result;
2956 u32 result_count;
2957 u32 status;
2958
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002959 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002960
Arend van Spriel5c36b992012-11-14 18:46:05 -08002961 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002962 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002963 return 0;
2964 }
2965
2966 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2967 result_count = le32_to_cpu(pfn_result->count);
2968 status = le32_to_cpu(pfn_result->status);
2969
2970 /*
2971 * PFN event is limited to fit 512 bytes so we may get
2972 * multiple NET_FOUND events. For now place a warning here.
2973 */
2974 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002975 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002976 if (result_count > 0) {
2977 int i;
2978
2979 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002980 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2981 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002982 if (!request || !ssid || !channel) {
2983 err = -ENOMEM;
2984 goto out_err;
2985 }
2986
2987 request->wiphy = wiphy;
2988 data += sizeof(struct brcmf_pno_scanresults_le);
2989 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2990
2991 for (i = 0; i < result_count; i++) {
2992 netinfo = &netinfo_start[i];
2993 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002994 brcmf_err("Invalid netinfo ptr. index: %d\n",
2995 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002996 err = -EINVAL;
2997 goto out_err;
2998 }
2999
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003000 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3001 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02003002 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3003 ssid[i].ssid_len = netinfo->SSID_len;
3004 request->n_ssids++;
3005
3006 channel_req = netinfo->channel;
3007 if (channel_req <= CH_MAX_2G_CHANNEL)
3008 band = NL80211_BAND_2GHZ;
3009 else
3010 band = NL80211_BAND_5GHZ;
3011 channel[i].center_freq =
3012 ieee80211_channel_to_frequency(channel_req,
3013 band);
3014 channel[i].band = band;
3015 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3016 request->channels[i] = &channel[i];
3017 request->n_channels++;
3018 }
3019
3020 /* assign parsed ssid array */
3021 if (request->n_ssids)
3022 request->ssids = &ssid[0];
3023
Arend van Sprielc1179032012-10-22 13:55:33 -07003024 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02003025 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003026 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003027 }
3028
Arend van Sprielc1179032012-10-22 13:55:33 -07003029 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel2668b0b2014-01-13 22:20:28 +01003030 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003031 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02003032 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003033 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003034 goto out_err;
3035 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003036 cfg->sched_escan = true;
3037 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02003038 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003039 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003040 goto out_err;
3041 }
3042
3043 kfree(ssid);
3044 kfree(channel);
3045 kfree(request);
3046 return 0;
3047
3048out_err:
3049 kfree(ssid);
3050 kfree(channel);
3051 kfree(request);
3052 cfg80211_sched_scan_stopped(wiphy);
3053 return err;
3054}
3055
Arend van Spriele5806072012-09-19 22:21:08 +02003056static int brcmf_dev_pno_clean(struct net_device *ndev)
3057{
Arend van Spriele5806072012-09-19 22:21:08 +02003058 int ret;
3059
3060 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003061 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003062 if (ret == 0) {
3063 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003064 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3065 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003066 }
3067 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003068 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003069
3070 return ret;
3071}
3072
3073static int brcmf_dev_pno_config(struct net_device *ndev)
3074{
3075 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003076
3077 memset(&pfn_param, 0, sizeof(pfn_param));
3078 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3079
3080 /* set extra pno params */
3081 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3082 pfn_param.repeat = BRCMF_PNO_REPEAT;
3083 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3084
3085 /* set up pno scan fr */
3086 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3087
Arend van Sprielac24be62012-10-22 10:36:23 -07003088 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3089 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003090}
3091
3092static int
3093brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3094 struct net_device *ndev,
3095 struct cfg80211_sched_scan_request *request)
3096{
Arend van Sprielc1179032012-10-22 13:55:33 -07003097 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003098 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003099 struct brcmf_pno_net_param_le pfn;
3100 int i;
3101 int ret = 0;
3102
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003103 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003104 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003105 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003106 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003107 return -EAGAIN;
3108 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003109 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3110 brcmf_err("Scanning suppressed: status (%lu)\n",
3111 cfg->scan_status);
3112 return -EAGAIN;
3113 }
Arend van Spriele5806072012-09-19 22:21:08 +02003114
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003115 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003116 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003117 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003118 return -EINVAL;
3119 }
3120
3121 if (request->n_ssids > 0) {
3122 for (i = 0; i < request->n_ssids; i++) {
3123 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003124 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3125 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003126
3127 /*
3128 * match_set ssids is a supert set of n_ssid list,
3129 * so we need not add these set seperately.
3130 */
3131 }
3132 }
3133
3134 if (request->n_match_sets > 0) {
3135 /* clean up everything */
3136 ret = brcmf_dev_pno_clean(ndev);
3137 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003138 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003139 return ret;
3140 }
3141
3142 /* configure pno */
3143 ret = brcmf_dev_pno_config(ndev);
3144 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003145 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003146 return -EINVAL;
3147 }
3148
3149 /* configure each match set */
3150 for (i = 0; i < request->n_match_sets; i++) {
3151 struct cfg80211_ssid *ssid;
3152 u32 ssid_len;
3153
3154 ssid = &request->match_sets[i].ssid;
3155 ssid_len = ssid->ssid_len;
3156
3157 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003158 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003159 continue;
3160 }
3161 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3162 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3163 pfn.wsec = cpu_to_le32(0);
3164 pfn.infra = cpu_to_le32(1);
3165 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3166 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3167 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003168 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003169 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003170 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3171 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003172 }
3173 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003174 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003175 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003176 return -EINVAL;
3177 }
3178 } else {
3179 return -EINVAL;
3180 }
3181
3182 return 0;
3183}
3184
3185static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3186 struct net_device *ndev)
3187{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003188 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003189
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003190 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003191 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003192 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003193 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003194 return 0;
3195}
Arend van Spriele5806072012-09-19 22:21:08 +02003196
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003197#ifdef CONFIG_NL80211_TESTMODE
David Spinadelfc73f112013-07-31 18:04:15 +03003198static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3199 struct wireless_dev *wdev,
3200 void *data, int len)
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003201{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003202 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003203 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003204 struct brcmf_dcmd *dcmd = data;
3205 struct sk_buff *reply;
3206 int ret;
3207
Arend van Sprield96b8012012-12-05 15:26:02 +01003208 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3209 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003210
3211 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003212 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3213 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003214 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003215 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3216 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003217 if (ret == 0) {
3218 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3219 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3220 ret = cfg80211_testmode_reply(reply);
3221 }
3222 return ret;
3223}
3224#endif
3225
Hante Meuleman1f170112013-02-06 18:40:38 +01003226static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003227{
3228 s32 err;
3229
3230 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003231 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003232 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003233 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003234 return err;
3235 }
3236 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003237 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003238 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003239 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003240 return err;
3241 }
3242 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003243 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003244 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003245 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003246 return err;
3247 }
3248
3249 return 0;
3250}
3251
3252static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3253{
3254 if (is_rsn_ie)
3255 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3256
3257 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3258}
3259
3260static s32
Johannes Berg4b5800f2014-01-15 14:55:59 +01003261brcmf_configure_wpaie(struct net_device *ndev,
3262 const struct brcmf_vs_tlv *wpa_ie,
3263 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003264{
Arend van Sprielac24be62012-10-22 10:36:23 -07003265 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003266 u32 auth = 0; /* d11 open authentication */
3267 u16 count;
3268 s32 err = 0;
3269 s32 len = 0;
3270 u32 i;
3271 u32 wsec;
3272 u32 pval = 0;
3273 u32 gval = 0;
3274 u32 wpa_auth = 0;
3275 u32 offset;
3276 u8 *data;
3277 u16 rsn_cap;
3278 u32 wme_bss_disable;
3279
Arend van Sprield96b8012012-12-05 15:26:02 +01003280 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003281 if (wpa_ie == NULL)
3282 goto exit;
3283
3284 len = wpa_ie->len + TLV_HDR_LEN;
3285 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003286 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003287 if (!is_rsn_ie)
3288 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003289 else
3290 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003291
3292 /* check for multicast cipher suite */
3293 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3294 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003295 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003296 goto exit;
3297 }
3298
3299 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3300 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003301 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003302 goto exit;
3303 }
3304 offset += TLV_OUI_LEN;
3305
3306 /* pick up multicast cipher */
3307 switch (data[offset]) {
3308 case WPA_CIPHER_NONE:
3309 gval = 0;
3310 break;
3311 case WPA_CIPHER_WEP_40:
3312 case WPA_CIPHER_WEP_104:
3313 gval = WEP_ENABLED;
3314 break;
3315 case WPA_CIPHER_TKIP:
3316 gval = TKIP_ENABLED;
3317 break;
3318 case WPA_CIPHER_AES_CCM:
3319 gval = AES_ENABLED;
3320 break;
3321 default:
3322 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003323 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003324 goto exit;
3325 }
3326
3327 offset++;
3328 /* walk thru unicast cipher list and pick up what we recognize */
3329 count = data[offset] + (data[offset + 1] << 8);
3330 offset += WPA_IE_SUITE_COUNT_LEN;
3331 /* Check for unicast suite(s) */
3332 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3333 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003334 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003335 goto exit;
3336 }
3337 for (i = 0; i < count; i++) {
3338 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3339 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003340 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003341 goto exit;
3342 }
3343 offset += TLV_OUI_LEN;
3344 switch (data[offset]) {
3345 case WPA_CIPHER_NONE:
3346 break;
3347 case WPA_CIPHER_WEP_40:
3348 case WPA_CIPHER_WEP_104:
3349 pval |= WEP_ENABLED;
3350 break;
3351 case WPA_CIPHER_TKIP:
3352 pval |= TKIP_ENABLED;
3353 break;
3354 case WPA_CIPHER_AES_CCM:
3355 pval |= AES_ENABLED;
3356 break;
3357 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003358 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003359 }
3360 offset++;
3361 }
3362 /* walk thru auth management suite list and pick up what we recognize */
3363 count = data[offset] + (data[offset + 1] << 8);
3364 offset += WPA_IE_SUITE_COUNT_LEN;
3365 /* Check for auth key management suite(s) */
3366 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3367 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003368 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003369 goto exit;
3370 }
3371 for (i = 0; i < count; i++) {
3372 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3373 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003374 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003375 goto exit;
3376 }
3377 offset += TLV_OUI_LEN;
3378 switch (data[offset]) {
3379 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003380 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003381 wpa_auth |= WPA_AUTH_NONE;
3382 break;
3383 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003384 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003385 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3386 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3387 break;
3388 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003389 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003390 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3391 (wpa_auth |= WPA_AUTH_PSK);
3392 break;
3393 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003394 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003395 }
3396 offset++;
3397 }
3398
3399 if (is_rsn_ie) {
3400 wme_bss_disable = 1;
3401 if ((offset + RSN_CAP_LEN) <= len) {
3402 rsn_cap = data[offset] + (data[offset + 1] << 8);
3403 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3404 wme_bss_disable = 0;
3405 }
3406 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003407 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003408 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003409 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003410 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003411 goto exit;
3412 }
3413 }
3414 /* FOR WPS , set SES_OW_ENABLED */
3415 wsec = (pval | gval | SES_OW_ENABLED);
3416
3417 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003418 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003419 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003420 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003421 goto exit;
3422 }
3423 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003424 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003425 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003426 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003427 goto exit;
3428 }
3429 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003430 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003431 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003432 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003433 goto exit;
3434 }
3435
3436exit:
3437 return err;
3438}
3439
3440static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003441brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003442 struct parsed_vndr_ies *vndr_ies)
3443{
3444 s32 err = 0;
3445 struct brcmf_vs_tlv *vndrie;
3446 struct brcmf_tlv *ie;
3447 struct parsed_vndr_ie_info *parsed_info;
3448 s32 remaining_len;
3449
3450 remaining_len = (s32)vndr_ie_len;
3451 memset(vndr_ies, 0, sizeof(*vndr_ies));
3452
3453 ie = (struct brcmf_tlv *)vndr_ie_buf;
3454 while (ie) {
3455 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3456 goto next;
3457 vndrie = (struct brcmf_vs_tlv *)ie;
3458 /* len should be bigger than OUI length + one */
3459 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003460 brcmf_err("invalid vndr ie. length is too small %d\n",
3461 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003462 goto next;
3463 }
3464 /* if wpa or wme ie, do not add ie */
3465 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3466 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3467 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003468 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003469 goto next;
3470 }
3471
3472 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3473
3474 /* save vndr ie information */
3475 parsed_info->ie_ptr = (char *)vndrie;
3476 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3477 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3478
3479 vndr_ies->count++;
3480
Arend van Sprield96b8012012-12-05 15:26:02 +01003481 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3482 parsed_info->vndrie.oui[0],
3483 parsed_info->vndrie.oui[1],
3484 parsed_info->vndrie.oui[2],
3485 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003486
Arend van Spriel9f440b72013-02-08 15:53:36 +01003487 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003488 break;
3489next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003490 remaining_len -= (ie->len + TLV_HDR_LEN);
3491 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003492 ie = NULL;
3493 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003494 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3495 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003496 }
3497 return err;
3498}
3499
3500static u32
3501brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3502{
3503
3504 __le32 iecount_le;
3505 __le32 pktflag_le;
3506
3507 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3508 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3509
3510 iecount_le = cpu_to_le32(1);
3511 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3512
3513 pktflag_le = cpu_to_le32(pktflag);
3514 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3515
3516 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3517
3518 return ie_len + VNDR_IE_HDR_SIZE;
3519}
3520
Arend van Spriel1332e262012-11-05 16:22:18 -08003521s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3522 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003523{
Arend van Spriel1332e262012-11-05 16:22:18 -08003524 struct brcmf_if *ifp;
3525 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003526 s32 err = 0;
3527 u8 *iovar_ie_buf;
3528 u8 *curr_ie_buf;
3529 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003530 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003531 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003532 u32 del_add_ie_buf_len = 0;
3533 u32 total_ie_buf_len = 0;
3534 u32 parsed_ie_buf_len = 0;
3535 struct parsed_vndr_ies old_vndr_ies;
3536 struct parsed_vndr_ies new_vndr_ies;
3537 struct parsed_vndr_ie_info *vndrie_info;
3538 s32 i;
3539 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003540 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003541
Arend van Spriel1332e262012-11-05 16:22:18 -08003542 if (!vif)
3543 return -ENODEV;
3544 ifp = vif->ifp;
3545 saved_ie = &vif->saved_ie;
3546
Arend van Sprield96b8012012-12-05 15:26:02 +01003547 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003548 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3549 if (!iovar_ie_buf)
3550 return -ENOMEM;
3551 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003552 switch (pktflag) {
3553 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3554 mgmt_ie_buf = saved_ie->probe_req_ie;
3555 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3556 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3557 break;
3558 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3559 mgmt_ie_buf = saved_ie->probe_res_ie;
3560 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3561 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3562 break;
3563 case BRCMF_VNDR_IE_BEACON_FLAG:
3564 mgmt_ie_buf = saved_ie->beacon_ie;
3565 mgmt_ie_len = &saved_ie->beacon_ie_len;
3566 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3567 break;
3568 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3569 mgmt_ie_buf = saved_ie->assoc_req_ie;
3570 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3571 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3572 break;
3573 default:
3574 err = -EPERM;
3575 brcmf_err("not suitable type\n");
3576 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003577 }
3578
3579 if (vndr_ie_len > mgmt_ie_buf_len) {
3580 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003581 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003582 goto exit;
3583 }
3584
3585 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3586 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3587 ptr = curr_ie_buf;
3588 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3589 for (i = 0; i < new_vndr_ies.count; i++) {
3590 vndrie_info = &new_vndr_ies.ie_info[i];
3591 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3592 vndrie_info->ie_len);
3593 parsed_ie_buf_len += vndrie_info->ie_len;
3594 }
3595 }
3596
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003597 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003598 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3599 (memcmp(mgmt_ie_buf, curr_ie_buf,
3600 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003601 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003602 goto exit;
3603 }
3604
3605 /* parse old vndr_ie */
3606 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3607
3608 /* make a command to delete old ie */
3609 for (i = 0; i < old_vndr_ies.count; i++) {
3610 vndrie_info = &old_vndr_ies.ie_info[i];
3611
Arend van Sprield96b8012012-12-05 15:26:02 +01003612 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3613 vndrie_info->vndrie.id,
3614 vndrie_info->vndrie.len,
3615 vndrie_info->vndrie.oui[0],
3616 vndrie_info->vndrie.oui[1],
3617 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003618
3619 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3620 vndrie_info->ie_ptr,
3621 vndrie_info->ie_len,
3622 "del");
3623 curr_ie_buf += del_add_ie_buf_len;
3624 total_ie_buf_len += del_add_ie_buf_len;
3625 }
3626 }
3627
3628 *mgmt_ie_len = 0;
3629 /* Add if there is any extra IE */
3630 if (mgmt_ie_buf && parsed_ie_buf_len) {
3631 ptr = mgmt_ie_buf;
3632
3633 remained_buf_len = mgmt_ie_buf_len;
3634
3635 /* make a command to add new ie */
3636 for (i = 0; i < new_vndr_ies.count; i++) {
3637 vndrie_info = &new_vndr_ies.ie_info[i];
3638
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003639 /* verify remained buf size before copy data */
3640 if (remained_buf_len < (vndrie_info->vndrie.len +
3641 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003642 brcmf_err("no space in mgmt_ie_buf: len left %d",
3643 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003644 break;
3645 }
3646 remained_buf_len -= (vndrie_info->ie_len +
3647 VNDR_IE_VSIE_OFFSET);
3648
Arend van Sprield96b8012012-12-05 15:26:02 +01003649 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3650 vndrie_info->vndrie.id,
3651 vndrie_info->vndrie.len,
3652 vndrie_info->vndrie.oui[0],
3653 vndrie_info->vndrie.oui[1],
3654 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003655
3656 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3657 vndrie_info->ie_ptr,
3658 vndrie_info->ie_len,
3659 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003660
3661 /* save the parsed IE in wl struct */
3662 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3663 vndrie_info->ie_len);
3664 *mgmt_ie_len += vndrie_info->ie_len;
3665
3666 curr_ie_buf += del_add_ie_buf_len;
3667 total_ie_buf_len += del_add_ie_buf_len;
3668 }
3669 }
3670 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003671 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003672 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003673 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003674 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003675 }
3676
3677exit:
3678 kfree(iovar_ie_buf);
3679 return err;
3680}
3681
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003682s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3683{
3684 s32 pktflags[] = {
3685 BRCMF_VNDR_IE_PRBREQ_FLAG,
3686 BRCMF_VNDR_IE_PRBRSP_FLAG,
3687 BRCMF_VNDR_IE_BEACON_FLAG
3688 };
3689 int i;
3690
3691 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3692 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3693
3694 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3695 return 0;
3696}
3697
Hante Meuleman1a873342012-09-27 14:17:54 +02003698static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003699brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3700 struct cfg80211_beacon_data *beacon)
3701{
3702 s32 err;
3703
3704 /* Set Beacon IEs to FW */
3705 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3706 beacon->tail, beacon->tail_len);
3707 if (err) {
3708 brcmf_err("Set Beacon IE Failed\n");
3709 return err;
3710 }
3711 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3712
3713 /* Set Probe Response IEs to FW */
3714 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3715 beacon->proberesp_ies,
3716 beacon->proberesp_ies_len);
3717 if (err)
3718 brcmf_err("Set Probe Resp IE Failed\n");
3719 else
3720 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3721
3722 return err;
3723}
3724
3725static s32
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003726brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
3727 struct brcmf_if *ifp,
3728 struct ieee80211_channel *channel)
3729{
3730 u16 chanspec;
3731 s32 err;
3732
3733 brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
3734 channel->center_freq);
3735
3736 chanspec = channel_to_chanspec(&cfg->d11inf, channel);
3737 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3738
3739 return err;
3740}
3741
3742static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003743brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3744 struct cfg80211_ap_settings *settings)
3745{
3746 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003747 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07003748 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01003749 const struct brcmf_tlv *ssid_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003750 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003751 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01003752 const struct brcmf_tlv *rsn_ie;
3753 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003754 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003755 enum nl80211_iftype dev_role;
3756 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003757
Arend van Sprield96b8012012-12-05 15:26:02 +01003758 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3759 cfg80211_get_chandef_type(&settings->chandef),
3760 settings->beacon_interval,
3761 settings->dtim_period);
3762 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3763 settings->ssid, settings->ssid_len, settings->auth_type,
3764 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003765
Hante Meuleman426d0a52013-02-08 15:53:53 +01003766 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003767
3768 memset(&ssid_le, 0, sizeof(ssid_le));
3769 if (settings->ssid == NULL || settings->ssid_len == 0) {
3770 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3771 ssid_ie = brcmf_parse_tlvs(
3772 (u8 *)&settings->beacon.head[ie_offset],
3773 settings->beacon.head_len - ie_offset,
3774 WLAN_EID_SSID);
3775 if (!ssid_ie)
3776 return -EINVAL;
3777
3778 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3779 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003780 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003781 } else {
3782 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3783 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3784 }
3785
Arend van Sprielf96aa072013-04-05 10:57:48 +02003786 brcmf_set_mpc(ifp, 0);
Hante Meulemanb3657452013-05-27 21:09:53 +02003787 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003788
3789 /* find the RSN_IE */
3790 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3791 settings->beacon.tail_len, WLAN_EID_RSN);
3792
3793 /* find the WPA_IE */
3794 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3795 settings->beacon.tail_len);
3796
Hante Meuleman1a873342012-09-27 14:17:54 +02003797 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003798 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003799 if (wpa_ie != NULL) {
3800 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003801 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003802 if (err < 0)
3803 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003804 } else {
3805 /* RSN IE */
3806 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003807 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003808 if (err < 0)
3809 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003810 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003811 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003812 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003813 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003814 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003815
Hante Meulemana0f07952013-02-08 15:53:47 +01003816 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003817
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003818 err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
3819 if (err < 0) {
3820 brcmf_err("Set Channel failed, %d\n", err);
3821 goto exit;
3822 }
3823
Hante Meuleman1a873342012-09-27 14:17:54 +02003824 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003825 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003826 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003827 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003828 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003829 goto exit;
3830 }
3831 }
3832 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003833 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003834 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003835 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003836 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003837 goto exit;
3838 }
3839 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003840
3841 if (dev_role == NL80211_IFTYPE_AP) {
3842 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3843 if (err < 0) {
3844 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3845 goto exit;
3846 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003847 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003848 }
3849
Hante Meulemana0f07952013-02-08 15:53:47 +01003850 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003851 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003852 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003853 goto exit;
3854 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003855 if (dev_role == NL80211_IFTYPE_AP) {
3856 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3857 if (err < 0) {
3858 brcmf_err("setting AP mode failed %d\n", err);
3859 goto exit;
3860 }
3861 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3862 if (err < 0) {
3863 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3864 goto exit;
3865 }
3866
3867 memset(&join_params, 0, sizeof(join_params));
3868 /* join parameters starts with ssid */
3869 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3870 /* create softap */
3871 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3872 &join_params, sizeof(join_params));
3873 if (err < 0) {
3874 brcmf_err("SET SSID error (%d)\n", err);
3875 goto exit;
3876 }
3877 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3878 } else {
3879 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3880 sizeof(ssid_le));
3881 if (err < 0) {
3882 brcmf_err("setting ssid failed %d\n", err);
3883 goto exit;
3884 }
3885 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3886 bss_enable.enable = cpu_to_le32(1);
3887 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3888 sizeof(bss_enable));
3889 if (err < 0) {
3890 brcmf_err("bss_enable config failed %d\n", err);
3891 goto exit;
3892 }
3893
3894 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3895 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003896 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3897 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003898
3899exit:
Hante Meulemanb3657452013-05-27 21:09:53 +02003900 if (err) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02003901 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003902 brcmf_configure_arp_offload(ifp, true);
3903 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003904 return err;
3905}
3906
3907static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3908{
Arend van Sprielc1179032012-10-22 13:55:33 -07003909 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003910 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003911 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02003912 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003913
Arend van Sprield96b8012012-12-05 15:26:02 +01003914 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003915
Hante Meuleman426d0a52013-02-08 15:53:53 +01003916 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003917 /* Due to most likely deauths outstanding we sleep */
3918 /* first to make sure they get processed by fw. */
3919 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003920
3921 memset(&join_params, 0, sizeof(join_params));
3922 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3923 &join_params, sizeof(join_params));
3924 if (err < 0)
3925 brcmf_err("SET SSID error (%d)\n", err);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003926 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003927 if (err < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003928 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003929 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3930 if (err < 0)
3931 brcmf_err("setting AP mode failed %d\n", err);
3932 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3933 if (err < 0)
3934 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003935 } else {
3936 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3937 bss_enable.enable = cpu_to_le32(0);
3938 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3939 sizeof(bss_enable));
3940 if (err < 0)
3941 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003942 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02003943 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003944 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003945 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3946 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3947
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 return err;
3949}
3950
Hante Meulemana0f07952013-02-08 15:53:47 +01003951static s32
3952brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3953 struct cfg80211_beacon_data *info)
3954{
Hante Meulemana0f07952013-02-08 15:53:47 +01003955 struct brcmf_if *ifp = netdev_priv(ndev);
3956 s32 err;
3957
3958 brcmf_dbg(TRACE, "Enter\n");
3959
Hante Meulemana0f07952013-02-08 15:53:47 +01003960 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3961
3962 return err;
3963}
3964
Hante Meuleman1a873342012-09-27 14:17:54 +02003965static int
3966brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3967 u8 *mac)
3968{
Hante Meulemana0f07952013-02-08 15:53:47 +01003969 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003970 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003971 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003972 s32 err;
3973
3974 if (!mac)
3975 return -EFAULT;
3976
Arend van Sprield96b8012012-12-05 15:26:02 +01003977 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003978
Hante Meulemana0f07952013-02-08 15:53:47 +01003979 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3980 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003981 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003982 return -EIO;
3983
3984 memcpy(&scbval.ea, mac, ETH_ALEN);
3985 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003986 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003987 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003989 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01003990
Arend van Sprield96b8012012-12-05 15:26:02 +01003991 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003992 return err;
3993}
3994
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003995
3996static void
3997brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3998 struct wireless_dev *wdev,
3999 u16 frame_type, bool reg)
4000{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004001 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004002 u16 mgmt_type;
4003
4004 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4005
4006 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004007 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004008 if (reg)
4009 vif->mgmt_rx_reg |= BIT(mgmt_type);
4010 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004011 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004012}
4013
4014
4015static int
4016brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004017 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004018{
4019 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004020 struct ieee80211_channel *chan = params->chan;
4021 const u8 *buf = params->buf;
4022 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004023 const struct ieee80211_mgmt *mgmt;
4024 struct brcmf_cfg80211_vif *vif;
4025 s32 err = 0;
4026 s32 ie_offset;
4027 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004028 struct brcmf_fil_action_frame_le *action_frame;
4029 struct brcmf_fil_af_params_le *af_params;
4030 bool ack;
4031 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004032 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004033
4034 brcmf_dbg(TRACE, "Enter\n");
4035
4036 *cookie = 0;
4037
4038 mgmt = (const struct ieee80211_mgmt *)buf;
4039
Hante Meulemana0f07952013-02-08 15:53:47 +01004040 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4041 brcmf_err("Driver only allows MGMT packet type\n");
4042 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004043 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004044
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004045 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4046
Hante Meulemana0f07952013-02-08 15:53:47 +01004047 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4048 /* Right now the only reason to get a probe response */
4049 /* is for p2p listen response or for p2p GO from */
4050 /* wpa_supplicant. Unfortunately the probe is send */
4051 /* on primary ndev, while dongle wants it on the p2p */
4052 /* vif. Since this is only reason for a probe */
4053 /* response to be sent, the vif is taken from cfg. */
4054 /* If ever desired to send proberesp for non p2p */
4055 /* response then data should be checked for */
4056 /* "DIRECT-". Note in future supplicant will take */
4057 /* dedicated p2p wdev to do this and then this 'hack'*/
4058 /* is not needed anymore. */
4059 ie_offset = DOT11_MGMT_HDR_LEN +
4060 DOT11_BCN_PRB_FIXED_LEN;
4061 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004062 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4063 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4064 err = brcmf_vif_set_mgmt_ie(vif,
4065 BRCMF_VNDR_IE_PRBRSP_FLAG,
4066 &buf[ie_offset],
4067 ie_len);
4068 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4069 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004070 } else if (ieee80211_is_action(mgmt->frame_control)) {
4071 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4072 if (af_params == NULL) {
4073 brcmf_err("unable to allocate frame\n");
4074 err = -ENOMEM;
4075 goto exit;
4076 }
4077 action_frame = &af_params->action_frame;
4078 /* Add the packet Id */
4079 action_frame->packet_id = cpu_to_le32(*cookie);
4080 /* Add BSSID */
4081 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4082 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4083 /* Add the length exepted for 802.11 header */
4084 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004085 /* Add the channel. Use the one specified as parameter if any or
4086 * the current one (got from the firmware) otherwise
4087 */
4088 if (chan)
4089 freq = chan->center_freq;
4090 else
4091 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4092 &freq);
4093 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004094 af_params->channel = cpu_to_le32(chan_nr);
4095
4096 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4097 le16_to_cpu(action_frame->len));
4098
4099 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004100 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004101
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004102 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004103 af_params);
4104
4105 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4106 GFP_KERNEL);
4107 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004108 } else {
4109 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4110 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4111 }
4112
Hante Meuleman18e2f612013-02-08 15:53:49 +01004113exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004114 return err;
4115}
4116
4117
4118static int
4119brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4120 struct wireless_dev *wdev,
4121 u64 cookie)
4122{
4123 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4124 struct brcmf_cfg80211_vif *vif;
4125 int err = 0;
4126
4127 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4128
4129 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4130 if (vif == NULL) {
4131 brcmf_err("No p2p device available for probe response\n");
4132 err = -ENODEV;
4133 goto exit;
4134 }
4135 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4136exit:
4137 return err;
4138}
4139
Piotr Haber61730d42013-04-23 12:53:12 +02004140static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4141 struct wireless_dev *wdev,
4142 enum nl80211_crit_proto_id proto,
4143 u16 duration)
4144{
4145 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4146 struct brcmf_cfg80211_vif *vif;
4147
4148 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4149
4150 /* only DHCP support for now */
4151 if (proto != NL80211_CRIT_PROTO_DHCP)
4152 return -EINVAL;
4153
4154 /* suppress and abort scanning */
4155 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4156 brcmf_abort_scanning(cfg);
4157
4158 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4159}
4160
4161static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4162 struct wireless_dev *wdev)
4163{
4164 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4165 struct brcmf_cfg80211_vif *vif;
4166
4167 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4168
4169 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4170 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4171}
4172
Arend van Spriel89c2f382013-08-10 12:27:25 +02004173static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4174{
4175 int ret;
4176
4177 switch (oper) {
4178 case NL80211_TDLS_DISCOVERY_REQ:
4179 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4180 break;
4181 case NL80211_TDLS_SETUP:
4182 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4183 break;
4184 case NL80211_TDLS_TEARDOWN:
4185 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4186 break;
4187 default:
4188 brcmf_err("unsupported operation: %d\n", oper);
4189 ret = -EOPNOTSUPP;
4190 }
4191 return ret;
4192}
4193
4194static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4195 struct net_device *ndev, u8 *peer,
4196 enum nl80211_tdls_operation oper)
4197{
4198 struct brcmf_if *ifp;
4199 struct brcmf_tdls_iovar_le info;
4200 int ret = 0;
4201
4202 ret = brcmf_convert_nl80211_tdls_oper(oper);
4203 if (ret < 0)
4204 return ret;
4205
4206 ifp = netdev_priv(ndev);
4207 memset(&info, 0, sizeof(info));
4208 info.mode = (u8)ret;
4209 if (peer)
4210 memcpy(info.ea, peer, ETH_ALEN);
4211
4212 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4213 &info, sizeof(info));
4214 if (ret < 0)
4215 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4216
4217 return ret;
4218}
4219
Arend van Spriel5b435de2011-10-05 13:19:03 +02004220static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004221 .add_virtual_intf = brcmf_cfg80211_add_iface,
4222 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004223 .change_virtual_intf = brcmf_cfg80211_change_iface,
4224 .scan = brcmf_cfg80211_scan,
4225 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4226 .join_ibss = brcmf_cfg80211_join_ibss,
4227 .leave_ibss = brcmf_cfg80211_leave_ibss,
4228 .get_station = brcmf_cfg80211_get_station,
4229 .set_tx_power = brcmf_cfg80211_set_tx_power,
4230 .get_tx_power = brcmf_cfg80211_get_tx_power,
4231 .add_key = brcmf_cfg80211_add_key,
4232 .del_key = brcmf_cfg80211_del_key,
4233 .get_key = brcmf_cfg80211_get_key,
4234 .set_default_key = brcmf_cfg80211_config_default_key,
4235 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4236 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004237 .connect = brcmf_cfg80211_connect,
4238 .disconnect = brcmf_cfg80211_disconnect,
4239 .suspend = brcmf_cfg80211_suspend,
4240 .resume = brcmf_cfg80211_resume,
4241 .set_pmksa = brcmf_cfg80211_set_pmksa,
4242 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004243 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004244 .start_ap = brcmf_cfg80211_start_ap,
4245 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004246 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004247 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004248 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4249 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004250 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4251 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4252 .remain_on_channel = brcmf_p2p_remain_on_channel,
4253 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004254 .start_p2p_device = brcmf_p2p_start_device,
4255 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004256 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4257 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004258 .tdls_oper = brcmf_cfg80211_tdls_oper,
Johannes Berge3335472013-08-06 11:13:19 +02004259 CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004260};
4261
Arend van Spriel9f440b72013-02-08 15:53:36 +01004262static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004263{
Arend van Spriel9f440b72013-02-08 15:53:36 +01004264 switch (type) {
4265 case NL80211_IFTYPE_AP_VLAN:
4266 case NL80211_IFTYPE_WDS:
4267 case NL80211_IFTYPE_MONITOR:
4268 case NL80211_IFTYPE_MESH_POINT:
4269 return -ENOTSUPP;
4270 case NL80211_IFTYPE_ADHOC:
4271 return WL_MODE_IBSS;
4272 case NL80211_IFTYPE_STATION:
4273 case NL80211_IFTYPE_P2P_CLIENT:
4274 return WL_MODE_BSS;
4275 case NL80211_IFTYPE_AP:
4276 case NL80211_IFTYPE_P2P_GO:
4277 return WL_MODE_AP;
4278 case NL80211_IFTYPE_P2P_DEVICE:
4279 return WL_MODE_P2P;
4280 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004281 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01004282 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004283 }
4284
Arend van Spriel9f440b72013-02-08 15:53:36 +01004285 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004286}
4287
Arend van Spriele5806072012-09-19 22:21:08 +02004288static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4289{
Arend van Spriele5806072012-09-19 22:21:08 +02004290 /* scheduled scan settings */
4291 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4292 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4293 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4294 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004295}
4296
Arend van Spriel9f440b72013-02-08 15:53:36 +01004297static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4298 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004299 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004300 .types = BIT(NL80211_IFTYPE_STATION) |
4301 BIT(NL80211_IFTYPE_ADHOC) |
4302 BIT(NL80211_IFTYPE_AP)
4303 },
4304 {
4305 .max = 1,
4306 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4307 BIT(NL80211_IFTYPE_P2P_GO)
4308 },
Arend van Spriel9af221b2013-05-14 20:52:36 +02004309 {
4310 .max = 1,
4311 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4312 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004313};
4314static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4315 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004316 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004317 .num_different_channels = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004318 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4319 .limits = brcmf_iface_limits
4320 }
4321};
4322
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004323static const struct ieee80211_txrx_stypes
4324brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4325 [NL80211_IFTYPE_STATION] = {
4326 .tx = 0xffff,
4327 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4328 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4329 },
4330 [NL80211_IFTYPE_P2P_CLIENT] = {
4331 .tx = 0xffff,
4332 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4333 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4334 },
4335 [NL80211_IFTYPE_P2P_GO] = {
4336 .tx = 0xffff,
4337 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4338 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4339 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4340 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4341 BIT(IEEE80211_STYPE_AUTH >> 4) |
4342 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4343 BIT(IEEE80211_STYPE_ACTION >> 4)
Arend van Sprielbffc61c2013-04-05 10:57:52 +02004344 },
4345 [NL80211_IFTYPE_P2P_DEVICE] = {
4346 .tx = 0xffff,
4347 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4348 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004349 }
4350};
4351
Arend van Spriel3eacf862012-10-22 13:55:30 -07004352static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004353{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004354 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004355 s32 err = 0;
4356
Arend van Spriel3eacf862012-10-22 13:55:30 -07004357 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4358 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004359 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004360 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004361 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004362 set_wiphy_dev(wiphy, phydev);
4363 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004364 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004365 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4366 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4367 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004368 BIT(NL80211_IFTYPE_AP) |
4369 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Arend van Spriel9af221b2013-05-14 20:52:36 +02004370 BIT(NL80211_IFTYPE_P2P_GO) |
4371 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004372 wiphy->iface_combinations = brcmf_iface_combos;
4373 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004374 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004375 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4376 wiphy->cipher_suites = __wl_cipher_suites;
4377 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004378 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004379 WIPHY_FLAG_OFFCHAN_TX |
Arend van Spriel89c2f382013-08-10 12:27:25 +02004380 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4381 WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004382 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4383 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004384 brcmf_wiphy_pno_params(wiphy);
Hante Meulemand48200b2013-04-03 12:40:29 +02004385 brcmf_dbg(INFO, "Registering custom regulatory\n");
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +01004386 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Hante Meulemand48200b2013-04-03 12:40:29 +02004387 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004388 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004389 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004390 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004391 wiphy_free(wiphy);
4392 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004393 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004394 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004395}
4396
Arend van Spriel3eacf862012-10-22 13:55:30 -07004397struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004398 enum nl80211_iftype type,
4399 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004400{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004401 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004402
Arend van Spriel33a6b152013-02-08 15:53:39 +01004403 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004404 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004405 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4406 if (!vif)
4407 return ERR_PTR(-ENOMEM);
4408
4409 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004410 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004411
Arend van Spriel9f440b72013-02-08 15:53:36 +01004412 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004413 vif->pm_block = pm_block;
4414 vif->roam_off = -1;
4415
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004416 brcmf_init_prof(&vif->profile);
4417
Arend van Spriel3eacf862012-10-22 13:55:30 -07004418 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004419 return vif;
4420}
4421
Arend van Spriel427dec52014-01-06 12:40:47 +01004422void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004423{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004424 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004425 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004426}
4427
Arend van Spriel9df4d542014-01-06 12:40:49 +01004428void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4429{
4430 struct brcmf_cfg80211_vif *vif;
4431 struct brcmf_if *ifp;
4432
4433 ifp = netdev_priv(ndev);
4434 vif = ifp->vif;
4435
4436 brcmf_free_vif(vif);
4437 free_netdev(ndev);
4438}
4439
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004440static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004441{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004442 u32 event = e->event_code;
4443 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004444
4445 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004446 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004447 return true;
4448 }
4449
4450 return false;
4451}
4452
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004453static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004454{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004455 u32 event = e->event_code;
4456 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004457
Hante Meuleman68ca3952014-02-25 20:30:26 +01004458 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
4459 (event == BRCMF_E_DISASSOC_IND) ||
4460 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004461 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004462 return true;
4463 }
4464 return false;
4465}
4466
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004467static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004468 const struct brcmf_event_msg *e)
4469{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004470 u32 event = e->event_code;
4471 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004472
4473 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004474 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4475 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004476 return true;
4477 }
4478
4479 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004480 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004481 return true;
4482 }
4483
4484 return false;
4485}
4486
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004487static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004488{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004489 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004490
4491 kfree(conn_info->req_ie);
4492 conn_info->req_ie = NULL;
4493 conn_info->req_ie_len = 0;
4494 kfree(conn_info->resp_ie);
4495 conn_info->resp_ie = NULL;
4496 conn_info->resp_ie_len = 0;
4497}
4498
Hante Meuleman89286dc2013-02-08 15:53:46 +01004499static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4500 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004501{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004502 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004503 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004504 u32 req_len;
4505 u32 resp_len;
4506 s32 err = 0;
4507
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004508 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004509
Arend van Sprielac24be62012-10-22 10:36:23 -07004510 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4511 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004512 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004513 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004514 return err;
4515 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004516 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004517 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004518 req_len = le32_to_cpu(assoc_info->req_len);
4519 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004520 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004521 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_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 req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004526 return err;
4527 }
4528 conn_info->req_ie_len = req_len;
4529 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004530 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004531 GFP_KERNEL);
4532 } else {
4533 conn_info->req_ie_len = 0;
4534 conn_info->req_ie = NULL;
4535 }
4536 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004537 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004538 cfg->extra_buf,
4539 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004540 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004541 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004542 return err;
4543 }
4544 conn_info->resp_ie_len = resp_len;
4545 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004546 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004547 GFP_KERNEL);
4548 } else {
4549 conn_info->resp_ie_len = 0;
4550 conn_info->resp_ie = NULL;
4551 }
Arend van Spriel16886732012-12-05 15:26:04 +01004552 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4553 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004554
4555 return err;
4556}
4557
4558static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004559brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004560 struct net_device *ndev,
4561 const struct brcmf_event_msg *e)
4562{
Arend van Sprielc1179032012-10-22 13:55:33 -07004563 struct brcmf_if *ifp = netdev_priv(ndev);
4564 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004565 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4566 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004567 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004568 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004569 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004570 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004571 u32 freq;
4572 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004573 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004574
Arend van Sprield96b8012012-12-05 15:26:02 +01004575 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004576
Hante Meuleman89286dc2013-02-08 15:53:46 +01004577 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004578 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004579 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004580
Franky Lina180b832012-10-10 11:13:09 -07004581 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4582 if (buf == NULL) {
4583 err = -ENOMEM;
4584 goto done;
4585 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004586
Franky Lina180b832012-10-10 11:13:09 -07004587 /* data sent to dongle has to be little endian */
4588 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004589 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004590 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004591
4592 if (err)
4593 goto done;
4594
4595 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004596 ch.chspec = le16_to_cpu(bi->chanspec);
4597 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004598
Franky Lin83cf17a2013-04-11 13:28:50 +02004599 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004600 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4601 else
4602 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4603
Franky Lin83cf17a2013-04-11 13:28:50 +02004604 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004605 notify_channel = ieee80211_get_channel(wiphy, freq);
4606
Franky Lina180b832012-10-10 11:13:09 -07004607done:
4608 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004609 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004610 conn_info->req_ie, conn_info->req_ie_len,
4611 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004612 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004613
Arend van Sprielc1179032012-10-22 13:55:33 -07004614 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004615 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004616 return err;
4617}
4618
4619static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004620brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004621 struct net_device *ndev, const struct brcmf_event_msg *e,
4622 bool completed)
4623{
Arend van Sprielc1179032012-10-22 13:55:33 -07004624 struct brcmf_if *ifp = netdev_priv(ndev);
4625 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004626 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004627 s32 err = 0;
4628
Arend van Sprield96b8012012-12-05 15:26:02 +01004629 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004630
Arend van Sprielc1179032012-10-22 13:55:33 -07004631 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4632 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004633 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004634 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004635 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004636 brcmf_update_bss_info(cfg, ifp);
4637 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4638 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004639 }
4640 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004641 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004642 conn_info->req_ie,
4643 conn_info->req_ie_len,
4644 conn_info->resp_ie,
4645 conn_info->resp_ie_len,
4646 completed ? WLAN_STATUS_SUCCESS :
4647 WLAN_STATUS_AUTH_TIMEOUT,
4648 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004649 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4650 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004651 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004652 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004653 return err;
4654}
4655
4656static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004657brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004658 struct net_device *ndev,
4659 const struct brcmf_event_msg *e, void *data)
4660{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004661 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004662 u32 event = e->event_code;
4663 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004664 struct station_info sinfo;
4665
Arend van Spriel16886732012-12-05 15:26:04 +01004666 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004667 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4668 ndev != cfg_to_ndev(cfg)) {
4669 brcmf_dbg(CONN, "AP mode link down\n");
4670 complete(&cfg->vif_disabled);
4671 return 0;
4672 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004673
Hante Meuleman1a873342012-09-27 14:17:54 +02004674 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004675 (reason == BRCMF_E_STATUS_SUCCESS)) {
4676 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004677 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4678 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004679 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004680 return -EINVAL;
4681 }
4682 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004683 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004684 generation++;
4685 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004686 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004687 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4688 (event == BRCMF_E_DEAUTH_IND) ||
4689 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004690 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004691 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004692 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004693}
4694
4695static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004696brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004697 const struct brcmf_event_msg *e, void *data)
4698{
Arend van Spriel19937322012-11-05 16:22:32 -08004699 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4700 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004701 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004702 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004703 s32 err = 0;
Hante Meuleman68ca3952014-02-25 20:30:26 +01004704 u16 reason;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004705
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004706 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004707 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004708 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004709 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004710 if (brcmf_is_ibssmode(ifp->vif)) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004711 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004712 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004713 wl_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01004714 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004715 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4716 &ifp->vif->sme_state);
4717 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4718 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004719 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004720 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004721 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004722 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004723 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004724 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004725 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Hante Meuleman68ca3952014-02-25 20:30:26 +01004726 &ifp->vif->sme_state)) {
4727 reason = 0;
4728 if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
4729 (e->event_code == BRCMF_E_DISASSOC_IND)) &&
4730 (e->reason != WLAN_REASON_UNSPECIFIED))
4731 reason = e->reason;
4732 cfg80211_disconnected(ndev, reason, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004733 GFP_KERNEL);
Hante Meuleman68ca3952014-02-25 20:30:26 +01004734 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004735 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004736 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004737 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004738 if (ndev != cfg_to_ndev(cfg))
4739 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004740 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004741 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004742 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4743 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004744 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004745 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004746 }
4747
4748 return err;
4749}
4750
4751static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004752brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004753 const struct brcmf_event_msg *e, void *data)
4754{
Arend van Spriel19937322012-11-05 16:22:32 -08004755 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004756 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004757 u32 event = e->event_code;
4758 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004759
4760 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004761 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004762 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004763 else
Arend van Spriel19937322012-11-05 16:22:32 -08004764 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004765 }
4766
4767 return err;
4768}
4769
4770static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004771brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004772 const struct brcmf_event_msg *e, void *data)
4773{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004774 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004775 enum nl80211_key_type key_type;
4776
4777 if (flags & BRCMF_EVENT_MSG_GROUP)
4778 key_type = NL80211_KEYTYPE_GROUP;
4779 else
4780 key_type = NL80211_KEYTYPE_PAIRWISE;
4781
Arend van Spriel19937322012-11-05 16:22:32 -08004782 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004783 NULL, GFP_KERNEL);
4784
4785 return 0;
4786}
4787
Arend van Sprield3c0b632013-02-08 15:53:37 +01004788static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4789 const struct brcmf_event_msg *e, void *data)
4790{
4791 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4792 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4793 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4794 struct brcmf_cfg80211_vif *vif;
4795
4796 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4797 ifevent->action, ifevent->flags, ifevent->ifidx,
4798 ifevent->bssidx);
4799
Arend van Sprield3c0b632013-02-08 15:53:37 +01004800 mutex_lock(&event->vif_event_lock);
4801 event->action = ifevent->action;
4802 vif = event->vif;
4803
4804 switch (ifevent->action) {
4805 case BRCMF_E_IF_ADD:
4806 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004807 if (!cfg->vif_event.vif) {
4808 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004809 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004810 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004811
4812 ifp->vif = vif;
4813 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02004814 if (ifp->ndev) {
4815 vif->wdev.netdev = ifp->ndev;
4816 ifp->ndev->ieee80211_ptr = &vif->wdev;
4817 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4818 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004819 mutex_unlock(&event->vif_event_lock);
4820 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004821 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004822
4823 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01004824 mutex_unlock(&event->vif_event_lock);
4825 /* event may not be upon user request */
4826 if (brcmf_cfg80211_vif_event_armed(cfg))
4827 wake_up(&event->vif_wq);
4828 return 0;
4829
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004830 case BRCMF_E_IF_CHANGE:
4831 mutex_unlock(&event->vif_event_lock);
4832 wake_up(&event->vif_wq);
4833 return 0;
4834
Arend van Sprield3c0b632013-02-08 15:53:37 +01004835 default:
4836 mutex_unlock(&event->vif_event_lock);
4837 break;
4838 }
4839 return -EINVAL;
4840}
4841
Arend van Spriel5b435de2011-10-05 13:19:03 +02004842static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4843{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004844 conf->frag_threshold = (u32)-1;
4845 conf->rts_threshold = (u32)-1;
4846 conf->retry_short = (u32)-1;
4847 conf->retry_long = (u32)-1;
4848 conf->tx_power = -1;
4849}
4850
Arend van Spriel5c36b992012-11-14 18:46:05 -08004851static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004852{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004853 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4854 brcmf_notify_connect_status);
4855 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4856 brcmf_notify_connect_status);
4857 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4858 brcmf_notify_connect_status);
4859 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4860 brcmf_notify_connect_status);
4861 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4862 brcmf_notify_connect_status);
4863 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4864 brcmf_notify_connect_status);
4865 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4866 brcmf_notify_roaming_status);
4867 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4868 brcmf_notify_mic_status);
4869 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4870 brcmf_notify_connect_status);
4871 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4872 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004873 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4874 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004875 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004876 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004877 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4878 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004879 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4880 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004881 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4882 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004883 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4884 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004885}
4886
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004887static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004888{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004889 kfree(cfg->conf);
4890 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004891 kfree(cfg->escan_ioctl_buf);
4892 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004893 kfree(cfg->extra_buf);
4894 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004895 kfree(cfg->pmk_list);
4896 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004897}
4898
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004899static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004900{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004901 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4902 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004903 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004904 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4905 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004906 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004907 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4908 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004909 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004910 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4911 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004912 goto init_priv_mem_out;
4913
4914 return 0;
4915
4916init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004917 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004918
4919 return -ENOMEM;
4920}
4921
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004922static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004923{
4924 s32 err = 0;
4925
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004926 cfg->scan_request = NULL;
4927 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01004928 cfg->active_scan = true; /* we do active scan per default */
4929 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004930 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004931 if (err)
4932 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004933 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004934 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004935 brcmf_init_escan(cfg);
4936 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004937 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004938 return err;
4939}
4940
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004941static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004942{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004943 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004944 brcmf_abort_scanning(cfg);
4945 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004946}
4947
Arend van Sprield3c0b632013-02-08 15:53:37 +01004948static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4949{
4950 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004951 mutex_init(&event->vif_event_lock);
4952}
4953
Arend van Sprield9cb2592012-12-05 15:25:54 +01004954struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4955 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004956{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004957 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004958 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004959 struct wiphy *wiphy;
4960 struct brcmf_cfg80211_vif *vif;
4961 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004962 s32 err = 0;
Franky Lin83cf17a2013-04-11 13:28:50 +02004963 s32 io_type;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004964
4965 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004966 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004967 return NULL;
4968 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004969
Arend van Spriel3eacf862012-10-22 13:55:30 -07004970 ifp = netdev_priv(ndev);
4971 wiphy = brcmf_setup_wiphy(busdev);
4972 if (IS_ERR(wiphy))
4973 return NULL;
4974
4975 cfg = wiphy_priv(wiphy);
4976 cfg->wiphy = wiphy;
4977 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004978 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004979 INIT_LIST_HEAD(&cfg->vif_list);
4980
Arend van Sprield3c0b632013-02-08 15:53:37 +01004981 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004982 if (IS_ERR(vif)) {
4983 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004984 return NULL;
4985 }
4986
Arend van Sprield3c0b632013-02-08 15:53:37 +01004987 vif->ifp = ifp;
4988 vif->wdev.netdev = ndev;
4989 ndev->ieee80211_ptr = &vif->wdev;
4990 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4991
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004992 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004993 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004994 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004995 goto cfg80211_attach_out;
4996 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004997 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004998
4999 err = brcmf_p2p_attach(cfg);
5000 if (err) {
5001 brcmf_err("P2P initilisation failed (%d)\n", err);
5002 goto cfg80211_p2p_attach_out;
5003 }
Piotr Haber61730d42013-04-23 12:53:12 +02005004 err = brcmf_btcoex_attach(cfg);
5005 if (err) {
5006 brcmf_err("BT-coex initialisation failed (%d)\n", err);
5007 brcmf_p2p_detach(&cfg->p2p);
5008 goto cfg80211_p2p_attach_out;
5009 }
Hante Meuleman2fde59d2013-02-08 15:53:52 +01005010
Arend van Spriel89c2f382013-08-10 12:27:25 +02005011 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
5012 if (err) {
5013 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
5014 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
5015 }
5016
Franky Lin83cf17a2013-04-11 13:28:50 +02005017 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
5018 &io_type);
5019 if (err) {
5020 brcmf_err("Failed to get D11 version (%d)\n", err);
5021 goto cfg80211_p2p_attach_out;
5022 }
5023 cfg->d11inf.io_type = (u8)io_type;
5024 brcmu_d11_attach(&cfg->d11inf);
5025
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005026 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005027
Hante Meuleman2fde59d2013-02-08 15:53:52 +01005028cfg80211_p2p_attach_out:
5029 wl_deinit_priv(cfg);
5030
Arend van Spriel5b435de2011-10-05 13:19:03 +02005031cfg80211_attach_out:
Arend van Spriel427dec52014-01-06 12:40:47 +01005032 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005033 return NULL;
5034}
5035
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005036void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005037{
Arend van Spriele1479952014-01-06 12:40:48 +01005038 if (!cfg)
5039 return;
5040
Arend van Spriel427dec52014-01-06 12:40:47 +01005041 WARN_ON(!list_empty(&cfg->vif_list));
5042 wiphy_unregister(cfg->wiphy);
Piotr Haber61730d42013-04-23 12:53:12 +02005043 brcmf_btcoex_detach(cfg);
Arend van Spriel427dec52014-01-06 12:40:47 +01005044 wl_deinit_priv(cfg);
5045 wiphy_free(cfg->wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005046}
5047
Arend van Spriel5b435de2011-10-05 13:19:03 +02005048static s32
Hante Meuleman68ca3952014-02-25 20:30:26 +01005049brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005050{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005051 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005052 __le32 roamtrigger[2];
5053 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005054
5055 /*
5056 * Setup timeout if Beacons are lost and roam is
5057 * off to report link down
5058 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005059 if (brcmf_roamoff) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005060 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005061 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005062 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005063 goto dongle_rom_out;
5064 }
5065 }
5066
5067 /*
5068 * Enable/Disable built-in roaming to allow supplicant
5069 * to take care of roaming
5070 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005071 brcmf_dbg(INFO, "Internal Roaming = %s\n",
5072 brcmf_roamoff ? "Off" : "On");
5073 err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005074 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005075 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005076 goto dongle_rom_out;
5077 }
5078
Arend van Sprielf588bc02011-10-12 20:51:22 +02005079 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5080 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005081 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005082 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005083 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005084 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005085 goto dongle_rom_out;
5086 }
5087
Arend van Sprielf588bc02011-10-12 20:51:22 +02005088 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5089 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005090 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005091 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005092 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005093 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005094 goto dongle_rom_out;
5095 }
5096
5097dongle_rom_out:
5098 return err;
5099}
5100
5101static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005102brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005103 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005104{
5105 s32 err = 0;
5106
Arend van Sprielac24be62012-10-22 10:36:23 -07005107 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005108 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005109 if (err) {
5110 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005111 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005112 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005113 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005114 goto dongle_scantime_out;
5115 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005116 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005117 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005118 if (err) {
5119 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005120 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005121 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005122 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005123 goto dongle_scantime_out;
5124 }
5125
Arend van Sprielac24be62012-10-22 10:36:23 -07005126 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005127 scan_passive_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 passive 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 passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005133 goto dongle_scantime_out;
5134 }
5135
5136dongle_scantime_out:
5137 return err;
5138}
5139
Hante Meulemand48200b2013-04-03 12:40:29 +02005140
Arend van Spriel2375d972014-01-06 12:40:41 +01005141static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
5142 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005143{
5144 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5145 struct ieee80211_channel *band_chan_arr;
5146 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005147 struct brcmu_chan ch;
Hante Meulemand48200b2013-04-03 12:40:29 +02005148 s32 err;
5149 u8 *pbuf;
5150 u32 i, j;
5151 u32 total;
Hante Meulemand48200b2013-04-03 12:40:29 +02005152 enum ieee80211_band band;
5153 u32 channel;
5154 u32 *n_cnt;
Hante Meulemand48200b2013-04-03 12:40:29 +02005155 u32 index;
5156 u32 ht40_flag;
5157 bool update;
5158 u32 array_size;
5159
5160 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5161
5162 if (pbuf == NULL)
5163 return -ENOMEM;
5164
5165 list = (struct brcmf_chanspec_list *)pbuf;
5166
5167 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5168 BRCMF_DCMD_MEDLEN);
5169 if (err) {
5170 brcmf_err("get chanspecs error (%d)\n", err);
5171 goto exit;
5172 }
5173
5174 __wl_band_2ghz.n_channels = 0;
5175 __wl_band_5ghz_a.n_channels = 0;
5176
5177 total = le32_to_cpu(list->count);
5178 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005179 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5180 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005181
Franky Lin83cf17a2013-04-11 13:28:50 +02005182 if (ch.band == BRCMU_CHAN_BAND_2G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005183 band_chan_arr = __wl_2ghz_channels;
5184 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5185 n_cnt = &__wl_band_2ghz.n_channels;
5186 band = IEEE80211_BAND_2GHZ;
Franky Lin83cf17a2013-04-11 13:28:50 +02005187 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005188 band_chan_arr = __wl_5ghz_a_channels;
5189 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
5190 n_cnt = &__wl_band_5ghz_a.n_channels;
5191 band = IEEE80211_BAND_5GHZ;
Hante Meulemand48200b2013-04-03 12:40:29 +02005192 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005193 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005194 continue;
5195 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005196 if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
5197 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005198 continue;
5199 update = false;
5200 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005201 if (band_chan_arr[j].hw_value == ch.chnum) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005202 update = true;
5203 break;
5204 }
5205 }
5206 if (update)
5207 index = j;
5208 else
5209 index = *n_cnt;
5210 if (index < array_size) {
5211 band_chan_arr[index].center_freq =
Franky Lin83cf17a2013-04-11 13:28:50 +02005212 ieee80211_channel_to_frequency(ch.chnum, band);
5213 band_chan_arr[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005214
Arend van Spriel2375d972014-01-06 12:40:41 +01005215 if (ch.bw == BRCMU_CHAN_BW_40) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005216 /* assuming the order is HT20, HT40 Upper,
5217 * HT40 lower from chanspecs
5218 */
5219 ht40_flag = band_chan_arr[index].flags &
5220 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005221 if (ch.sb == BRCMU_CHAN_SB_U) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005222 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5223 band_chan_arr[index].flags &=
5224 ~IEEE80211_CHAN_NO_HT40;
5225 band_chan_arr[index].flags |=
5226 IEEE80211_CHAN_NO_HT40PLUS;
5227 } else {
5228 /* It should be one of
5229 * IEEE80211_CHAN_NO_HT40 or
5230 * IEEE80211_CHAN_NO_HT40PLUS
5231 */
5232 band_chan_arr[index].flags &=
5233 ~IEEE80211_CHAN_NO_HT40;
5234 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5235 band_chan_arr[index].flags |=
5236 IEEE80211_CHAN_NO_HT40MINUS;
5237 }
5238 } else {
5239 band_chan_arr[index].flags =
5240 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005241 ch.bw = BRCMU_CHAN_BW_20;
5242 cfg->d11inf.encchspec(&ch);
5243 channel = ch.chspec;
Hante Meulemand48200b2013-04-03 12:40:29 +02005244 err = brcmf_fil_bsscfg_int_get(ifp,
5245 "per_chan_info",
5246 &channel);
5247 if (!err) {
5248 if (channel & WL_CHAN_RADAR)
5249 band_chan_arr[index].flags |=
5250 (IEEE80211_CHAN_RADAR |
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005251 IEEE80211_CHAN_NO_IR);
Hante Meulemand48200b2013-04-03 12:40:29 +02005252 if (channel & WL_CHAN_PASSIVE)
5253 band_chan_arr[index].flags |=
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005254 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005255 }
5256 }
5257 if (!update)
5258 (*n_cnt)++;
5259 }
5260 }
5261exit:
5262 kfree(pbuf);
5263 return err;
5264}
5265
Arend van Spriel2375d972014-01-06 12:40:41 +01005266static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5267{
5268 u32 band, mimo_bwcap;
5269 int err;
5270
5271 band = WLC_BAND_2G;
5272 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5273 if (!err) {
5274 bw_cap[IEEE80211_BAND_2GHZ] = band;
5275 band = WLC_BAND_5G;
5276 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5277 if (!err) {
5278 bw_cap[IEEE80211_BAND_5GHZ] = band;
5279 return;
5280 }
5281 WARN_ON(1);
5282 return;
5283 }
5284 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5285 mimo_bwcap = 0;
5286 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5287 if (err)
5288 /* assume 20MHz if firmware does not give a clue */
5289 mimo_bwcap = WLC_N_BW_20ALL;
5290
5291 switch (mimo_bwcap) {
5292 case WLC_N_BW_40ALL:
5293 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5294 /* fall-thru */
5295 case WLC_N_BW_20IN2G_40IN5G:
5296 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5297 /* fall-thru */
5298 case WLC_N_BW_20ALL:
5299 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5300 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5301 break;
5302 default:
5303 brcmf_err("invalid mimo_bw_cap value\n");
5304 }
5305}
Hante Meulemand48200b2013-04-03 12:40:29 +02005306
5307static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005308{
Arend van Sprielac24be62012-10-22 10:36:23 -07005309 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005310 struct wiphy *wiphy;
5311 s32 phy_list;
Hante Meulemand48200b2013-04-03 12:40:29 +02005312 u32 band_list[3];
5313 u32 nmode;
Arend van Spriel2375d972014-01-06 12:40:41 +01005314 u32 bw_cap[2] = { 0, 0 };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005315 u32 rxchain;
5316 u32 nchain;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005317 s8 phy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005318 s32 err;
5319 u32 nband;
5320 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005321 struct ieee80211_supported_band *bands[2] = { NULL, NULL };
5322 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005323
Hante Meulemanb87e2c42012-11-14 18:46:23 -08005324 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005325 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005326 if (err) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005327 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328 return err;
5329 }
5330
Hante Meuleman3ba81372012-09-19 22:21:13 +02005331 phy = ((char *)&phy_list)[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005332 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5333
5334
5335 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5336 &band_list, sizeof(band_list));
5337 if (err) {
5338 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5339 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005340 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005341 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5342 band_list[0], band_list[1], band_list[2]);
5343
5344 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5345 if (err) {
5346 brcmf_err("nmode error (%d)\n", err);
5347 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005348 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005349 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005350 brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
5351 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005352
Daniel Kim4aca7a12014-02-25 20:30:36 +01005353 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5354 if (err) {
5355 brcmf_err("rxchain error (%d)\n", err);
5356 nchain = 1;
5357 } else {
5358 for (nchain = 0; rxchain; nchain++)
5359 rxchain = rxchain & (rxchain - 1);
5360 }
5361 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5362
Hante Meulemand48200b2013-04-03 12:40:29 +02005363 err = brcmf_construct_reginfo(cfg, bw_cap);
5364 if (err) {
5365 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5366 return err;
5367 }
5368
5369 nband = band_list[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005370
5371 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
Arend van Spriel2375d972014-01-06 12:40:41 +01005372 band = NULL;
Hante Meulemand48200b2013-04-03 12:40:29 +02005373 if ((band_list[i] == WLC_BAND_5G) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005374 (__wl_band_5ghz_a.n_channels > 0))
5375 band = &__wl_band_5ghz_a;
5376 else if ((band_list[i] == WLC_BAND_2G) &&
5377 (__wl_band_2ghz.n_channels > 0))
5378 band = &__wl_band_2ghz;
5379 else
5380 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005381
Arend van Spriel2375d972014-01-06 12:40:41 +01005382 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5383 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5384 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Hante Meulemand48200b2013-04-03 12:40:29 +02005385 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005386 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5387 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5388 band->ht_cap.ht_supported = true;
5389 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5390 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
Daniel Kim4aca7a12014-02-25 20:30:36 +01005391 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
Arend van Spriel2375d972014-01-06 12:40:41 +01005392 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5393 bands[band->band] = band;
Hante Meulemand48200b2013-04-03 12:40:29 +02005394 }
5395
5396 wiphy = cfg_to_wiphy(cfg);
5397 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5398 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5399 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005400
5401 return err;
5402}
5403
Hante Meulemand48200b2013-04-03 12:40:29 +02005404
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005405static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005406{
Hante Meulemand48200b2013-04-03 12:40:29 +02005407 return brcmf_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005408}
5409
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005410static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005411{
5412 struct net_device *ndev;
5413 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01005414 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415 s32 power_mode;
5416 s32 err = 0;
5417
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005418 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419 return err;
5420
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005421 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005422 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01005423 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005424
Hante Meuleman40a23292013-01-02 15:22:51 +01005425 /* make sure RF is ready for work */
5426 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5427
5428 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5429 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005430
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005431 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01005432 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005433 if (err)
5434 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005435 brcmf_dbg(INFO, "power save set to %s\n",
5436 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005437
Hante Meuleman68ca3952014-02-25 20:30:26 +01005438 err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 if (err)
5440 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005441 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5442 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01005443 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005444 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005445 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005446 if (err)
5447 goto default_conf_out;
5448
Hante Meulemanb3657452013-05-27 21:09:53 +02005449 brcmf_configure_arp_offload(ifp, true);
5450
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005451 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005452default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005453
5454 return err;
5455
5456}
5457
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005458static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005459{
Arend van Sprielc1179032012-10-22 13:55:33 -07005460 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005461
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005462 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005463}
5464
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005465static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005466{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005467 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005468
Arend van Spriel5b435de2011-10-05 13:19:03 +02005469 /*
5470 * While going down, if associated with AP disassociate
5471 * from AP to save power
5472 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005473 if (check_vif_up(ifp->vif)) {
5474 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005475
5476 /* Make sure WPA_Supplicant receives all the event
5477 generated due to DISASSOC call to the fw to keep
5478 the state fw and WPA_Supplicant state consistent
5479 */
5480 brcmf_delay(500);
5481 }
5482
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005483 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005484 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005485
Arend van Spriel5b435de2011-10-05 13:19:03 +02005486 return 0;
5487}
5488
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005489s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005490{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005491 struct brcmf_if *ifp = netdev_priv(ndev);
5492 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005493 s32 err = 0;
5494
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005495 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005496 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005497 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005498
5499 return err;
5500}
5501
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005502s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005503{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005504 struct brcmf_if *ifp = netdev_priv(ndev);
5505 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005506 s32 err = 0;
5507
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005508 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005509 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005510 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005511
5512 return err;
5513}
5514
Arend van Spriela7965fb2013-04-11 17:08:37 +02005515enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5516{
5517 struct wireless_dev *wdev = &ifp->vif->wdev;
5518
5519 return wdev->iftype;
5520}
5521
Arend van Spriel9f440b72013-02-08 15:53:36 +01005522u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5523{
5524 struct brcmf_cfg80211_vif *vif;
5525 bool result = 0;
5526
5527 list_for_each_entry(vif, &cfg->vif_list, list) {
5528 if (test_bit(state, &vif->sme_state))
5529 result++;
5530 }
5531 return result;
5532}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005533
5534static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5535 u8 action)
5536{
5537 u8 evt_action;
5538
5539 mutex_lock(&event->vif_event_lock);
5540 evt_action = event->action;
5541 mutex_unlock(&event->vif_event_lock);
5542 return evt_action == action;
5543}
5544
5545void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5546 struct brcmf_cfg80211_vif *vif)
5547{
5548 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5549
5550 mutex_lock(&event->vif_event_lock);
5551 event->vif = vif;
5552 event->action = 0;
5553 mutex_unlock(&event->vif_event_lock);
5554}
5555
5556bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5557{
5558 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5559 bool armed;
5560
5561 mutex_lock(&event->vif_event_lock);
5562 armed = event->vif != NULL;
5563 mutex_unlock(&event->vif_event_lock);
5564
5565 return armed;
5566}
5567int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5568 u8 action, ulong timeout)
5569{
5570 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5571
5572 return wait_event_timeout(event->vif_wq,
5573 vif_event_equals(event, action), timeout);
5574}
5575