blob: 3d25c18340c57d11960b2ac1285faeb5404b77ac [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>
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020022#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023
24#include <brcmu_utils.h>
25#include <defs.h>
26#include <brcmu_wifi.h>
27#include "dhd.h"
Arend van Spriel16886732012-12-05 15:26:04 +010028#include "dhd_dbg.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020029#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010030#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010031#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020032#include "btcoex.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020033#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070034#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020035
Arend van Spriele5806072012-09-19 22:21:08 +020036#define BRCMF_SCAN_IE_LEN_MAX 2048
37#define BRCMF_PNO_VERSION 2
38#define BRCMF_PNO_TIME 30
39#define BRCMF_PNO_REPEAT 4
40#define BRCMF_PNO_FREQ_EXPO_MAX 3
41#define BRCMF_PNO_MAX_PFN_COUNT 16
42#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
43#define BRCMF_PNO_HIDDEN_BIT 2
44#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
45#define BRCMF_PNO_SCAN_COMPLETE 1
46#define BRCMF_PNO_SCAN_INCOMPLETE 0
47
Arend van Spriel9f440b72013-02-08 15:53:36 +010048#define BRCMF_IFACE_MAX_CNT 3
Arend van Spriel3eacf862012-10-22 13:55:30 -070049
Hante Meuleman1a873342012-09-27 14:17:54 +020050#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
51#define WPA_OUI_TYPE 1
52#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
53#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010054#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020055
56#define VS_IE_FIXED_HDR_LEN 6
57#define WPA_IE_VERSION_LEN 2
58#define WPA_IE_MIN_OUI_LEN 4
59#define WPA_IE_SUITE_COUNT_LEN 2
60
61#define WPA_CIPHER_NONE 0 /* None */
62#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
63#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
64#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
65#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
66
67#define RSN_AKM_NONE 0 /* None (IBSS) */
68#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
69#define RSN_AKM_PSK 2 /* Pre-shared Key */
70#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
71#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
72
73#define VNDR_IE_CMD_LEN 4 /* length of the set command
74 * string :"add", "del" (+ NUL)
75 */
76#define VNDR_IE_COUNT_OFFSET 4
77#define VNDR_IE_PKTFLAG_OFFSET 8
78#define VNDR_IE_VSIE_OFFSET 12
79#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010080#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020081
82#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
83#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020084
Hante Meuleman89286dc2013-02-08 15:53:46 +010085#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
86#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
87#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
88
Arend van Spriel5b435de2011-10-05 13:19:03 +020089#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
90 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
91
Arend van Sprielce81e312012-10-22 13:55:37 -070092static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020093{
Arend van Sprielc1179032012-10-22 13:55:33 -070094 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010095 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
96 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020097 return false;
98 }
99 return true;
100}
101
102#define CHAN2G(_channel, _freq, _flags) { \
103 .band = IEEE80211_BAND_2GHZ, \
104 .center_freq = (_freq), \
105 .hw_value = (_channel), \
106 .flags = (_flags), \
107 .max_antenna_gain = 0, \
108 .max_power = 30, \
109}
110
111#define CHAN5G(_channel, _flags) { \
112 .band = IEEE80211_BAND_5GHZ, \
113 .center_freq = 5000 + (5 * (_channel)), \
114 .hw_value = (_channel), \
115 .flags = (_flags), \
116 .max_antenna_gain = 0, \
117 .max_power = 30, \
118}
119
120#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
121#define RATETAB_ENT(_rateid, _flags) \
122 { \
123 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
124 .hw_value = (_rateid), \
125 .flags = (_flags), \
126 }
127
128static struct ieee80211_rate __wl_rates[] = {
129 RATETAB_ENT(BRCM_RATE_1M, 0),
130 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
132 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
133 RATETAB_ENT(BRCM_RATE_6M, 0),
134 RATETAB_ENT(BRCM_RATE_9M, 0),
135 RATETAB_ENT(BRCM_RATE_12M, 0),
136 RATETAB_ENT(BRCM_RATE_18M, 0),
137 RATETAB_ENT(BRCM_RATE_24M, 0),
138 RATETAB_ENT(BRCM_RATE_36M, 0),
139 RATETAB_ENT(BRCM_RATE_48M, 0),
140 RATETAB_ENT(BRCM_RATE_54M, 0),
141};
142
143#define wl_a_rates (__wl_rates + 4)
144#define wl_a_rates_size 8
145#define wl_g_rates (__wl_rates + 0)
146#define wl_g_rates_size 12
147
148static struct ieee80211_channel __wl_2ghz_channels[] = {
149 CHAN2G(1, 2412, 0),
150 CHAN2G(2, 2417, 0),
151 CHAN2G(3, 2422, 0),
152 CHAN2G(4, 2427, 0),
153 CHAN2G(5, 2432, 0),
154 CHAN2G(6, 2437, 0),
155 CHAN2G(7, 2442, 0),
156 CHAN2G(8, 2447, 0),
157 CHAN2G(9, 2452, 0),
158 CHAN2G(10, 2457, 0),
159 CHAN2G(11, 2462, 0),
160 CHAN2G(12, 2467, 0),
161 CHAN2G(13, 2472, 0),
162 CHAN2G(14, 2484, 0),
163};
164
165static struct ieee80211_channel __wl_5ghz_a_channels[] = {
166 CHAN5G(34, 0), CHAN5G(36, 0),
167 CHAN5G(38, 0), CHAN5G(40, 0),
168 CHAN5G(42, 0), CHAN5G(44, 0),
169 CHAN5G(46, 0), CHAN5G(48, 0),
170 CHAN5G(52, 0), CHAN5G(56, 0),
171 CHAN5G(60, 0), CHAN5G(64, 0),
172 CHAN5G(100, 0), CHAN5G(104, 0),
173 CHAN5G(108, 0), CHAN5G(112, 0),
174 CHAN5G(116, 0), CHAN5G(120, 0),
175 CHAN5G(124, 0), CHAN5G(128, 0),
176 CHAN5G(132, 0), CHAN5G(136, 0),
177 CHAN5G(140, 0), CHAN5G(149, 0),
178 CHAN5G(153, 0), CHAN5G(157, 0),
179 CHAN5G(161, 0), CHAN5G(165, 0),
180 CHAN5G(184, 0), CHAN5G(188, 0),
181 CHAN5G(192, 0), CHAN5G(196, 0),
182 CHAN5G(200, 0), CHAN5G(204, 0),
183 CHAN5G(208, 0), CHAN5G(212, 0),
184 CHAN5G(216, 0),
185};
186
Arend van Spriel5b435de2011-10-05 13:19:03 +0200187static struct ieee80211_supported_band __wl_band_2ghz = {
188 .band = IEEE80211_BAND_2GHZ,
189 .channels = __wl_2ghz_channels,
190 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
191 .bitrates = wl_g_rates,
192 .n_bitrates = wl_g_rates_size,
193};
194
195static struct ieee80211_supported_band __wl_band_5ghz_a = {
196 .band = IEEE80211_BAND_5GHZ,
197 .channels = __wl_5ghz_a_channels,
198 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
199 .bitrates = wl_a_rates,
200 .n_bitrates = wl_a_rates_size,
201};
202
Hante Meulemand48200b2013-04-03 12:40:29 +0200203/* This is to override regulatory domains defined in cfg80211 module (reg.c)
204 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200205 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
206 * With respect to these flags, wpa_supplicant doesn't * start p2p
207 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200208 * domain are to be done here.
209 */
210static const struct ieee80211_regdomain brcmf_regdom = {
211 .n_reg_rules = 4,
212 .alpha2 = "99",
213 .reg_rules = {
214 /* IEEE 802.11b/g, channels 1..11 */
215 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
216 /* If any */
217 /* IEEE 802.11 channel 14 - Only JP enables
218 * this and for 802.11b only
219 */
220 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
221 /* IEEE 802.11a, channel 36..64 */
222 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
223 /* IEEE 802.11a, channel 100..165 */
224 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200225};
226
227static const u32 __wl_cipher_suites[] = {
228 WLAN_CIPHER_SUITE_WEP40,
229 WLAN_CIPHER_SUITE_WEP104,
230 WLAN_CIPHER_SUITE_TKIP,
231 WLAN_CIPHER_SUITE_CCMP,
232 WLAN_CIPHER_SUITE_AES_CMAC,
233};
234
Hante Meuleman1a873342012-09-27 14:17:54 +0200235/* Vendor specific ie. id = 221, oui and type defines exact ie */
236struct brcmf_vs_tlv {
237 u8 id;
238 u8 len;
239 u8 oui[3];
240 u8 oui_type;
241};
242
243struct parsed_vndr_ie_info {
244 u8 *ie_ptr;
245 u32 ie_len; /* total length including id & length field */
246 struct brcmf_vs_tlv vndrie;
247};
248
249struct parsed_vndr_ies {
250 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100251 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200252};
253
Alwin Beukersef6ac172011-10-12 20:51:26 +0200254/* Quarter dBm units to mW
255 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
256 * Table is offset so the last entry is largest mW value that fits in
257 * a u16.
258 */
259
260#define QDBM_OFFSET 153 /* Offset for first entry */
261#define QDBM_TABLE_LEN 40 /* Table size */
262
263/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
264 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
265 */
266#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
267
268/* Largest mW value that will round down to the last table entry,
269 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
270 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
271 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
272 */
273#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
274
275static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
276/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
277/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
278/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
279/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
280/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
281/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
282};
283
284static u16 brcmf_qdbm_to_mw(u8 qdbm)
285{
286 uint factor = 1;
287 int idx = qdbm - QDBM_OFFSET;
288
289 if (idx >= QDBM_TABLE_LEN)
290 /* clamp to max u16 mW value */
291 return 0xFFFF;
292
293 /* scale the qdBm index up to the range of the table 0-40
294 * where an offset of 40 qdBm equals a factor of 10 mW.
295 */
296 while (idx < 0) {
297 idx += 40;
298 factor *= 10;
299 }
300
301 /* return the mW value scaled down to the correct factor of 10,
302 * adding in factor/2 to get proper rounding.
303 */
304 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
305}
306
307static u8 brcmf_mw_to_qdbm(u16 mw)
308{
309 u8 qdbm;
310 int offset;
311 uint mw_uint = mw;
312 uint boundary;
313
314 /* handle boundary case */
315 if (mw_uint <= 1)
316 return 0;
317
318 offset = QDBM_OFFSET;
319
320 /* move mw into the range of the table */
321 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
322 mw_uint *= 10;
323 offset -= 40;
324 }
325
326 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
327 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
328 nqdBm_to_mW_map[qdbm]) / 2;
329 if (mw_uint < boundary)
330 break;
331 }
332
333 qdbm += (u8) offset;
334
335 return qdbm;
336}
337
Franky Lin83cf17a2013-04-11 13:28:50 +0200338u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
339 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700340{
Franky Lin83cf17a2013-04-11 13:28:50 +0200341 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700342
Franky Lin83cf17a2013-04-11 13:28:50 +0200343 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
344 ch_inf.bw = BRCMU_CHAN_BW_20;
345 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700346
Franky Lin83cf17a2013-04-11 13:28:50 +0200347 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700348}
349
Hante Meuleman89286dc2013-02-08 15:53:46 +0100350/* Traverse a string of 1-byte tag/1-byte length/variable-length value
351 * triples, returning a pointer to the substring whose first element
352 * matches tag
353 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100354const struct brcmf_tlv *
355brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100356{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100357 const struct brcmf_tlv *elt = buf;
358 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100359
360 /* find tagged parameter */
361 while (totlen >= TLV_HDR_LEN) {
362 int len = elt->len;
363
364 /* validate remaining totlen */
365 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
366 return elt;
367
368 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
369 totlen -= (len + TLV_HDR_LEN);
370 }
371
372 return NULL;
373}
374
375/* Is any of the tlvs the expected entry? If
376 * not update the tlvs buffer pointer/length.
377 */
378static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100379brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
380 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100381{
382 /* If the contents match the OUI and the type */
383 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
384 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
385 type == ie[TLV_BODY_OFF + oui_len]) {
386 return true;
387 }
388
389 if (tlvs == NULL)
390 return false;
391 /* point to the next ie */
392 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
393 /* calculate the length of the rest of the buffer */
394 *tlvs_len -= (int)(ie - *tlvs);
395 /* update the pointer to the start of the buffer */
396 *tlvs = ie;
397
398 return false;
399}
400
401static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100402brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100403{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100404 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100405
406 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100407 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100408 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
409 return (struct brcmf_vs_tlv *)ie;
410 }
411 return NULL;
412}
413
414static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100415brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100416{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100417 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100418
419 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
420 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
421 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
422 return (struct brcmf_vs_tlv *)ie;
423 }
424 return NULL;
425}
426
427
Arend van Spriel5b435de2011-10-05 13:19:03 +0200428static void convert_key_from_CPU(struct brcmf_wsec_key *key,
429 struct brcmf_wsec_key_le *key_le)
430{
431 key_le->index = cpu_to_le32(key->index);
432 key_le->len = cpu_to_le32(key->len);
433 key_le->algo = cpu_to_le32(key->algo);
434 key_le->flags = cpu_to_le32(key->flags);
435 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
436 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
437 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
438 memcpy(key_le->data, key->data, sizeof(key->data));
439 memcpy(key_le->ea, key->ea, sizeof(key->ea));
440}
441
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200442static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700443send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200444{
445 int err;
446 struct brcmf_wsec_key_le key_le;
447
448 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200449
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700450 brcmf_netdev_wait_pend8021x(ndev);
451
Arend van Sprielac24be62012-10-22 10:36:23 -0700452 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700453 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200454
Arend van Spriel5b435de2011-10-05 13:19:03 +0200455 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100456 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200457 return err;
458}
459
Hante Meulemanb3657452013-05-27 21:09:53 +0200460static s32
461brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
462{
463 s32 err;
464 u32 mode;
465
466 if (enable)
467 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
468 else
469 mode = 0;
470
471 /* Try to set and enable ARP offload feature, this may fail, then it */
472 /* is simply not supported and err 0 will be returned */
473 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
474 if (err) {
475 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
476 mode, err);
477 err = 0;
478 } else {
479 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
480 if (err) {
481 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
482 enable, err);
483 err = 0;
484 } else
485 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
486 enable, mode);
487 }
488
489 return err;
490}
491
Arend van Spriel9f440b72013-02-08 15:53:36 +0100492static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
493 const char *name,
494 enum nl80211_iftype type,
495 u32 *flags,
496 struct vif_params *params)
497{
498 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
499 switch (type) {
500 case NL80211_IFTYPE_ADHOC:
501 case NL80211_IFTYPE_STATION:
502 case NL80211_IFTYPE_AP:
503 case NL80211_IFTYPE_AP_VLAN:
504 case NL80211_IFTYPE_WDS:
505 case NL80211_IFTYPE_MONITOR:
506 case NL80211_IFTYPE_MESH_POINT:
507 return ERR_PTR(-EOPNOTSUPP);
508 case NL80211_IFTYPE_P2P_CLIENT:
509 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200510 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100511 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
512 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100513 default:
514 return ERR_PTR(-EINVAL);
515 }
516}
517
Arend van Sprielf96aa072013-04-05 10:57:48 +0200518void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100519{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100520 s32 err = 0;
521
522 if (check_vif_up(ifp->vif)) {
523 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
524 if (err) {
525 brcmf_err("fail to set mpc\n");
526 return;
527 }
528 brcmf_dbg(INFO, "MPC : %d\n", mpc);
529 }
530}
531
Arend van Spriela0f472a2013-04-05 10:57:49 +0200532s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
533 struct brcmf_if *ifp, bool aborted,
534 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100535{
536 struct brcmf_scan_params_le params_le;
537 struct cfg80211_scan_request *scan_request;
538 s32 err = 0;
539
540 brcmf_dbg(SCAN, "Enter\n");
541
542 /* clear scan request, because the FW abort can cause a second call */
543 /* to this functon and might cause a double cfg80211_scan_done */
544 scan_request = cfg->scan_request;
545 cfg->scan_request = NULL;
546
547 if (timer_pending(&cfg->escan_timeout))
548 del_timer_sync(&cfg->escan_timeout);
549
550 if (fw_abort) {
551 /* Do a scan abort to stop the driver's scan engine */
552 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
553 memset(&params_le, 0, sizeof(params_le));
554 memset(params_le.bssid, 0xFF, ETH_ALEN);
555 params_le.bss_type = DOT11_BSSTYPE_ANY;
556 params_le.scan_type = 0;
557 params_le.channel_num = cpu_to_le32(1);
558 params_le.nprobes = cpu_to_le32(1);
559 params_le.active_time = cpu_to_le32(-1);
560 params_le.passive_time = cpu_to_le32(-1);
561 params_le.home_time = cpu_to_le32(-1);
562 /* Scan is aborted by setting channel_list[0] to -1 */
563 params_le.channel_list[0] = cpu_to_le16(-1);
564 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200565 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100566 &params_le, sizeof(params_le));
567 if (err)
568 brcmf_err("Scan abort failed\n");
569 }
570 /*
571 * e-scan can be initiated by scheduled scan
572 * which takes precedence.
573 */
574 if (cfg->sched_escan) {
575 brcmf_dbg(SCAN, "scheduled scan completed\n");
576 cfg->sched_escan = false;
577 if (!aborted)
578 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Sprielf96aa072013-04-05 10:57:48 +0200579 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100580 } else if (scan_request) {
581 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
582 aborted ? "Aborted" : "Done");
583 cfg80211_scan_done(scan_request, aborted);
Arend van Sprielf96aa072013-04-05 10:57:48 +0200584 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100585 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100586 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
587 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100588
589 return err;
590}
591
Arend van Spriel9f440b72013-02-08 15:53:36 +0100592static
593int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
594{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100595 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
596 struct net_device *ndev = wdev->netdev;
597
598 /* vif event pending in firmware */
599 if (brcmf_cfg80211_vif_event_armed(cfg))
600 return -EBUSY;
601
602 if (ndev) {
603 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200604 cfg->escan_info.ifp == netdev_priv(ndev))
605 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
606 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100607
608 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
609 }
610
Arend van Spriel9f440b72013-02-08 15:53:36 +0100611 switch (wdev->iftype) {
612 case NL80211_IFTYPE_ADHOC:
613 case NL80211_IFTYPE_STATION:
614 case NL80211_IFTYPE_AP:
615 case NL80211_IFTYPE_AP_VLAN:
616 case NL80211_IFTYPE_WDS:
617 case NL80211_IFTYPE_MONITOR:
618 case NL80211_IFTYPE_MESH_POINT:
619 return -EOPNOTSUPP;
620 case NL80211_IFTYPE_P2P_CLIENT:
621 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200622 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100623 return brcmf_p2p_del_vif(wiphy, wdev);
624 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100625 default:
626 return -EINVAL;
627 }
628 return -EOPNOTSUPP;
629}
630
Arend van Spriel5b435de2011-10-05 13:19:03 +0200631static s32
632brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
633 enum nl80211_iftype type, u32 *flags,
634 struct vif_params *params)
635{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100636 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700637 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100638 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200639 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200640 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200641 s32 err = 0;
642
Arend van Sprield96b8012012-12-05 15:26:02 +0100643 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200644
645 switch (type) {
646 case NL80211_IFTYPE_MONITOR:
647 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100648 brcmf_err("type (%d) : currently we do not support this type\n",
649 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200650 return -EOPNOTSUPP;
651 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100652 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200653 infra = 0;
654 break;
655 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100656 /* Ignore change for p2p IF. Unclear why supplicant does this */
657 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
658 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
659 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
660 /* WAR: It is unexpected to get a change of VIF for P2P
661 * IF, but it happens. The request can not be handled
662 * but returning EPERM causes a crash. Returning 0
663 * without setting ieee80211_ptr->iftype causes trace
664 * (WARN_ON) but it works with wpa_supplicant
665 */
666 return 0;
667 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100668 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200669 infra = 1;
670 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200671 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100672 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100673 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200674 ap = 1;
675 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200676 default:
677 err = -EINVAL;
678 goto done;
679 }
680
Hante Meuleman1a873342012-09-27 14:17:54 +0200681 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100682 if (type == NL80211_IFTYPE_P2P_GO) {
683 brcmf_dbg(INFO, "IF Type = P2P GO\n");
684 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
685 }
686 if (!err) {
687 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
688 brcmf_dbg(INFO, "IF Type = AP\n");
689 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200690 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100691 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200692 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100693 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200694 err = -EAGAIN;
695 goto done;
696 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100697 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
698 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200699 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200700 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200701
702done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100703 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200704
705 return err;
706}
707
Franky Lin83cf17a2013-04-11 13:28:50 +0200708static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
709 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200710 struct cfg80211_scan_request *request)
711{
712 u32 n_ssids;
713 u32 n_channels;
714 s32 i;
715 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200716 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200717 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200718 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200719
Arend van Sprielba40d162012-10-22 13:55:38 -0700720 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200721 params_le->bss_type = DOT11_BSSTYPE_ANY;
722 params_le->scan_type = 0;
723 params_le->channel_num = 0;
724 params_le->nprobes = cpu_to_le32(-1);
725 params_le->active_time = cpu_to_le32(-1);
726 params_le->passive_time = cpu_to_le32(-1);
727 params_le->home_time = cpu_to_le32(-1);
728 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
729
730 /* if request is null exit so it will be all channel broadcast scan */
731 if (!request)
732 return;
733
734 n_ssids = request->n_ssids;
735 n_channels = request->n_channels;
736 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100737 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
738 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200739 if (n_channels > 0) {
740 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200741 chanspec = channel_to_chanspec(&cfg->d11inf,
742 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100743 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
744 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200745 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200746 }
747 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100748 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200749 }
750 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100751 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200752 if (n_ssids > 0) {
753 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
754 n_channels * sizeof(u16);
755 offset = roundup(offset, sizeof(u32));
756 ptr = (char *)params_le + offset;
757 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200758 memset(&ssid_le, 0, sizeof(ssid_le));
759 ssid_le.SSID_len =
760 cpu_to_le32(request->ssids[i].ssid_len);
761 memcpy(ssid_le.SSID, request->ssids[i].ssid,
762 request->ssids[i].ssid_len);
763 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100764 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200765 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100766 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
767 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200768 memcpy(ptr, &ssid_le, sizeof(ssid_le));
769 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200770 }
771 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100772 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200773 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100774 brcmf_dbg(SCAN, "SSID %s len=%d\n",
775 params_le->ssid_le.SSID,
776 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200777 params_le->ssid_le.SSID_len =
778 cpu_to_le32(request->ssids->ssid_len);
779 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
780 request->ssids->ssid_len);
781 }
782 }
783 /* Adding mask to channel numbers */
784 params_le->channel_num =
785 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
786 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
787}
788
789static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200790brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +0200791 struct cfg80211_scan_request *request, u16 action)
792{
793 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
794 offsetof(struct brcmf_escan_params_le, params_le);
795 struct brcmf_escan_params_le *params;
796 s32 err = 0;
797
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100798 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200799
800 if (request != NULL) {
801 /* Allocate space for populating ssids in struct */
802 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
803
804 /* Allocate space for populating ssids in struct */
805 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
806 }
807
808 params = kzalloc(params_size, GFP_KERNEL);
809 if (!params) {
810 err = -ENOMEM;
811 goto exit;
812 }
813 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +0200814 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200815 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
816 params->action = cpu_to_le16(action);
817 params->sync_id = cpu_to_le16(0x1234);
818
Arend van Spriela0f472a2013-04-05 10:57:49 +0200819 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200820 if (err) {
821 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100822 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200823 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100824 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200825 }
826
827 kfree(params);
828exit:
829 return err;
830}
831
832static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200833brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +0200834 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200835{
836 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700837 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200838 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100839 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200840
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100841 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200842 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100843 escan->wiphy = wiphy;
844 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700845 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +0200846 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700847 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200848 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100849 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200850 return err;
851 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200852 brcmf_set_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200853 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200854 results->version = 0;
855 results->count = 0;
856 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
857
Arend van Spriela0f472a2013-04-05 10:57:49 +0200858 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200859 if (err)
Arend van Sprielf96aa072013-04-05 10:57:48 +0200860 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200861 return err;
862}
863
864static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200865brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +0200866 struct cfg80211_scan_request *request,
867 struct cfg80211_ssid *this_ssid)
868{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200869 struct brcmf_if *ifp = vif->ifp;
870 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +0200871 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800872 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700873 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200874 bool escan_req;
875 bool spec_scan;
876 s32 err;
877 u32 SSID_len;
878
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100879 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200880
Arend van Sprielc1179032012-10-22 13:55:33 -0700881 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100882 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200883 return -EAGAIN;
884 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700885 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100886 brcmf_err("Scanning being aborted: status (%lu)\n",
887 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200888 return -EAGAIN;
889 }
Arend van Spriel1687eee2013-04-23 12:53:11 +0200890 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
891 brcmf_err("Scanning suppressed: status (%lu)\n",
892 cfg->scan_status);
893 return -EAGAIN;
894 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700895 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100896 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200897 return -EAGAIN;
898 }
899
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100900 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +0200901 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
902 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100903
Hante Meulemane756af52012-09-11 21:18:52 +0200904 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200905 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200906 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
907
908 escan_req = false;
909 if (request) {
910 /* scan bss */
911 ssids = request->ssids;
912 escan_req = true;
913 } else {
914 /* scan in ibss */
915 /* we don't do escan in ibss */
916 ssids = this_ssid;
917 }
918
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200919 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700920 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200921 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100922 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +0200923 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100924 if (err)
925 goto scan_out;
926
Arend van Spriela0f472a2013-04-05 10:57:49 +0200927 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800928 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200929 goto scan_out;
930 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100931 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
932 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200933 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
934 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
935 sr->ssid_le.SSID_len = cpu_to_le32(0);
936 spec_scan = false;
937 if (SSID_len) {
938 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
939 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
940 spec_scan = true;
941 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100942 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200943
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700944 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700945 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700946 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200947 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100948 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200949 goto scan_out;
950 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200951 brcmf_set_mpc(ifp, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700952 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700953 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200954 if (err) {
955 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100956 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
957 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200958 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100959 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200960
Arend van Sprielf96aa072013-04-05 10:57:48 +0200961 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200962 goto scan_out;
963 }
964 }
965
966 return 0;
967
968scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700969 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200970 if (timer_pending(&cfg->escan_timeout))
971 del_timer_sync(&cfg->escan_timeout);
972 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200973 return err;
974}
975
Arend van Spriel5b435de2011-10-05 13:19:03 +0200976static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700977brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200978{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200979 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200980 s32 err = 0;
981
Arend van Sprield96b8012012-12-05 15:26:02 +0100982 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200983 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
984 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200985 return -EIO;
986
Arend van Spriela0f472a2013-04-05 10:57:49 +0200987 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200988
Arend van Spriel5b435de2011-10-05 13:19:03 +0200989 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100990 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200991
Arend van Sprield96b8012012-12-05 15:26:02 +0100992 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200993 return err;
994}
995
996static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
997{
998 s32 err = 0;
999
Arend van Sprielac24be62012-10-22 10:36:23 -07001000 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1001 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001002 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001003 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001004
1005 return err;
1006}
1007
1008static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1009{
1010 s32 err = 0;
1011
Arend van Sprielac24be62012-10-22 10:36:23 -07001012 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1013 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001014 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001015 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001016
1017 return err;
1018}
1019
1020static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1021{
1022 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001023 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001024
Arend van Sprielac24be62012-10-22 10:36:23 -07001025 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001026 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001027 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001028 return err;
1029 }
1030 return err;
1031}
1032
1033static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1034{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001035 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1036 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001037 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001038 s32 err = 0;
1039
Arend van Sprield96b8012012-12-05 15:26:02 +01001040 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001041 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001042 return -EIO;
1043
1044 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001045 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1046 cfg->conf->rts_threshold = wiphy->rts_threshold;
1047 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001048 if (!err)
1049 goto done;
1050 }
1051 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001052 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1053 cfg->conf->frag_threshold = wiphy->frag_threshold;
1054 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001055 if (!err)
1056 goto done;
1057 }
1058 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001059 && (cfg->conf->retry_long != wiphy->retry_long)) {
1060 cfg->conf->retry_long = wiphy->retry_long;
1061 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001062 if (!err)
1063 goto done;
1064 }
1065 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001066 && (cfg->conf->retry_short != wiphy->retry_short)) {
1067 cfg->conf->retry_short = wiphy->retry_short;
1068 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001069 if (!err)
1070 goto done;
1071 }
1072
1073done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001074 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001075 return err;
1076}
1077
Arend van Spriel5b435de2011-10-05 13:19:03 +02001078static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1079{
1080 memset(prof, 0, sizeof(*prof));
1081}
1082
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001083static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001084{
Piotr Haber61730d42013-04-23 12:53:12 +02001085 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001086 s32 err = 0;
1087
Arend van Sprield96b8012012-12-05 15:26:02 +01001088 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001089
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001090 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001091 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001092 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001093 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001094 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001095 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001096 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001097 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001098 cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
1099
Arend van Spriel5b435de2011-10-05 13:19:03 +02001100 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001101 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001102 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1103 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001104 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001105}
1106
1107static s32
1108brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1109 struct cfg80211_ibss_params *params)
1110{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001111 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001112 struct brcmf_if *ifp = netdev_priv(ndev);
1113 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001114 struct brcmf_join_params join_params;
1115 size_t join_params_size = 0;
1116 s32 err = 0;
1117 s32 wsec = 0;
1118 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001119 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001120
Arend van Sprield96b8012012-12-05 15:26:02 +01001121 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001122 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001123 return -EIO;
1124
1125 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001126 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001127 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001128 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001129 return -EOPNOTSUPP;
1130 }
1131
Arend van Sprielc1179032012-10-22 13:55:33 -07001132 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133
1134 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001135 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001136 else
Arend van Spriel16886732012-12-05 15:26:04 +01001137 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138
Johannes Berg683b6d32012-11-08 21:25:48 +01001139 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001140 brcmf_dbg(CONN, "channel: %d\n",
1141 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001142 else
Arend van Spriel16886732012-12-05 15:26:04 +01001143 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001144
1145 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001146 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147 else
Arend van Spriel16886732012-12-05 15:26:04 +01001148 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149
1150 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001151 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152 else
Arend van Spriel16886732012-12-05 15:26:04 +01001153 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154
1155 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001156 brcmf_dbg(CONN, "beacon interval: %d\n",
1157 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001158 else
Arend van Spriel16886732012-12-05 15:26:04 +01001159 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160
1161 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001162 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163 else
Arend van Spriel16886732012-12-05 15:26:04 +01001164 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165
1166 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001167 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001168 else
Arend van Spriel16886732012-12-05 15:26:04 +01001169 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170
1171 /* Configure Privacy for starter */
1172 if (params->privacy)
1173 wsec |= WEP_ENABLED;
1174
Arend van Sprielc1179032012-10-22 13:55:33 -07001175 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001176 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001177 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001178 goto done;
1179 }
1180
1181 /* Configure Beacon Interval for starter */
1182 if (params->beacon_interval)
1183 bcnprd = params->beacon_interval;
1184 else
1185 bcnprd = 100;
1186
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001187 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001188 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001189 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001190 goto done;
1191 }
1192
1193 /* Configure required join parameter */
1194 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1195
1196 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001197 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1198 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1199 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1200 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001201 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001202
1203 /* BSSID */
1204 if (params->bssid) {
1205 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1206 join_params_size = sizeof(join_params.ssid_le) +
1207 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001208 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001210 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001211 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001212 }
1213
Arend van Spriel5b435de2011-10-05 13:19:03 +02001214 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001215 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001216 u32 target_channel;
1217
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001218 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001219 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001220 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001221 if (params->channel_fixed) {
1222 /* adding chanspec */
Franky Lin83cf17a2013-04-11 13:28:50 +02001223 chanspec = channel_to_chanspec(&cfg->d11inf,
1224 params->chandef.chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001225 join_params.params_le.chanspec_list[0] =
1226 cpu_to_le16(chanspec);
1227 join_params.params_le.chanspec_num = cpu_to_le32(1);
1228 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001229 }
1230
1231 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001232 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001233 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001234 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001236 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237 goto done;
1238 }
1239 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001240 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001241
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001242 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001243
1244
Arend van Sprielc1179032012-10-22 13:55:33 -07001245 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001246 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001247 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001248 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001249 goto done;
1250 }
1251
1252done:
1253 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001254 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001255 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001256 return err;
1257}
1258
1259static s32
1260brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1261{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001262 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001263 s32 err = 0;
1264
Arend van Sprield96b8012012-12-05 15:26:02 +01001265 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001266 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001267 return -EIO;
1268
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001269 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001270
Arend van Sprield96b8012012-12-05 15:26:02 +01001271 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272
1273 return err;
1274}
1275
1276static s32 brcmf_set_wpa_version(struct net_device *ndev,
1277 struct cfg80211_connect_params *sme)
1278{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001279 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001280 struct brcmf_cfg80211_security *sec;
1281 s32 val = 0;
1282 s32 err = 0;
1283
1284 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1285 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1286 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1287 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1288 else
1289 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001290 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001291 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001292 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001293 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001294 return err;
1295 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001296 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001297 sec->wpa_versions = sme->crypto.wpa_versions;
1298 return err;
1299}
1300
1301static s32 brcmf_set_auth_type(struct net_device *ndev,
1302 struct cfg80211_connect_params *sme)
1303{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001304 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 struct brcmf_cfg80211_security *sec;
1306 s32 val = 0;
1307 s32 err = 0;
1308
1309 switch (sme->auth_type) {
1310 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1311 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001312 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001313 break;
1314 case NL80211_AUTHTYPE_SHARED_KEY:
1315 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001316 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001317 break;
1318 case NL80211_AUTHTYPE_AUTOMATIC:
1319 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001320 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 break;
1322 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001323 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324 default:
1325 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001326 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001327 break;
1328 }
1329
Hante Meuleman89286dc2013-02-08 15:53:46 +01001330 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001331 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001332 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001333 return err;
1334 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001335 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001336 sec->auth_type = sme->auth_type;
1337 return err;
1338}
1339
1340static s32
1341brcmf_set_set_cipher(struct net_device *ndev,
1342 struct cfg80211_connect_params *sme)
1343{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001344 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001345 struct brcmf_cfg80211_security *sec;
1346 s32 pval = 0;
1347 s32 gval = 0;
1348 s32 err = 0;
1349
1350 if (sme->crypto.n_ciphers_pairwise) {
1351 switch (sme->crypto.ciphers_pairwise[0]) {
1352 case WLAN_CIPHER_SUITE_WEP40:
1353 case WLAN_CIPHER_SUITE_WEP104:
1354 pval = WEP_ENABLED;
1355 break;
1356 case WLAN_CIPHER_SUITE_TKIP:
1357 pval = TKIP_ENABLED;
1358 break;
1359 case WLAN_CIPHER_SUITE_CCMP:
1360 pval = AES_ENABLED;
1361 break;
1362 case WLAN_CIPHER_SUITE_AES_CMAC:
1363 pval = AES_ENABLED;
1364 break;
1365 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001366 brcmf_err("invalid cipher pairwise (%d)\n",
1367 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001368 return -EINVAL;
1369 }
1370 }
1371 if (sme->crypto.cipher_group) {
1372 switch (sme->crypto.cipher_group) {
1373 case WLAN_CIPHER_SUITE_WEP40:
1374 case WLAN_CIPHER_SUITE_WEP104:
1375 gval = WEP_ENABLED;
1376 break;
1377 case WLAN_CIPHER_SUITE_TKIP:
1378 gval = TKIP_ENABLED;
1379 break;
1380 case WLAN_CIPHER_SUITE_CCMP:
1381 gval = AES_ENABLED;
1382 break;
1383 case WLAN_CIPHER_SUITE_AES_CMAC:
1384 gval = AES_ENABLED;
1385 break;
1386 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001387 brcmf_err("invalid cipher group (%d)\n",
1388 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001389 return -EINVAL;
1390 }
1391 }
1392
Arend van Spriel16886732012-12-05 15:26:04 +01001393 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001394 /* In case of privacy, but no security and WPS then simulate */
1395 /* setting AES. WPS-2.0 allows no security */
1396 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1397 sme->privacy)
1398 pval = AES_ENABLED;
1399 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001400 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001401 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 return err;
1403 }
1404
Arend van Spriel06bb1232012-09-27 14:17:56 +02001405 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001406 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1407 sec->cipher_group = sme->crypto.cipher_group;
1408
1409 return err;
1410}
1411
1412static s32
1413brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1414{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001415 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001416 struct brcmf_cfg80211_security *sec;
1417 s32 val = 0;
1418 s32 err = 0;
1419
1420 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001421 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1422 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001423 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001424 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001425 return err;
1426 }
1427 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1428 switch (sme->crypto.akm_suites[0]) {
1429 case WLAN_AKM_SUITE_8021X:
1430 val = WPA_AUTH_UNSPECIFIED;
1431 break;
1432 case WLAN_AKM_SUITE_PSK:
1433 val = WPA_AUTH_PSK;
1434 break;
1435 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001436 brcmf_err("invalid cipher group (%d)\n",
1437 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001438 return -EINVAL;
1439 }
1440 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1441 switch (sme->crypto.akm_suites[0]) {
1442 case WLAN_AKM_SUITE_8021X:
1443 val = WPA2_AUTH_UNSPECIFIED;
1444 break;
1445 case WLAN_AKM_SUITE_PSK:
1446 val = WPA2_AUTH_PSK;
1447 break;
1448 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001449 brcmf_err("invalid cipher group (%d)\n",
1450 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001451 return -EINVAL;
1452 }
1453 }
1454
Arend van Spriel16886732012-12-05 15:26:04 +01001455 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001456 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1457 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001459 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001460 return err;
1461 }
1462 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001463 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001464 sec->wpa_auth = sme->crypto.akm_suites[0];
1465
1466 return err;
1467}
1468
1469static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001470brcmf_set_sharedkey(struct net_device *ndev,
1471 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001473 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474 struct brcmf_cfg80211_security *sec;
1475 struct brcmf_wsec_key key;
1476 s32 val;
1477 s32 err = 0;
1478
Arend van Spriel16886732012-12-05 15:26:04 +01001479 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480
Roland Vossena718e2f2011-10-12 20:51:24 +02001481 if (sme->key_len == 0)
1482 return 0;
1483
Arend van Spriel06bb1232012-09-27 14:17:56 +02001484 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001485 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1486 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001487
1488 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1489 return 0;
1490
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001491 if (!(sec->cipher_pairwise &
1492 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1493 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001494
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001495 memset(&key, 0, sizeof(key));
1496 key.len = (u32) sme->key_len;
1497 key.index = (u32) sme->key_idx;
1498 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001499 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001500 return -EINVAL;
1501 }
1502 memcpy(key.data, sme->key, key.len);
1503 key.flags = BRCMF_PRIMARY_KEY;
1504 switch (sec->cipher_pairwise) {
1505 case WLAN_CIPHER_SUITE_WEP40:
1506 key.algo = CRYPTO_ALGO_WEP1;
1507 break;
1508 case WLAN_CIPHER_SUITE_WEP104:
1509 key.algo = CRYPTO_ALGO_WEP128;
1510 break;
1511 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001512 brcmf_err("Invalid algorithm (%d)\n",
1513 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001514 return -EINVAL;
1515 }
1516 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001517 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1518 key.len, key.index, key.algo);
1519 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001520 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001521 if (err)
1522 return err;
1523
1524 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001525 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001526 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001527 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001528 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001529 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530 }
1531 return err;
1532}
1533
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001534static
1535enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1536 enum nl80211_auth_type type)
1537{
1538 u32 ci;
1539 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1540 /* shift to ignore chip revision */
1541 ci = brcmf_get_chip_info(ifp) >> 4;
1542 switch (ci) {
1543 case 43236:
1544 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1545 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1546 default:
1547 break;
1548 }
1549 }
1550 return type;
1551}
1552
Arend van Spriel5b435de2011-10-05 13:19:03 +02001553static s32
1554brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001555 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001556{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001557 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001558 struct brcmf_if *ifp = netdev_priv(ndev);
1559 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001560 struct ieee80211_channel *chan = sme->channel;
1561 struct brcmf_join_params join_params;
1562 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001563 const struct brcmf_tlv *rsn_ie;
1564 const struct brcmf_vs_tlv *wpa_ie;
1565 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001566 u32 ie_len;
1567 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001568 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569
1570 s32 err = 0;
1571
Arend van Sprield96b8012012-12-05 15:26:02 +01001572 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001573 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 return -EIO;
1575
1576 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001577 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001578 return -EOPNOTSUPP;
1579 }
1580
Hante Meuleman89286dc2013-02-08 15:53:46 +01001581 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1582 /* A normal (non P2P) connection request setup. */
1583 ie = NULL;
1584 ie_len = 0;
1585 /* find the WPA_IE */
1586 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1587 if (wpa_ie) {
1588 ie = wpa_ie;
1589 ie_len = wpa_ie->len + TLV_HDR_LEN;
1590 } else {
1591 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001592 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1593 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001594 WLAN_EID_RSN);
1595 if (rsn_ie) {
1596 ie = rsn_ie;
1597 ie_len = rsn_ie->len + TLV_HDR_LEN;
1598 }
1599 }
1600 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1601 }
1602
1603 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1604 sme->ie, sme->ie_len);
1605 if (err)
1606 brcmf_err("Set Assoc REQ IE Failed\n");
1607 else
1608 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1609
Arend van Sprielc1179032012-10-22 13:55:33 -07001610 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001611
1612 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001613 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001614 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001615 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001616 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1617 cfg->channel, chan->center_freq, chanspec);
1618 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001619 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001620 chanspec = 0;
1621 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001622
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001623 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624
1625 err = brcmf_set_wpa_version(ndev, sme);
1626 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001627 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001628 goto done;
1629 }
1630
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001631 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 err = brcmf_set_auth_type(ndev, sme);
1633 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001634 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001635 goto done;
1636 }
1637
1638 err = brcmf_set_set_cipher(ndev, sme);
1639 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001640 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001641 goto done;
1642 }
1643
1644 err = brcmf_set_key_mgmt(ndev, sme);
1645 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001646 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001647 goto done;
1648 }
1649
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001650 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001651 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001652 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 goto done;
1654 }
1655
Hante Meuleman89286dc2013-02-08 15:53:46 +01001656 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1657 (u32)sme->ssid_len);
1658 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1659 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1660 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1661 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1662 profile->ssid.SSID_len);
1663 }
1664
1665 /* Join with specific BSSID and cached SSID
1666 * If SSID is zero join based on BSSID only
1667 */
1668 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1669 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1670 if (cfg->channel)
1671 join_params_size += sizeof(u16);
1672 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1673 if (ext_join_params == NULL) {
1674 err = -ENOMEM;
1675 goto done;
1676 }
1677 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1678 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1679 profile->ssid.SSID_len);
1680 /*increase dwell time to receive probe response or detect Beacon
1681 * from target AP at a noisy air only during connect command
1682 */
1683 ext_join_params->scan_le.active_time =
1684 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1685 ext_join_params->scan_le.passive_time =
1686 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1687 /* Set up join scan parameters */
1688 ext_join_params->scan_le.scan_type = -1;
1689 /* to sync with presence period of VSDB GO.
1690 * Send probe request more frequently. Probe request will be stopped
1691 * when it gets probe response from target AP/GO.
1692 */
1693 ext_join_params->scan_le.nprobes =
1694 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1695 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1696 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1697
1698 if (sme->bssid)
1699 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1700 else
1701 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1702
1703 if (cfg->channel) {
1704 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1705
1706 ext_join_params->assoc_le.chanspec_list[0] =
1707 cpu_to_le16(chanspec);
1708 }
1709
1710 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1711 join_params_size);
1712 kfree(ext_join_params);
1713 if (!err)
1714 /* This is it. join command worked, we are done */
1715 goto done;
1716
1717 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001718 memset(&join_params, 0, sizeof(join_params));
1719 join_params_size = sizeof(join_params.ssid_le);
1720
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001721 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001722 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001723
Hante Meuleman89286dc2013-02-08 15:53:46 +01001724 if (sme->bssid)
1725 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1726 else
1727 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001728
Hante Meuleman17012612013-02-06 18:40:44 +01001729 if (cfg->channel) {
1730 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1731 join_params.params_le.chanspec_num = cpu_to_le32(1);
1732 join_params_size += sizeof(join_params.params_le);
1733 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001734 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001735 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001736 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001737 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001738
1739done:
1740 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001741 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001742 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001743 return err;
1744}
1745
1746static s32
1747brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1748 u16 reason_code)
1749{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001750 struct brcmf_if *ifp = netdev_priv(ndev);
1751 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001752 struct brcmf_scb_val_le scbval;
1753 s32 err = 0;
1754
Arend van Sprield96b8012012-12-05 15:26:02 +01001755 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001756 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001757 return -EIO;
1758
Arend van Sprielc1179032012-10-22 13:55:33 -07001759 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001760 cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001761
Arend van Spriel06bb1232012-09-27 14:17:56 +02001762 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001764 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001765 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001766 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001767 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001768
Arend van Sprield96b8012012-12-05 15:26:02 +01001769 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 return err;
1771}
1772
1773static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001774brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001775 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001776{
1777
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001778 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001779 struct net_device *ndev = cfg_to_ndev(cfg);
1780 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001781 u16 txpwrmw;
1782 s32 err = 0;
1783 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001784 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001785
Arend van Sprield96b8012012-12-05 15:26:02 +01001786 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001787 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001788 return -EIO;
1789
1790 switch (type) {
1791 case NL80211_TX_POWER_AUTOMATIC:
1792 break;
1793 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001794 case NL80211_TX_POWER_FIXED:
1795 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001796 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 err = -EINVAL;
1798 goto done;
1799 }
1800 break;
1801 }
1802 /* Make sure radio is off or on as far as software is concerned */
1803 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001804 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001805 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001806 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001807
1808 if (dbm > 0xffff)
1809 txpwrmw = 0xffff;
1810 else
1811 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001812 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1813 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001814 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001815 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001816 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001817
1818done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001819 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001820 return err;
1821}
1822
Johannes Bergc8442112012-10-24 10:17:18 +02001823static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1824 struct wireless_dev *wdev,
1825 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001826{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001827 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001828 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001829 s32 txpwrdbm;
1830 u8 result;
1831 s32 err = 0;
1832
Arend van Sprield96b8012012-12-05 15:26:02 +01001833 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001834 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001835 return -EIO;
1836
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001837 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001838 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001839 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 goto done;
1841 }
1842
1843 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001844 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001845
1846done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001847 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001848 return err;
1849}
1850
1851static s32
1852brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1853 u8 key_idx, bool unicast, bool multicast)
1854{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001855 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001856 u32 index;
1857 u32 wsec;
1858 s32 err = 0;
1859
Arend van Sprield96b8012012-12-05 15:26:02 +01001860 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001861 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001862 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001863 return -EIO;
1864
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001865 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001866 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001867 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001868 goto done;
1869 }
1870
1871 if (wsec & WEP_ENABLED) {
1872 /* Just select a new current key */
1873 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001874 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001875 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001876 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001877 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001878 }
1879done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001880 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001881 return err;
1882}
1883
1884static s32
1885brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1886 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1887{
Hante Meuleman992f6062013-04-02 21:06:17 +02001888 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02001891 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02001892
1893 memset(&key, 0, sizeof(key));
1894 key.index = (u32) key_idx;
1895 /* Instead of bcast for ea address for default wep keys,
1896 driver needs it to be Null */
1897 if (!is_multicast_ether_addr(mac_addr))
1898 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1899 key.len = (u32) params->key_len;
1900 /* check for key index change */
1901 if (key.len == 0) {
1902 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001903 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001904 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001905 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001906 } else {
1907 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001908 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001909 return -EINVAL;
1910 }
1911
Arend van Spriel16886732012-12-05 15:26:04 +01001912 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001913 memcpy(key.data, params->key, key.len);
1914
Hante Meuleman992f6062013-04-02 21:06:17 +02001915 if ((ifp->vif->mode != WL_MODE_AP) &&
1916 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1917 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001918 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1919 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1920 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1921 }
1922
1923 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1924 if (params->seq && params->seq_len == 6) {
1925 /* rx iv */
1926 u8 *ivptr;
1927 ivptr = (u8 *) params->seq;
1928 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1929 (ivptr[3] << 8) | ivptr[2];
1930 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1931 key.iv_initialized = true;
1932 }
1933
1934 switch (params->cipher) {
1935 case WLAN_CIPHER_SUITE_WEP40:
1936 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001937 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001938 break;
1939 case WLAN_CIPHER_SUITE_WEP104:
1940 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001941 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001942 break;
1943 case WLAN_CIPHER_SUITE_TKIP:
1944 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001945 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001946 break;
1947 case WLAN_CIPHER_SUITE_AES_CMAC:
1948 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001949 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950 break;
1951 case WLAN_CIPHER_SUITE_CCMP:
1952 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001953 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001954 break;
1955 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001956 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 return -EINVAL;
1958 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001959 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001960 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001961 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001962 }
1963 return err;
1964}
1965
1966static s32
1967brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1968 u8 key_idx, bool pairwise, const u8 *mac_addr,
1969 struct key_params *params)
1970{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001971 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001972 struct brcmf_wsec_key key;
1973 s32 val;
1974 s32 wsec;
1975 s32 err = 0;
1976 u8 keybuf[8];
1977
Arend van Sprield96b8012012-12-05 15:26:02 +01001978 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001979 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001980 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981 return -EIO;
1982
1983 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001984 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1986 }
1987 memset(&key, 0, sizeof(key));
1988
1989 key.len = (u32) params->key_len;
1990 key.index = (u32) key_idx;
1991
1992 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001993 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001994 err = -EINVAL;
1995 goto done;
1996 }
1997 memcpy(key.data, params->key, key.len);
1998
1999 key.flags = BRCMF_PRIMARY_KEY;
2000 switch (params->cipher) {
2001 case WLAN_CIPHER_SUITE_WEP40:
2002 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002003 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002004 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002005 break;
2006 case WLAN_CIPHER_SUITE_WEP104:
2007 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002008 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002009 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002010 break;
2011 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002012 if (ifp->vif->mode != WL_MODE_AP) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002013 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002014 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2015 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2016 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2017 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002018 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002019 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002020 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021 break;
2022 case WLAN_CIPHER_SUITE_AES_CMAC:
2023 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002024 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002025 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002026 break;
2027 case WLAN_CIPHER_SUITE_CCMP:
2028 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002029 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002030 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002031 break;
2032 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002033 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034 err = -EINVAL;
2035 goto done;
2036 }
2037
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002038 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002039 if (err)
2040 goto done;
2041
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002042 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002043 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002044 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002045 goto done;
2046 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002047 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002048 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002049 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002050 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002051 goto done;
2052 }
2053
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002055 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056 return err;
2057}
2058
2059static s32
2060brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2061 u8 key_idx, bool pairwise, const u8 *mac_addr)
2062{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002063 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 struct brcmf_wsec_key key;
2065 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066
Arend van Sprield96b8012012-12-05 15:26:02 +01002067 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002068 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 return -EIO;
2070
Hante Meuleman256c3742012-11-05 16:22:28 -08002071 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2072 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002073 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002074 return -EINVAL;
2075 }
2076
Arend van Spriel5b435de2011-10-05 13:19:03 +02002077 memset(&key, 0, sizeof(key));
2078
2079 key.index = (u32) key_idx;
2080 key.flags = BRCMF_PRIMARY_KEY;
2081 key.algo = CRYPTO_ALGO_OFF;
2082
Arend van Spriel16886732012-12-05 15:26:04 +01002083 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002084
2085 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002086 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002087
Arend van Sprield96b8012012-12-05 15:26:02 +01002088 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 return err;
2090}
2091
2092static s32
2093brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2094 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2095 void (*callback) (void *cookie, struct key_params * params))
2096{
2097 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002098 struct brcmf_if *ifp = netdev_priv(ndev);
2099 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 struct brcmf_cfg80211_security *sec;
2101 s32 wsec;
2102 s32 err = 0;
2103
Arend van Sprield96b8012012-12-05 15:26:02 +01002104 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002105 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002106 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002107 return -EIO;
2108
2109 memset(&params, 0, sizeof(params));
2110
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002111 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002113 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114 /* Ignore this error, may happen during DISASSOC */
2115 err = -EAGAIN;
2116 goto done;
2117 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002118 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002119 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2121 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002122 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2124 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002125 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002126 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002127 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002128 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002129 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002130 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002133 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002134 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 err = -EINVAL;
2136 goto done;
2137 }
2138 callback(cookie, &params);
2139
2140done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002141 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142 return err;
2143}
2144
2145static s32
2146brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2147 struct net_device *ndev, u8 key_idx)
2148{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002149 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002150
2151 return -EOPNOTSUPP;
2152}
2153
2154static s32
2155brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002156 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002158 struct brcmf_if *ifp = netdev_priv(ndev);
2159 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 struct brcmf_scb_val_le scb_val;
2161 int rssi;
2162 s32 rate;
2163 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002164 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002165 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166
Arend van Sprield96b8012012-12-05 15:26:02 +01002167 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002168 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 return -EIO;
2170
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002171 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002172 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002173 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002174 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002175 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002176 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002177 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002178 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002179 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002180 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002181 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2182 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002183 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002184 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002185 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002186 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2187 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002188 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002189 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002190 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2191 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002192 err = -ENOENT;
2193 goto done;
2194 }
2195 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002196 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002197 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002198 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002199 goto done;
2200 } else {
2201 sinfo->filled |= STATION_INFO_TX_BITRATE;
2202 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002203 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002204 }
2205
Arend van Sprielc1179032012-10-22 13:55:33 -07002206 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2207 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002208 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002209 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2210 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002211 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002212 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002213 goto done;
2214 } else {
2215 rssi = le32_to_cpu(scb_val.val);
2216 sinfo->filled |= STATION_INFO_SIGNAL;
2217 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002218 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002219 }
2220 }
2221 } else
2222 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002224 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002225 return err;
2226}
2227
2228static s32
2229brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2230 bool enabled, s32 timeout)
2231{
2232 s32 pm;
2233 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002234 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002235 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236
Arend van Sprield96b8012012-12-05 15:26:02 +01002237 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
2239 /*
2240 * Powersave enable/disable request is coming from the
2241 * cfg80211 even before the interface is up. In that
2242 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002243 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244 * FW later while initializing the dongle
2245 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002246 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002247 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002248
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002249 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002250 goto done;
2251 }
2252
2253 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002254 /* Do not enable the power save after assoc if it is a p2p interface */
2255 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2256 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2257 pm = PM_OFF;
2258 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002259 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Arend van Sprielc1179032012-10-22 13:55:33 -07002261 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002262 if (err) {
2263 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002264 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002266 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267 }
2268done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002269 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002270 return err;
2271}
2272
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002273static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002274 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002276 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277 struct ieee80211_channel *notify_channel;
2278 struct cfg80211_bss *bss;
2279 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002280 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002281 s32 err = 0;
2282 u16 channel;
2283 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284 u16 notify_capability;
2285 u16 notify_interval;
2286 u8 *notify_ie;
2287 size_t notify_ielen;
2288 s32 notify_signal;
2289
2290 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002291 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 return 0;
2293 }
2294
Franky Lin83cf17a2013-04-11 13:28:50 +02002295 if (!bi->ctl_ch) {
2296 ch.chspec = le16_to_cpu(bi->chanspec);
2297 cfg->d11inf.decchspec(&ch);
2298 bi->ctl_ch = ch.chnum;
2299 }
2300 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301
2302 if (channel <= CH_MAX_2G_CHANNEL)
2303 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2304 else
2305 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2306
2307 freq = ieee80211_channel_to_frequency(channel, band->band);
2308 notify_channel = ieee80211_get_channel(wiphy, freq);
2309
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310 notify_capability = le16_to_cpu(bi->capability);
2311 notify_interval = le16_to_cpu(bi->beacon_period);
2312 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2313 notify_ielen = le32_to_cpu(bi->ie_length);
2314 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2315
Arend van Spriel16886732012-12-05 15:26:04 +01002316 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2317 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2318 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2319 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2320 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002321
2322 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002323 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324 notify_ielen, notify_signal, GFP_KERNEL);
2325
Franky Line78946e2011-11-10 20:30:34 +01002326 if (!bss)
2327 return -ENOMEM;
2328
Johannes Berg5b112d32013-02-01 01:49:58 +01002329 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002330
2331 return err;
2332}
2333
Roland Vossen6f09be02011-10-18 14:03:02 +02002334static struct brcmf_bss_info_le *
2335next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2336{
2337 if (bss == NULL)
2338 return list->bss_info_le;
2339 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2340 le32_to_cpu(bss->length));
2341}
2342
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002343static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344{
2345 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002346 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002347 s32 err = 0;
2348 int i;
2349
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002350 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002351 if (bss_list->count != 0 &&
2352 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002353 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2354 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002355 return -EOPNOTSUPP;
2356 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002357 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002358 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002359 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002360 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002361 if (err)
2362 break;
2363 }
2364 return err;
2365}
2366
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002367static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002368 struct net_device *ndev, const u8 *bssid)
2369{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002370 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002372 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002374 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002375 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376 u8 *buf = NULL;
2377 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002379 u16 notify_capability;
2380 u16 notify_interval;
2381 u8 *notify_ie;
2382 size_t notify_ielen;
2383 s32 notify_signal;
2384
Arend van Sprield96b8012012-12-05 15:26:02 +01002385 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386
2387 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2388 if (buf == NULL) {
2389 err = -ENOMEM;
2390 goto CleanUp;
2391 }
2392
2393 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2394
Arend van Sprielac24be62012-10-22 10:36:23 -07002395 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2396 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002397 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002398 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399 goto CleanUp;
2400 }
2401
Roland Vossend34bf642011-10-18 14:03:01 +02002402 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002403
Franky Lin83cf17a2013-04-11 13:28:50 +02002404 ch.chspec = le16_to_cpu(bi->chanspec);
2405 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002406
Franky Lin83cf17a2013-04-11 13:28:50 +02002407 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002408 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2409 else
2410 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2411
Franky Lin83cf17a2013-04-11 13:28:50 +02002412 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002413 notify_channel = ieee80211_get_channel(wiphy, freq);
2414
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 notify_capability = le16_to_cpu(bi->capability);
2416 notify_interval = le16_to_cpu(bi->beacon_period);
2417 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2418 notify_ielen = le32_to_cpu(bi->ie_length);
2419 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2420
Franky Lin83cf17a2013-04-11 13:28:50 +02002421 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002422 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2423 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2424 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425
Franky Line78946e2011-11-10 20:30:34 +01002426 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002427 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2429
Franky Line78946e2011-11-10 20:30:34 +01002430 if (!bss) {
2431 err = -ENOMEM;
2432 goto CleanUp;
2433 }
2434
Johannes Berg5b112d32013-02-01 01:49:58 +01002435 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002436
Arend van Spriel5b435de2011-10-05 13:19:03 +02002437CleanUp:
2438
2439 kfree(buf);
2440
Arend van Sprield96b8012012-12-05 15:26:02 +01002441 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002442
2443 return err;
2444}
2445
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002446static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002447{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002448 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002449}
2450
Hante Meuleman89286dc2013-02-08 15:53:46 +01002451static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2452 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002453{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002454 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002455 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002456 struct brcmf_ssid *ssid;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002457 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002458 u16 beacon_interval;
2459 u8 dtim_period;
2460 size_t ie_len;
2461 u8 *ie;
2462 s32 err = 0;
2463
Arend van Sprield96b8012012-12-05 15:26:02 +01002464 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002465 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002466 return err;
2467
Arend van Spriel06bb1232012-09-27 14:17:56 +02002468 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002469
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002470 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002471 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002472 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002473 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002474 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002475 goto update_bss_info_out;
2476 }
2477
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002478 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2479 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002480 if (err)
2481 goto update_bss_info_out;
2482
2483 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2484 ie_len = le32_to_cpu(bi->ie_length);
2485 beacon_interval = le16_to_cpu(bi->beacon_period);
2486
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002487 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488 if (tim)
2489 dtim_period = tim->data[1];
2490 else {
2491 /*
2492 * active scan was done so we could not get dtim
2493 * information out of probe response.
2494 * so we speficially query dtim information to dongle.
2495 */
2496 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002497 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002498 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002499 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002500 goto update_bss_info_out;
2501 }
2502 dtim_period = (u8)var;
2503 }
2504
Arend van Spriel5b435de2011-10-05 13:19:03 +02002505update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002506 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002507 return err;
2508}
2509
Hante Meuleman18e2f612013-02-08 15:53:49 +01002510void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002511{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002512 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002513
Arend van Sprielc1179032012-10-22 13:55:33 -07002514 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002515 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002516 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002517 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002518 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002519 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2520 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002521}
2522
Hante Meulemane756af52012-09-11 21:18:52 +02002523static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2524{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002525 struct brcmf_cfg80211_info *cfg =
2526 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002527 escan_timeout_work);
2528
Arend van Spriela0f472a2013-04-05 10:57:49 +02002529 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002530}
2531
2532static void brcmf_escan_timeout(unsigned long data)
2533{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002534 struct brcmf_cfg80211_info *cfg =
2535 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002536
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002537 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002538 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002539 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002540 }
2541}
2542
2543static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002544brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2545 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002546 struct brcmf_bss_info_le *bss_info_le)
2547{
Franky Lin83cf17a2013-04-11 13:28:50 +02002548 struct brcmu_chan ch_bss, ch_bss_info_le;
2549
2550 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2551 cfg->d11inf.decchspec(&ch_bss);
2552 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2553 cfg->d11inf.decchspec(&ch_bss_info_le);
2554
Hante Meulemane756af52012-09-11 21:18:52 +02002555 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002556 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002557 bss_info_le->SSID_len == bss->SSID_len &&
2558 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002559 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2560 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002561 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2562 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2563
Hante Meulemane756af52012-09-11 21:18:52 +02002564 /* preserve max RSSI if the measurements are
2565 * both on-channel or both off-channel
2566 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002567 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002568 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002569 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2570 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002571 /* preserve the on-channel rssi measurement
2572 * if the new measurement is off channel
2573 */
2574 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002575 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002576 }
2577 return 1;
2578 }
2579 return 0;
2580}
2581
2582static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002583brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002584 const struct brcmf_event_msg *e, void *data)
2585{
Arend van Spriel19937322012-11-05 16:22:32 -08002586 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002587 s32 status;
2588 s32 err = 0;
2589 struct brcmf_escan_result_le *escan_result_le;
2590 struct brcmf_bss_info_le *bss_info_le;
2591 struct brcmf_bss_info_le *bss = NULL;
2592 u32 bi_length;
2593 struct brcmf_scan_results *list;
2594 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002595 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002596
Arend van Spriel5c36b992012-11-14 18:46:05 -08002597 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002598
Arend van Spriela0f472a2013-04-05 10:57:49 +02002599 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2600 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002601 return -EPERM;
2602 }
2603
2604 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002605 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002606 escan_result_le = (struct brcmf_escan_result_le *) data;
2607 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002608 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002609 goto exit;
2610 }
Hante Meulemane756af52012-09-11 21:18:52 +02002611 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002612 brcmf_err("Invalid bss_count %d: ignoring\n",
2613 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002614 goto exit;
2615 }
2616 bss_info_le = &escan_result_le->bss_info_le;
2617
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002618 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2619 goto exit;
2620
2621 if (!cfg->scan_request) {
2622 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2623 goto exit;
2624 }
2625
Hante Meulemane756af52012-09-11 21:18:52 +02002626 bi_length = le32_to_cpu(bss_info_le->length);
2627 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2628 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002629 brcmf_err("Invalid bss_info length %d: ignoring\n",
2630 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002631 goto exit;
2632 }
2633
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002634 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002635 BIT(NL80211_IFTYPE_ADHOC))) {
2636 if (le16_to_cpu(bss_info_le->capability) &
2637 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002638 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002639 goto exit;
2640 }
2641 }
2642
2643 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002644 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002645 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002646 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002647 goto exit;
2648 }
2649
2650 for (i = 0; i < list->count; i++) {
2651 bss = bss ? (struct brcmf_bss_info_le *)
2652 ((unsigned char *)bss +
2653 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002654 if (brcmf_compare_update_same_bss(cfg, bss,
2655 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002656 goto exit;
2657 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002658 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002659 bss_info_le, bi_length);
2660 list->version = le32_to_cpu(bss_info_le->version);
2661 list->buflen += bi_length;
2662 list->count++;
2663 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002664 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002665 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2666 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002667 if (cfg->scan_request) {
2668 cfg->bss_list = (struct brcmf_scan_results *)
2669 cfg->escan_info.escan_buf;
2670 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002671 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002672 brcmf_notify_escan_complete(cfg, ifp, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002673 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002674 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002675 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2676 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002677 }
2678exit:
2679 return err;
2680}
2681
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002682static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002683{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002684 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2685 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002686 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2687 /* Init scan_timeout timer */
2688 init_timer(&cfg->escan_timeout);
2689 cfg->escan_timeout.data = (unsigned long) cfg;
2690 cfg->escan_timeout.function = brcmf_escan_timeout;
2691 INIT_WORK(&cfg->escan_timeout_work,
2692 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002693}
2694
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002695static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002696{
2697 if (ms < 1000 / HZ) {
2698 cond_resched();
2699 mdelay(ms);
2700 } else {
2701 msleep(ms);
2702 }
2703}
2704
2705static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2706{
Arend van Sprield96b8012012-12-05 15:26:02 +01002707 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002708
Arend van Spriel5b435de2011-10-05 13:19:03 +02002709 return 0;
2710}
2711
2712static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2713 struct cfg80211_wowlan *wow)
2714{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002715 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2716 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002717 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718
Arend van Sprield96b8012012-12-05 15:26:02 +01002719 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002720
2721 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002722 * if the primary net_device is not READY there is nothing
2723 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002724 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002725 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2726 if (!check_vif_up(vif))
2727 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002728
Arend van Spriel7d641072012-10-22 13:55:39 -07002729 list_for_each_entry(vif, &cfg->vif_list, list) {
2730 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2731 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002732 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002733 * While going to suspend if associated with AP disassociate
2734 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002735 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002736 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002737
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002738 /* Make sure WPA_Supplicant receives all the event
2739 * generated due to DISASSOC call to the fw to keep
2740 * the state fw and WPA_Supplicant state consistent
2741 */
2742 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002743 }
2744
Arend van Spriel7d641072012-10-22 13:55:39 -07002745 /* end any scanning */
2746 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002747 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002748
2749 /* Turn off watchdog timer */
Arend van Sprielf96aa072013-04-05 10:57:48 +02002750 brcmf_set_mpc(netdev_priv(ndev), 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002751
Arend van Spriel7d641072012-10-22 13:55:39 -07002752exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002753 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002754 /* clear any scanning activity */
2755 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756 return 0;
2757}
2758
2759static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002760brcmf_update_pmklist(struct net_device *ndev,
2761 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2762{
2763 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002764 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002765
Arend van Spriel40c8e952011-10-12 20:51:20 +02002766 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2767
Arend van Spriel16886732012-12-05 15:26:04 +01002768 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002769 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002770 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2771 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002773 brcmf_dbg(CONN, "%02x\n",
2774 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002775 }
2776
2777 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002778 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2779 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002780
2781 return err;
2782}
2783
2784static s32
2785brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2786 struct cfg80211_pmksa *pmksa)
2787{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002788 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002789 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002790 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002791 s32 err = 0;
2792 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002793 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002794
Arend van Sprield96b8012012-12-05 15:26:02 +01002795 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002796 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 return -EIO;
2798
Arend van Spriel40c8e952011-10-12 20:51:20 +02002799 pmkid_len = le32_to_cpu(pmkids->npmkid);
2800 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2802 break;
2803 if (i < WL_NUM_PMKIDS_MAX) {
2804 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2805 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002806 if (i == pmkid_len) {
2807 pmkid_len++;
2808 pmkids->npmkid = cpu_to_le32(pmkid_len);
2809 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002810 } else
2811 err = -EINVAL;
2812
Arend van Spriel16886732012-12-05 15:26:04 +01002813 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2814 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002815 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002816 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002817
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002818 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819
Arend van Sprield96b8012012-12-05 15:26:02 +01002820 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002821 return err;
2822}
2823
2824static s32
2825brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2826 struct cfg80211_pmksa *pmksa)
2827{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002828 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002829 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 struct pmkid_list pmkid;
2831 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002832 int i, 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
2838 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2839 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2840
Arend van Spriel16886732012-12-05 15:26:04 +01002841 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2842 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002843 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002844 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002846 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002847 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002849 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002850 ETH_ALEN))
2851 break;
2852
Arend van Spriel40c8e952011-10-12 20:51:20 +02002853 if ((pmkid_len > 0)
2854 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002855 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002857 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002858 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2859 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002861 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2862 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002863 WLAN_PMKID_LEN);
2864 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002865 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002866 } else
2867 err = -EINVAL;
2868
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002869 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002870
Arend van Sprield96b8012012-12-05 15:26:02 +01002871 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872 return err;
2873
2874}
2875
2876static s32
2877brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2878{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002879 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002880 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 s32 err = 0;
2882
Arend van Sprield96b8012012-12-05 15:26:02 +01002883 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002884 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885 return -EIO;
2886
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002887 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2888 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002889
Arend van Sprield96b8012012-12-05 15:26:02 +01002890 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891 return err;
2892
2893}
2894
Arend van Spriele5806072012-09-19 22:21:08 +02002895/*
2896 * PFN result doesn't have all the info which are
2897 * required by the supplicant
2898 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2899 * via wl_inform_single_bss in the required format. Escan does require the
2900 * scan request in the form of cfg80211_scan_request. For timebeing, create
2901 * cfg80211_scan_request one out of the received PNO event.
2902 */
2903static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002904brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002905 const struct brcmf_event_msg *e, void *data)
2906{
Arend van Spriel19937322012-11-05 16:22:32 -08002907 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02002908 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2909 struct cfg80211_scan_request *request = NULL;
2910 struct cfg80211_ssid *ssid = NULL;
2911 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002912 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002913 int err = 0;
2914 int channel_req = 0;
2915 int band = 0;
2916 struct brcmf_pno_scanresults_le *pfn_result;
2917 u32 result_count;
2918 u32 status;
2919
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002920 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002921
Arend van Spriel5c36b992012-11-14 18:46:05 -08002922 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002923 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002924 return 0;
2925 }
2926
2927 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2928 result_count = le32_to_cpu(pfn_result->count);
2929 status = le32_to_cpu(pfn_result->status);
2930
2931 /*
2932 * PFN event is limited to fit 512 bytes so we may get
2933 * multiple NET_FOUND events. For now place a warning here.
2934 */
2935 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002936 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002937 if (result_count > 0) {
2938 int i;
2939
2940 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002941 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2942 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002943 if (!request || !ssid || !channel) {
2944 err = -ENOMEM;
2945 goto out_err;
2946 }
2947
2948 request->wiphy = wiphy;
2949 data += sizeof(struct brcmf_pno_scanresults_le);
2950 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2951
2952 for (i = 0; i < result_count; i++) {
2953 netinfo = &netinfo_start[i];
2954 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002955 brcmf_err("Invalid netinfo ptr. index: %d\n",
2956 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002957 err = -EINVAL;
2958 goto out_err;
2959 }
2960
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002961 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2962 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002963 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2964 ssid[i].ssid_len = netinfo->SSID_len;
2965 request->n_ssids++;
2966
2967 channel_req = netinfo->channel;
2968 if (channel_req <= CH_MAX_2G_CHANNEL)
2969 band = NL80211_BAND_2GHZ;
2970 else
2971 band = NL80211_BAND_5GHZ;
2972 channel[i].center_freq =
2973 ieee80211_channel_to_frequency(channel_req,
2974 band);
2975 channel[i].band = band;
2976 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2977 request->channels[i] = &channel[i];
2978 request->n_channels++;
2979 }
2980
2981 /* assign parsed ssid array */
2982 if (request->n_ssids)
2983 request->ssids = &ssid[0];
2984
Arend van Sprielc1179032012-10-22 13:55:33 -07002985 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002986 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002987 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002988 }
2989
Arend van Sprielc1179032012-10-22 13:55:33 -07002990 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel2668b0b2014-01-13 22:20:28 +01002991 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002992 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002993 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002994 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002995 goto out_err;
2996 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002997 cfg->sched_escan = true;
2998 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002999 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003000 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003001 goto out_err;
3002 }
3003
3004 kfree(ssid);
3005 kfree(channel);
3006 kfree(request);
3007 return 0;
3008
3009out_err:
3010 kfree(ssid);
3011 kfree(channel);
3012 kfree(request);
3013 cfg80211_sched_scan_stopped(wiphy);
3014 return err;
3015}
3016
Arend van Spriele5806072012-09-19 22:21:08 +02003017static int brcmf_dev_pno_clean(struct net_device *ndev)
3018{
Arend van Spriele5806072012-09-19 22:21:08 +02003019 int ret;
3020
3021 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003022 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003023 if (ret == 0) {
3024 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003025 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3026 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003027 }
3028 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003029 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003030
3031 return ret;
3032}
3033
3034static int brcmf_dev_pno_config(struct net_device *ndev)
3035{
3036 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003037
3038 memset(&pfn_param, 0, sizeof(pfn_param));
3039 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3040
3041 /* set extra pno params */
3042 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3043 pfn_param.repeat = BRCMF_PNO_REPEAT;
3044 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3045
3046 /* set up pno scan fr */
3047 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3048
Arend van Sprielac24be62012-10-22 10:36:23 -07003049 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3050 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003051}
3052
3053static int
3054brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3055 struct net_device *ndev,
3056 struct cfg80211_sched_scan_request *request)
3057{
Arend van Sprielc1179032012-10-22 13:55:33 -07003058 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003059 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003060 struct brcmf_pno_net_param_le pfn;
3061 int i;
3062 int ret = 0;
3063
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003064 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003065 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003066 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003067 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003068 return -EAGAIN;
3069 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003070 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3071 brcmf_err("Scanning suppressed: status (%lu)\n",
3072 cfg->scan_status);
3073 return -EAGAIN;
3074 }
Arend van Spriele5806072012-09-19 22:21:08 +02003075
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003076 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003077 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003078 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003079 return -EINVAL;
3080 }
3081
3082 if (request->n_ssids > 0) {
3083 for (i = 0; i < request->n_ssids; i++) {
3084 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003085 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3086 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003087
3088 /*
3089 * match_set ssids is a supert set of n_ssid list,
3090 * so we need not add these set seperately.
3091 */
3092 }
3093 }
3094
3095 if (request->n_match_sets > 0) {
3096 /* clean up everything */
3097 ret = brcmf_dev_pno_clean(ndev);
3098 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003099 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003100 return ret;
3101 }
3102
3103 /* configure pno */
3104 ret = brcmf_dev_pno_config(ndev);
3105 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003106 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003107 return -EINVAL;
3108 }
3109
3110 /* configure each match set */
3111 for (i = 0; i < request->n_match_sets; i++) {
3112 struct cfg80211_ssid *ssid;
3113 u32 ssid_len;
3114
3115 ssid = &request->match_sets[i].ssid;
3116 ssid_len = ssid->ssid_len;
3117
3118 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003119 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003120 continue;
3121 }
3122 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3123 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3124 pfn.wsec = cpu_to_le32(0);
3125 pfn.infra = cpu_to_le32(1);
3126 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3127 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3128 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003129 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003130 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003131 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3132 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003133 }
3134 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003135 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003136 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003137 return -EINVAL;
3138 }
3139 } else {
3140 return -EINVAL;
3141 }
3142
3143 return 0;
3144}
3145
3146static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3147 struct net_device *ndev)
3148{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003149 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003150
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003151 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003152 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003153 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003154 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003155 return 0;
3156}
Arend van Spriele5806072012-09-19 22:21:08 +02003157
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003158#ifdef CONFIG_NL80211_TESTMODE
David Spinadelfc73f112013-07-31 18:04:15 +03003159static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3160 struct wireless_dev *wdev,
3161 void *data, int len)
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003162{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003163 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003164 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003165 struct brcmf_dcmd *dcmd = data;
3166 struct sk_buff *reply;
3167 int ret;
3168
Arend van Sprield96b8012012-12-05 15:26:02 +01003169 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3170 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003171
3172 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003173 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3174 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003175 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003176 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3177 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003178 if (ret == 0) {
3179 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3180 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3181 ret = cfg80211_testmode_reply(reply);
3182 }
3183 return ret;
3184}
3185#endif
3186
Hante Meuleman1f170112013-02-06 18:40:38 +01003187static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003188{
3189 s32 err;
3190
3191 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003192 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003193 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003194 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003195 return err;
3196 }
3197 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003198 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003199 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003200 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003201 return err;
3202 }
3203 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003204 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003205 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003206 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003207 return err;
3208 }
3209
3210 return 0;
3211}
3212
3213static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3214{
3215 if (is_rsn_ie)
3216 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3217
3218 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3219}
3220
3221static s32
Johannes Berg4b5800f2014-01-15 14:55:59 +01003222brcmf_configure_wpaie(struct net_device *ndev,
3223 const struct brcmf_vs_tlv *wpa_ie,
3224 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003225{
Arend van Sprielac24be62012-10-22 10:36:23 -07003226 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003227 u32 auth = 0; /* d11 open authentication */
3228 u16 count;
3229 s32 err = 0;
3230 s32 len = 0;
3231 u32 i;
3232 u32 wsec;
3233 u32 pval = 0;
3234 u32 gval = 0;
3235 u32 wpa_auth = 0;
3236 u32 offset;
3237 u8 *data;
3238 u16 rsn_cap;
3239 u32 wme_bss_disable;
3240
Arend van Sprield96b8012012-12-05 15:26:02 +01003241 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003242 if (wpa_ie == NULL)
3243 goto exit;
3244
3245 len = wpa_ie->len + TLV_HDR_LEN;
3246 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003247 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003248 if (!is_rsn_ie)
3249 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003250 else
3251 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003252
3253 /* check for multicast cipher suite */
3254 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3255 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003256 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003257 goto exit;
3258 }
3259
3260 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3261 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003262 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003263 goto exit;
3264 }
3265 offset += TLV_OUI_LEN;
3266
3267 /* pick up multicast cipher */
3268 switch (data[offset]) {
3269 case WPA_CIPHER_NONE:
3270 gval = 0;
3271 break;
3272 case WPA_CIPHER_WEP_40:
3273 case WPA_CIPHER_WEP_104:
3274 gval = WEP_ENABLED;
3275 break;
3276 case WPA_CIPHER_TKIP:
3277 gval = TKIP_ENABLED;
3278 break;
3279 case WPA_CIPHER_AES_CCM:
3280 gval = AES_ENABLED;
3281 break;
3282 default:
3283 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003284 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003285 goto exit;
3286 }
3287
3288 offset++;
3289 /* walk thru unicast cipher list and pick up what we recognize */
3290 count = data[offset] + (data[offset + 1] << 8);
3291 offset += WPA_IE_SUITE_COUNT_LEN;
3292 /* Check for unicast suite(s) */
3293 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3294 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003295 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003296 goto exit;
3297 }
3298 for (i = 0; i < count; i++) {
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 switch (data[offset]) {
3306 case WPA_CIPHER_NONE:
3307 break;
3308 case WPA_CIPHER_WEP_40:
3309 case WPA_CIPHER_WEP_104:
3310 pval |= WEP_ENABLED;
3311 break;
3312 case WPA_CIPHER_TKIP:
3313 pval |= TKIP_ENABLED;
3314 break;
3315 case WPA_CIPHER_AES_CCM:
3316 pval |= AES_ENABLED;
3317 break;
3318 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003319 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003320 }
3321 offset++;
3322 }
3323 /* walk thru auth management suite list and pick up what we recognize */
3324 count = data[offset] + (data[offset + 1] << 8);
3325 offset += WPA_IE_SUITE_COUNT_LEN;
3326 /* Check for auth key management suite(s) */
3327 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3328 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003329 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003330 goto exit;
3331 }
3332 for (i = 0; i < count; i++) {
3333 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3334 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003335 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003336 goto exit;
3337 }
3338 offset += TLV_OUI_LEN;
3339 switch (data[offset]) {
3340 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003341 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003342 wpa_auth |= WPA_AUTH_NONE;
3343 break;
3344 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003345 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003346 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3347 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3348 break;
3349 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003350 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003351 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3352 (wpa_auth |= WPA_AUTH_PSK);
3353 break;
3354 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003355 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003356 }
3357 offset++;
3358 }
3359
3360 if (is_rsn_ie) {
3361 wme_bss_disable = 1;
3362 if ((offset + RSN_CAP_LEN) <= len) {
3363 rsn_cap = data[offset] + (data[offset + 1] << 8);
3364 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3365 wme_bss_disable = 0;
3366 }
3367 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003368 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003369 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003370 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003371 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003372 goto exit;
3373 }
3374 }
3375 /* FOR WPS , set SES_OW_ENABLED */
3376 wsec = (pval | gval | SES_OW_ENABLED);
3377
3378 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003379 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003380 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003381 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003382 goto exit;
3383 }
3384 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003385 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003386 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003387 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003388 goto exit;
3389 }
3390 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003391 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003392 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003393 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003394 goto exit;
3395 }
3396
3397exit:
3398 return err;
3399}
3400
3401static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003402brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003403 struct parsed_vndr_ies *vndr_ies)
3404{
3405 s32 err = 0;
3406 struct brcmf_vs_tlv *vndrie;
3407 struct brcmf_tlv *ie;
3408 struct parsed_vndr_ie_info *parsed_info;
3409 s32 remaining_len;
3410
3411 remaining_len = (s32)vndr_ie_len;
3412 memset(vndr_ies, 0, sizeof(*vndr_ies));
3413
3414 ie = (struct brcmf_tlv *)vndr_ie_buf;
3415 while (ie) {
3416 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3417 goto next;
3418 vndrie = (struct brcmf_vs_tlv *)ie;
3419 /* len should be bigger than OUI length + one */
3420 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003421 brcmf_err("invalid vndr ie. length is too small %d\n",
3422 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003423 goto next;
3424 }
3425 /* if wpa or wme ie, do not add ie */
3426 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3427 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3428 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003429 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003430 goto next;
3431 }
3432
3433 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3434
3435 /* save vndr ie information */
3436 parsed_info->ie_ptr = (char *)vndrie;
3437 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3438 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3439
3440 vndr_ies->count++;
3441
Arend van Sprield96b8012012-12-05 15:26:02 +01003442 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3443 parsed_info->vndrie.oui[0],
3444 parsed_info->vndrie.oui[1],
3445 parsed_info->vndrie.oui[2],
3446 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003447
Arend van Spriel9f440b72013-02-08 15:53:36 +01003448 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003449 break;
3450next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003451 remaining_len -= (ie->len + TLV_HDR_LEN);
3452 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003453 ie = NULL;
3454 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003455 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3456 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003457 }
3458 return err;
3459}
3460
3461static u32
3462brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3463{
3464
3465 __le32 iecount_le;
3466 __le32 pktflag_le;
3467
3468 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3469 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3470
3471 iecount_le = cpu_to_le32(1);
3472 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3473
3474 pktflag_le = cpu_to_le32(pktflag);
3475 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3476
3477 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3478
3479 return ie_len + VNDR_IE_HDR_SIZE;
3480}
3481
Arend van Spriel1332e262012-11-05 16:22:18 -08003482s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3483 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003484{
Arend van Spriel1332e262012-11-05 16:22:18 -08003485 struct brcmf_if *ifp;
3486 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003487 s32 err = 0;
3488 u8 *iovar_ie_buf;
3489 u8 *curr_ie_buf;
3490 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003491 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003492 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003493 u32 del_add_ie_buf_len = 0;
3494 u32 total_ie_buf_len = 0;
3495 u32 parsed_ie_buf_len = 0;
3496 struct parsed_vndr_ies old_vndr_ies;
3497 struct parsed_vndr_ies new_vndr_ies;
3498 struct parsed_vndr_ie_info *vndrie_info;
3499 s32 i;
3500 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003501 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003502
Arend van Spriel1332e262012-11-05 16:22:18 -08003503 if (!vif)
3504 return -ENODEV;
3505 ifp = vif->ifp;
3506 saved_ie = &vif->saved_ie;
3507
Arend van Sprield96b8012012-12-05 15:26:02 +01003508 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003509 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3510 if (!iovar_ie_buf)
3511 return -ENOMEM;
3512 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003513 switch (pktflag) {
3514 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3515 mgmt_ie_buf = saved_ie->probe_req_ie;
3516 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3517 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3518 break;
3519 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3520 mgmt_ie_buf = saved_ie->probe_res_ie;
3521 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3522 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3523 break;
3524 case BRCMF_VNDR_IE_BEACON_FLAG:
3525 mgmt_ie_buf = saved_ie->beacon_ie;
3526 mgmt_ie_len = &saved_ie->beacon_ie_len;
3527 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3528 break;
3529 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3530 mgmt_ie_buf = saved_ie->assoc_req_ie;
3531 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3532 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3533 break;
3534 default:
3535 err = -EPERM;
3536 brcmf_err("not suitable type\n");
3537 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003538 }
3539
3540 if (vndr_ie_len > mgmt_ie_buf_len) {
3541 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003542 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003543 goto exit;
3544 }
3545
3546 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3547 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3548 ptr = curr_ie_buf;
3549 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3550 for (i = 0; i < new_vndr_ies.count; i++) {
3551 vndrie_info = &new_vndr_ies.ie_info[i];
3552 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3553 vndrie_info->ie_len);
3554 parsed_ie_buf_len += vndrie_info->ie_len;
3555 }
3556 }
3557
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003558 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003559 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3560 (memcmp(mgmt_ie_buf, curr_ie_buf,
3561 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003562 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003563 goto exit;
3564 }
3565
3566 /* parse old vndr_ie */
3567 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3568
3569 /* make a command to delete old ie */
3570 for (i = 0; i < old_vndr_ies.count; i++) {
3571 vndrie_info = &old_vndr_ies.ie_info[i];
3572
Arend van Sprield96b8012012-12-05 15:26:02 +01003573 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3574 vndrie_info->vndrie.id,
3575 vndrie_info->vndrie.len,
3576 vndrie_info->vndrie.oui[0],
3577 vndrie_info->vndrie.oui[1],
3578 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003579
3580 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3581 vndrie_info->ie_ptr,
3582 vndrie_info->ie_len,
3583 "del");
3584 curr_ie_buf += del_add_ie_buf_len;
3585 total_ie_buf_len += del_add_ie_buf_len;
3586 }
3587 }
3588
3589 *mgmt_ie_len = 0;
3590 /* Add if there is any extra IE */
3591 if (mgmt_ie_buf && parsed_ie_buf_len) {
3592 ptr = mgmt_ie_buf;
3593
3594 remained_buf_len = mgmt_ie_buf_len;
3595
3596 /* make a command to add new ie */
3597 for (i = 0; i < new_vndr_ies.count; i++) {
3598 vndrie_info = &new_vndr_ies.ie_info[i];
3599
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003600 /* verify remained buf size before copy data */
3601 if (remained_buf_len < (vndrie_info->vndrie.len +
3602 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003603 brcmf_err("no space in mgmt_ie_buf: len left %d",
3604 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003605 break;
3606 }
3607 remained_buf_len -= (vndrie_info->ie_len +
3608 VNDR_IE_VSIE_OFFSET);
3609
Arend van Sprield96b8012012-12-05 15:26:02 +01003610 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3611 vndrie_info->vndrie.id,
3612 vndrie_info->vndrie.len,
3613 vndrie_info->vndrie.oui[0],
3614 vndrie_info->vndrie.oui[1],
3615 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003616
3617 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3618 vndrie_info->ie_ptr,
3619 vndrie_info->ie_len,
3620 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003621
3622 /* save the parsed IE in wl struct */
3623 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3624 vndrie_info->ie_len);
3625 *mgmt_ie_len += vndrie_info->ie_len;
3626
3627 curr_ie_buf += del_add_ie_buf_len;
3628 total_ie_buf_len += del_add_ie_buf_len;
3629 }
3630 }
3631 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003632 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003633 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003634 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003635 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003636 }
3637
3638exit:
3639 kfree(iovar_ie_buf);
3640 return err;
3641}
3642
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003643s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3644{
3645 s32 pktflags[] = {
3646 BRCMF_VNDR_IE_PRBREQ_FLAG,
3647 BRCMF_VNDR_IE_PRBRSP_FLAG,
3648 BRCMF_VNDR_IE_BEACON_FLAG
3649 };
3650 int i;
3651
3652 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3653 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3654
3655 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3656 return 0;
3657}
3658
Hante Meuleman1a873342012-09-27 14:17:54 +02003659static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003660brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3661 struct cfg80211_beacon_data *beacon)
3662{
3663 s32 err;
3664
3665 /* Set Beacon IEs to FW */
3666 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3667 beacon->tail, beacon->tail_len);
3668 if (err) {
3669 brcmf_err("Set Beacon IE Failed\n");
3670 return err;
3671 }
3672 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3673
3674 /* Set Probe Response IEs to FW */
3675 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3676 beacon->proberesp_ies,
3677 beacon->proberesp_ies_len);
3678 if (err)
3679 brcmf_err("Set Probe Resp IE Failed\n");
3680 else
3681 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3682
3683 return err;
3684}
3685
3686static s32
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003687brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
3688 struct brcmf_if *ifp,
3689 struct ieee80211_channel *channel)
3690{
3691 u16 chanspec;
3692 s32 err;
3693
3694 brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
3695 channel->center_freq);
3696
3697 chanspec = channel_to_chanspec(&cfg->d11inf, channel);
3698 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3699
3700 return err;
3701}
3702
3703static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003704brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3705 struct cfg80211_ap_settings *settings)
3706{
3707 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003708 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07003709 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01003710 const struct brcmf_tlv *ssid_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003711 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003712 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01003713 const struct brcmf_tlv *rsn_ie;
3714 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003715 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003716 enum nl80211_iftype dev_role;
3717 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003718
Arend van Sprield96b8012012-12-05 15:26:02 +01003719 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3720 cfg80211_get_chandef_type(&settings->chandef),
3721 settings->beacon_interval,
3722 settings->dtim_period);
3723 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3724 settings->ssid, settings->ssid_len, settings->auth_type,
3725 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003726
Hante Meuleman426d0a52013-02-08 15:53:53 +01003727 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003728
3729 memset(&ssid_le, 0, sizeof(ssid_le));
3730 if (settings->ssid == NULL || settings->ssid_len == 0) {
3731 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3732 ssid_ie = brcmf_parse_tlvs(
3733 (u8 *)&settings->beacon.head[ie_offset],
3734 settings->beacon.head_len - ie_offset,
3735 WLAN_EID_SSID);
3736 if (!ssid_ie)
3737 return -EINVAL;
3738
3739 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3740 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003741 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003742 } else {
3743 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3744 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3745 }
3746
Arend van Sprielf96aa072013-04-05 10:57:48 +02003747 brcmf_set_mpc(ifp, 0);
Hante Meulemanb3657452013-05-27 21:09:53 +02003748 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003749
3750 /* find the RSN_IE */
3751 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3752 settings->beacon.tail_len, WLAN_EID_RSN);
3753
3754 /* find the WPA_IE */
3755 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3756 settings->beacon.tail_len);
3757
Hante Meuleman1a873342012-09-27 14:17:54 +02003758 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003759 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003760 if (wpa_ie != NULL) {
3761 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003762 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003763 if (err < 0)
3764 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003765 } else {
3766 /* RSN IE */
3767 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003768 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003769 if (err < 0)
3770 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003771 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003772 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003773 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003774 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003775 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003776
Hante Meulemana0f07952013-02-08 15:53:47 +01003777 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003778
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003779 err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
3780 if (err < 0) {
3781 brcmf_err("Set Channel failed, %d\n", err);
3782 goto exit;
3783 }
3784
Hante Meuleman1a873342012-09-27 14:17:54 +02003785 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003786 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003787 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003788 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003789 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003790 goto exit;
3791 }
3792 }
3793 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003794 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003795 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003796 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003797 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003798 goto exit;
3799 }
3800 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003801
3802 if (dev_role == NL80211_IFTYPE_AP) {
3803 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3804 if (err < 0) {
3805 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3806 goto exit;
3807 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003808 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003809 }
3810
Hante Meulemana0f07952013-02-08 15:53:47 +01003811 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003812 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003813 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003814 goto exit;
3815 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003816 if (dev_role == NL80211_IFTYPE_AP) {
3817 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3818 if (err < 0) {
3819 brcmf_err("setting AP mode failed %d\n", err);
3820 goto exit;
3821 }
3822 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3823 if (err < 0) {
3824 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3825 goto exit;
3826 }
3827
3828 memset(&join_params, 0, sizeof(join_params));
3829 /* join parameters starts with ssid */
3830 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3831 /* create softap */
3832 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3833 &join_params, sizeof(join_params));
3834 if (err < 0) {
3835 brcmf_err("SET SSID error (%d)\n", err);
3836 goto exit;
3837 }
3838 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3839 } else {
3840 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3841 sizeof(ssid_le));
3842 if (err < 0) {
3843 brcmf_err("setting ssid failed %d\n", err);
3844 goto exit;
3845 }
3846 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3847 bss_enable.enable = cpu_to_le32(1);
3848 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3849 sizeof(bss_enable));
3850 if (err < 0) {
3851 brcmf_err("bss_enable config failed %d\n", err);
3852 goto exit;
3853 }
3854
3855 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3856 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003857 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3858 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003859
3860exit:
Hante Meulemanb3657452013-05-27 21:09:53 +02003861 if (err) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02003862 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003863 brcmf_configure_arp_offload(ifp, true);
3864 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003865 return err;
3866}
3867
3868static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3869{
Arend van Sprielc1179032012-10-22 13:55:33 -07003870 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003871 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003872 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02003873 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003874
Arend van Sprield96b8012012-12-05 15:26:02 +01003875 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003876
Hante Meuleman426d0a52013-02-08 15:53:53 +01003877 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003878 /* Due to most likely deauths outstanding we sleep */
3879 /* first to make sure they get processed by fw. */
3880 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003881
3882 memset(&join_params, 0, sizeof(join_params));
3883 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3884 &join_params, sizeof(join_params));
3885 if (err < 0)
3886 brcmf_err("SET SSID error (%d)\n", err);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003887 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003888 if (err < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003889 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003890 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3891 if (err < 0)
3892 brcmf_err("setting AP mode failed %d\n", err);
3893 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3894 if (err < 0)
3895 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003896 } else {
3897 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3898 bss_enable.enable = cpu_to_le32(0);
3899 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3900 sizeof(bss_enable));
3901 if (err < 0)
3902 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003903 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02003904 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003905 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003906 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3907 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3908
Hante Meuleman1a873342012-09-27 14:17:54 +02003909 return err;
3910}
3911
Hante Meulemana0f07952013-02-08 15:53:47 +01003912static s32
3913brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3914 struct cfg80211_beacon_data *info)
3915{
Hante Meulemana0f07952013-02-08 15:53:47 +01003916 struct brcmf_if *ifp = netdev_priv(ndev);
3917 s32 err;
3918
3919 brcmf_dbg(TRACE, "Enter\n");
3920
Hante Meulemana0f07952013-02-08 15:53:47 +01003921 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3922
3923 return err;
3924}
3925
Hante Meuleman1a873342012-09-27 14:17:54 +02003926static int
3927brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3928 u8 *mac)
3929{
Hante Meulemana0f07952013-02-08 15:53:47 +01003930 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003931 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003932 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003933 s32 err;
3934
3935 if (!mac)
3936 return -EFAULT;
3937
Arend van Sprield96b8012012-12-05 15:26:02 +01003938 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003939
Hante Meulemana0f07952013-02-08 15:53:47 +01003940 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3941 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003942 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003943 return -EIO;
3944
3945 memcpy(&scbval.ea, mac, ETH_ALEN);
3946 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003947 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003948 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003949 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003950 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01003951
Arend van Sprield96b8012012-12-05 15:26:02 +01003952 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003953 return err;
3954}
3955
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003956
3957static void
3958brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3959 struct wireless_dev *wdev,
3960 u16 frame_type, bool reg)
3961{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003962 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003963 u16 mgmt_type;
3964
3965 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3966
3967 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003968 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003969 if (reg)
3970 vif->mgmt_rx_reg |= BIT(mgmt_type);
3971 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01003972 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003973}
3974
3975
3976static int
3977brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003978 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003979{
3980 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003981 struct ieee80211_channel *chan = params->chan;
3982 const u8 *buf = params->buf;
3983 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003984 const struct ieee80211_mgmt *mgmt;
3985 struct brcmf_cfg80211_vif *vif;
3986 s32 err = 0;
3987 s32 ie_offset;
3988 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01003989 struct brcmf_fil_action_frame_le *action_frame;
3990 struct brcmf_fil_af_params_le *af_params;
3991 bool ack;
3992 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02003993 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003994
3995 brcmf_dbg(TRACE, "Enter\n");
3996
3997 *cookie = 0;
3998
3999 mgmt = (const struct ieee80211_mgmt *)buf;
4000
Hante Meulemana0f07952013-02-08 15:53:47 +01004001 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4002 brcmf_err("Driver only allows MGMT packet type\n");
4003 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004004 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004005
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004006 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4007
Hante Meulemana0f07952013-02-08 15:53:47 +01004008 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4009 /* Right now the only reason to get a probe response */
4010 /* is for p2p listen response or for p2p GO from */
4011 /* wpa_supplicant. Unfortunately the probe is send */
4012 /* on primary ndev, while dongle wants it on the p2p */
4013 /* vif. Since this is only reason for a probe */
4014 /* response to be sent, the vif is taken from cfg. */
4015 /* If ever desired to send proberesp for non p2p */
4016 /* response then data should be checked for */
4017 /* "DIRECT-". Note in future supplicant will take */
4018 /* dedicated p2p wdev to do this and then this 'hack'*/
4019 /* is not needed anymore. */
4020 ie_offset = DOT11_MGMT_HDR_LEN +
4021 DOT11_BCN_PRB_FIXED_LEN;
4022 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004023 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4024 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4025 err = brcmf_vif_set_mgmt_ie(vif,
4026 BRCMF_VNDR_IE_PRBRSP_FLAG,
4027 &buf[ie_offset],
4028 ie_len);
4029 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4030 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004031 } else if (ieee80211_is_action(mgmt->frame_control)) {
4032 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4033 if (af_params == NULL) {
4034 brcmf_err("unable to allocate frame\n");
4035 err = -ENOMEM;
4036 goto exit;
4037 }
4038 action_frame = &af_params->action_frame;
4039 /* Add the packet Id */
4040 action_frame->packet_id = cpu_to_le32(*cookie);
4041 /* Add BSSID */
4042 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4043 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4044 /* Add the length exepted for 802.11 header */
4045 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004046 /* Add the channel. Use the one specified as parameter if any or
4047 * the current one (got from the firmware) otherwise
4048 */
4049 if (chan)
4050 freq = chan->center_freq;
4051 else
4052 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4053 &freq);
4054 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004055 af_params->channel = cpu_to_le32(chan_nr);
4056
4057 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4058 le16_to_cpu(action_frame->len));
4059
4060 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004061 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004062
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004063 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004064 af_params);
4065
4066 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4067 GFP_KERNEL);
4068 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004069 } else {
4070 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4071 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4072 }
4073
Hante Meuleman18e2f612013-02-08 15:53:49 +01004074exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004075 return err;
4076}
4077
4078
4079static int
4080brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4081 struct wireless_dev *wdev,
4082 u64 cookie)
4083{
4084 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4085 struct brcmf_cfg80211_vif *vif;
4086 int err = 0;
4087
4088 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4089
4090 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4091 if (vif == NULL) {
4092 brcmf_err("No p2p device available for probe response\n");
4093 err = -ENODEV;
4094 goto exit;
4095 }
4096 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4097exit:
4098 return err;
4099}
4100
Piotr Haber61730d42013-04-23 12:53:12 +02004101static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4102 struct wireless_dev *wdev,
4103 enum nl80211_crit_proto_id proto,
4104 u16 duration)
4105{
4106 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4107 struct brcmf_cfg80211_vif *vif;
4108
4109 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4110
4111 /* only DHCP support for now */
4112 if (proto != NL80211_CRIT_PROTO_DHCP)
4113 return -EINVAL;
4114
4115 /* suppress and abort scanning */
4116 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4117 brcmf_abort_scanning(cfg);
4118
4119 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4120}
4121
4122static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4123 struct wireless_dev *wdev)
4124{
4125 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4126 struct brcmf_cfg80211_vif *vif;
4127
4128 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4129
4130 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4131 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4132}
4133
Arend van Spriel89c2f382013-08-10 12:27:25 +02004134static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4135{
4136 int ret;
4137
4138 switch (oper) {
4139 case NL80211_TDLS_DISCOVERY_REQ:
4140 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4141 break;
4142 case NL80211_TDLS_SETUP:
4143 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4144 break;
4145 case NL80211_TDLS_TEARDOWN:
4146 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4147 break;
4148 default:
4149 brcmf_err("unsupported operation: %d\n", oper);
4150 ret = -EOPNOTSUPP;
4151 }
4152 return ret;
4153}
4154
4155static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4156 struct net_device *ndev, u8 *peer,
4157 enum nl80211_tdls_operation oper)
4158{
4159 struct brcmf_if *ifp;
4160 struct brcmf_tdls_iovar_le info;
4161 int ret = 0;
4162
4163 ret = brcmf_convert_nl80211_tdls_oper(oper);
4164 if (ret < 0)
4165 return ret;
4166
4167 ifp = netdev_priv(ndev);
4168 memset(&info, 0, sizeof(info));
4169 info.mode = (u8)ret;
4170 if (peer)
4171 memcpy(info.ea, peer, ETH_ALEN);
4172
4173 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4174 &info, sizeof(info));
4175 if (ret < 0)
4176 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4177
4178 return ret;
4179}
4180
Arend van Spriel5b435de2011-10-05 13:19:03 +02004181static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004182 .add_virtual_intf = brcmf_cfg80211_add_iface,
4183 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004184 .change_virtual_intf = brcmf_cfg80211_change_iface,
4185 .scan = brcmf_cfg80211_scan,
4186 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4187 .join_ibss = brcmf_cfg80211_join_ibss,
4188 .leave_ibss = brcmf_cfg80211_leave_ibss,
4189 .get_station = brcmf_cfg80211_get_station,
4190 .set_tx_power = brcmf_cfg80211_set_tx_power,
4191 .get_tx_power = brcmf_cfg80211_get_tx_power,
4192 .add_key = brcmf_cfg80211_add_key,
4193 .del_key = brcmf_cfg80211_del_key,
4194 .get_key = brcmf_cfg80211_get_key,
4195 .set_default_key = brcmf_cfg80211_config_default_key,
4196 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4197 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004198 .connect = brcmf_cfg80211_connect,
4199 .disconnect = brcmf_cfg80211_disconnect,
4200 .suspend = brcmf_cfg80211_suspend,
4201 .resume = brcmf_cfg80211_resume,
4202 .set_pmksa = brcmf_cfg80211_set_pmksa,
4203 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004204 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004205 .start_ap = brcmf_cfg80211_start_ap,
4206 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004207 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004208 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004209 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4210 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004211 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4212 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4213 .remain_on_channel = brcmf_p2p_remain_on_channel,
4214 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004215 .start_p2p_device = brcmf_p2p_start_device,
4216 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004217 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4218 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004219 .tdls_oper = brcmf_cfg80211_tdls_oper,
Johannes Berge3335472013-08-06 11:13:19 +02004220 CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004221};
4222
Arend van Spriel9f440b72013-02-08 15:53:36 +01004223static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004224{
Arend van Spriel9f440b72013-02-08 15:53:36 +01004225 switch (type) {
4226 case NL80211_IFTYPE_AP_VLAN:
4227 case NL80211_IFTYPE_WDS:
4228 case NL80211_IFTYPE_MONITOR:
4229 case NL80211_IFTYPE_MESH_POINT:
4230 return -ENOTSUPP;
4231 case NL80211_IFTYPE_ADHOC:
4232 return WL_MODE_IBSS;
4233 case NL80211_IFTYPE_STATION:
4234 case NL80211_IFTYPE_P2P_CLIENT:
4235 return WL_MODE_BSS;
4236 case NL80211_IFTYPE_AP:
4237 case NL80211_IFTYPE_P2P_GO:
4238 return WL_MODE_AP;
4239 case NL80211_IFTYPE_P2P_DEVICE:
4240 return WL_MODE_P2P;
4241 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01004243 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004244 }
4245
Arend van Spriel9f440b72013-02-08 15:53:36 +01004246 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004247}
4248
Arend van Spriele5806072012-09-19 22:21:08 +02004249static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4250{
Arend van Spriele5806072012-09-19 22:21:08 +02004251 /* scheduled scan settings */
4252 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4253 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4254 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4255 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004256}
4257
Arend van Spriel9f440b72013-02-08 15:53:36 +01004258static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4259 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004260 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004261 .types = BIT(NL80211_IFTYPE_STATION) |
4262 BIT(NL80211_IFTYPE_ADHOC) |
4263 BIT(NL80211_IFTYPE_AP)
4264 },
4265 {
4266 .max = 1,
4267 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4268 BIT(NL80211_IFTYPE_P2P_GO)
4269 },
Arend van Spriel9af221b2013-05-14 20:52:36 +02004270 {
4271 .max = 1,
4272 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4273 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004274};
4275static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4276 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004277 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004278 .num_different_channels = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004279 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4280 .limits = brcmf_iface_limits
4281 }
4282};
4283
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004284static const struct ieee80211_txrx_stypes
4285brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4286 [NL80211_IFTYPE_STATION] = {
4287 .tx = 0xffff,
4288 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4289 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4290 },
4291 [NL80211_IFTYPE_P2P_CLIENT] = {
4292 .tx = 0xffff,
4293 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4294 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4295 },
4296 [NL80211_IFTYPE_P2P_GO] = {
4297 .tx = 0xffff,
4298 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4299 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4300 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4301 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4302 BIT(IEEE80211_STYPE_AUTH >> 4) |
4303 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4304 BIT(IEEE80211_STYPE_ACTION >> 4)
Arend van Sprielbffc61c2013-04-05 10:57:52 +02004305 },
4306 [NL80211_IFTYPE_P2P_DEVICE] = {
4307 .tx = 0xffff,
4308 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4309 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004310 }
4311};
4312
Arend van Spriel3eacf862012-10-22 13:55:30 -07004313static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004314{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004315 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004316 s32 err = 0;
4317
Arend van Spriel3eacf862012-10-22 13:55:30 -07004318 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4319 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004320 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004321 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004322 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004323 set_wiphy_dev(wiphy, phydev);
4324 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004325 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004326 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4327 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4328 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004329 BIT(NL80211_IFTYPE_AP) |
4330 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Arend van Spriel9af221b2013-05-14 20:52:36 +02004331 BIT(NL80211_IFTYPE_P2P_GO) |
4332 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004333 wiphy->iface_combinations = brcmf_iface_combos;
4334 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004335 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004336 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4337 wiphy->cipher_suites = __wl_cipher_suites;
4338 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004339 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004340 WIPHY_FLAG_OFFCHAN_TX |
Arend van Spriel89c2f382013-08-10 12:27:25 +02004341 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4342 WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004343 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4344 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004345 brcmf_wiphy_pno_params(wiphy);
Hante Meulemand48200b2013-04-03 12:40:29 +02004346 brcmf_dbg(INFO, "Registering custom regulatory\n");
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +01004347 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Hante Meulemand48200b2013-04-03 12:40:29 +02004348 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004349 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004350 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004351 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004352 wiphy_free(wiphy);
4353 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004354 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004355 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004356}
4357
Arend van Spriel3eacf862012-10-22 13:55:30 -07004358struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004359 enum nl80211_iftype type,
4360 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004361{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004362 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004363
Arend van Spriel33a6b152013-02-08 15:53:39 +01004364 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004365 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004366 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4367 if (!vif)
4368 return ERR_PTR(-ENOMEM);
4369
4370 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004371 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004372
Arend van Spriel9f440b72013-02-08 15:53:36 +01004373 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004374 vif->pm_block = pm_block;
4375 vif->roam_off = -1;
4376
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004377 brcmf_init_prof(&vif->profile);
4378
Arend van Spriel3eacf862012-10-22 13:55:30 -07004379 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004380 return vif;
4381}
4382
Arend van Spriel427dec52014-01-06 12:40:47 +01004383void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004384{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004385 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004386 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004387}
4388
Arend van Spriel9df4d542014-01-06 12:40:49 +01004389void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4390{
4391 struct brcmf_cfg80211_vif *vif;
4392 struct brcmf_if *ifp;
4393
4394 ifp = netdev_priv(ndev);
4395 vif = ifp->vif;
4396
4397 brcmf_free_vif(vif);
4398 free_netdev(ndev);
4399}
4400
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004401static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004402{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004403 u32 event = e->event_code;
4404 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004405
4406 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004407 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004408 return true;
4409 }
4410
4411 return false;
4412}
4413
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004414static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004415{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004416 u32 event = e->event_code;
4417 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004418
4419 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004420 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004421 return true;
4422 }
4423 return false;
4424}
4425
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004426static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004427 const struct brcmf_event_msg *e)
4428{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004429 u32 event = e->event_code;
4430 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004431
4432 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004433 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4434 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004435 return true;
4436 }
4437
4438 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004439 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004440 return true;
4441 }
4442
4443 return false;
4444}
4445
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004446static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004447{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004448 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004449
4450 kfree(conn_info->req_ie);
4451 conn_info->req_ie = NULL;
4452 conn_info->req_ie_len = 0;
4453 kfree(conn_info->resp_ie);
4454 conn_info->resp_ie = NULL;
4455 conn_info->resp_ie_len = 0;
4456}
4457
Hante Meuleman89286dc2013-02-08 15:53:46 +01004458static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4459 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004460{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004461 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004462 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004463 u32 req_len;
4464 u32 resp_len;
4465 s32 err = 0;
4466
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004467 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004468
Arend van Sprielac24be62012-10-22 10:36:23 -07004469 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4470 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004471 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004472 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004473 return err;
4474 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004475 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004476 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004477 req_len = le32_to_cpu(assoc_info->req_len);
4478 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004479 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004480 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004481 cfg->extra_buf,
4482 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004483 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004484 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004485 return err;
4486 }
4487 conn_info->req_ie_len = req_len;
4488 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004489 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004490 GFP_KERNEL);
4491 } else {
4492 conn_info->req_ie_len = 0;
4493 conn_info->req_ie = NULL;
4494 }
4495 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004496 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004497 cfg->extra_buf,
4498 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004499 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004500 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004501 return err;
4502 }
4503 conn_info->resp_ie_len = resp_len;
4504 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004505 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004506 GFP_KERNEL);
4507 } else {
4508 conn_info->resp_ie_len = 0;
4509 conn_info->resp_ie = NULL;
4510 }
Arend van Spriel16886732012-12-05 15:26:04 +01004511 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4512 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004513
4514 return err;
4515}
4516
4517static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004518brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004519 struct net_device *ndev,
4520 const struct brcmf_event_msg *e)
4521{
Arend van Sprielc1179032012-10-22 13:55:33 -07004522 struct brcmf_if *ifp = netdev_priv(ndev);
4523 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004524 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4525 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004526 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004527 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004528 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004529 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004530 u32 freq;
4531 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004532 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004533
Arend van Sprield96b8012012-12-05 15:26:02 +01004534 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004535
Hante Meuleman89286dc2013-02-08 15:53:46 +01004536 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004537 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004538 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004539
Franky Lina180b832012-10-10 11:13:09 -07004540 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4541 if (buf == NULL) {
4542 err = -ENOMEM;
4543 goto done;
4544 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004545
Franky Lina180b832012-10-10 11:13:09 -07004546 /* data sent to dongle has to be little endian */
4547 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004548 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004549 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004550
4551 if (err)
4552 goto done;
4553
4554 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004555 ch.chspec = le16_to_cpu(bi->chanspec);
4556 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004557
Franky Lin83cf17a2013-04-11 13:28:50 +02004558 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004559 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4560 else
4561 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4562
Franky Lin83cf17a2013-04-11 13:28:50 +02004563 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004564 notify_channel = ieee80211_get_channel(wiphy, freq);
4565
Franky Lina180b832012-10-10 11:13:09 -07004566done:
4567 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004568 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004569 conn_info->req_ie, conn_info->req_ie_len,
4570 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004571 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004572
Arend van Sprielc1179032012-10-22 13:55:33 -07004573 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004574 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004575 return err;
4576}
4577
4578static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004579brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004580 struct net_device *ndev, const struct brcmf_event_msg *e,
4581 bool completed)
4582{
Arend van Sprielc1179032012-10-22 13:55:33 -07004583 struct brcmf_if *ifp = netdev_priv(ndev);
4584 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004585 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004586 s32 err = 0;
4587
Arend van Sprield96b8012012-12-05 15:26:02 +01004588 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004589
Arend van Sprielc1179032012-10-22 13:55:33 -07004590 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4591 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004592 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004593 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004594 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004595 brcmf_update_bss_info(cfg, ifp);
4596 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4597 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004598 }
4599 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004600 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004601 conn_info->req_ie,
4602 conn_info->req_ie_len,
4603 conn_info->resp_ie,
4604 conn_info->resp_ie_len,
4605 completed ? WLAN_STATUS_SUCCESS :
4606 WLAN_STATUS_AUTH_TIMEOUT,
4607 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004608 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4609 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004610 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004611 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004612 return err;
4613}
4614
4615static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004616brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004617 struct net_device *ndev,
4618 const struct brcmf_event_msg *e, void *data)
4619{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004620 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004621 u32 event = e->event_code;
4622 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004623 struct station_info sinfo;
4624
Arend van Spriel16886732012-12-05 15:26:04 +01004625 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004626 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4627 ndev != cfg_to_ndev(cfg)) {
4628 brcmf_dbg(CONN, "AP mode link down\n");
4629 complete(&cfg->vif_disabled);
4630 return 0;
4631 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004632
Hante Meuleman1a873342012-09-27 14:17:54 +02004633 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004634 (reason == BRCMF_E_STATUS_SUCCESS)) {
4635 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004636 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4637 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004638 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004639 return -EINVAL;
4640 }
4641 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004642 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004643 generation++;
4644 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004645 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004646 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4647 (event == BRCMF_E_DEAUTH_IND) ||
4648 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004649 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004650 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004651 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004652}
4653
4654static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004655brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004656 const struct brcmf_event_msg *e, void *data)
4657{
Arend van Spriel19937322012-11-05 16:22:32 -08004658 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4659 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004660 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004661 s32 err = 0;
4662
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004663 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004664 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004665 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004666 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004667 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004668 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004669 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004670 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004671 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4672 &ifp->vif->sme_state);
4673 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4674 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004675 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004676 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004677 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004678 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004679 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004680 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004681 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004682 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004683 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004684 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004685 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004686 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004687 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004688 if (ndev != cfg_to_ndev(cfg))
4689 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004690 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004691 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004692 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4693 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004694 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004695 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004696 }
4697
4698 return err;
4699}
4700
4701static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004702brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004703 const struct brcmf_event_msg *e, void *data)
4704{
Arend van Spriel19937322012-11-05 16:22:32 -08004705 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004706 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004707 u32 event = e->event_code;
4708 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004709
4710 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004711 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004712 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004713 else
Arend van Spriel19937322012-11-05 16:22:32 -08004714 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004715 }
4716
4717 return err;
4718}
4719
4720static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004721brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004722 const struct brcmf_event_msg *e, void *data)
4723{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004724 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004725 enum nl80211_key_type key_type;
4726
4727 if (flags & BRCMF_EVENT_MSG_GROUP)
4728 key_type = NL80211_KEYTYPE_GROUP;
4729 else
4730 key_type = NL80211_KEYTYPE_PAIRWISE;
4731
Arend van Spriel19937322012-11-05 16:22:32 -08004732 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004733 NULL, GFP_KERNEL);
4734
4735 return 0;
4736}
4737
Arend van Sprield3c0b632013-02-08 15:53:37 +01004738static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4739 const struct brcmf_event_msg *e, void *data)
4740{
4741 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4742 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4743 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4744 struct brcmf_cfg80211_vif *vif;
4745
4746 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4747 ifevent->action, ifevent->flags, ifevent->ifidx,
4748 ifevent->bssidx);
4749
Arend van Sprield3c0b632013-02-08 15:53:37 +01004750 mutex_lock(&event->vif_event_lock);
4751 event->action = ifevent->action;
4752 vif = event->vif;
4753
4754 switch (ifevent->action) {
4755 case BRCMF_E_IF_ADD:
4756 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004757 if (!cfg->vif_event.vif) {
4758 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004759 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004760 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004761
4762 ifp->vif = vif;
4763 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02004764 if (ifp->ndev) {
4765 vif->wdev.netdev = ifp->ndev;
4766 ifp->ndev->ieee80211_ptr = &vif->wdev;
4767 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4768 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004769 mutex_unlock(&event->vif_event_lock);
4770 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004771 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004772
4773 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01004774 mutex_unlock(&event->vif_event_lock);
4775 /* event may not be upon user request */
4776 if (brcmf_cfg80211_vif_event_armed(cfg))
4777 wake_up(&event->vif_wq);
4778 return 0;
4779
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004780 case BRCMF_E_IF_CHANGE:
4781 mutex_unlock(&event->vif_event_lock);
4782 wake_up(&event->vif_wq);
4783 return 0;
4784
Arend van Sprield3c0b632013-02-08 15:53:37 +01004785 default:
4786 mutex_unlock(&event->vif_event_lock);
4787 break;
4788 }
4789 return -EINVAL;
4790}
4791
Arend van Spriel5b435de2011-10-05 13:19:03 +02004792static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4793{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004794 conf->frag_threshold = (u32)-1;
4795 conf->rts_threshold = (u32)-1;
4796 conf->retry_short = (u32)-1;
4797 conf->retry_long = (u32)-1;
4798 conf->tx_power = -1;
4799}
4800
Arend van Spriel5c36b992012-11-14 18:46:05 -08004801static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004802{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004803 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4804 brcmf_notify_connect_status);
4805 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4806 brcmf_notify_connect_status);
4807 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4808 brcmf_notify_connect_status);
4809 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4810 brcmf_notify_connect_status);
4811 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4812 brcmf_notify_connect_status);
4813 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4814 brcmf_notify_connect_status);
4815 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4816 brcmf_notify_roaming_status);
4817 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4818 brcmf_notify_mic_status);
4819 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4820 brcmf_notify_connect_status);
4821 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4822 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004823 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4824 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004825 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004826 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004827 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4828 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004829 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4830 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004831 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4832 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004833 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4834 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004835}
4836
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004837static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004838{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004839 kfree(cfg->conf);
4840 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004841 kfree(cfg->escan_ioctl_buf);
4842 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004843 kfree(cfg->extra_buf);
4844 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004845 kfree(cfg->pmk_list);
4846 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004847}
4848
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004849static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004850{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004851 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4852 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004853 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004854 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4855 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004856 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004857 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4858 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004859 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004860 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4861 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004862 goto init_priv_mem_out;
4863
4864 return 0;
4865
4866init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004867 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004868
4869 return -ENOMEM;
4870}
4871
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004872static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004873{
4874 s32 err = 0;
4875
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004876 cfg->scan_request = NULL;
4877 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004878 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004879 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004880 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004881 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004882 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004883 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004884 if (err)
4885 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004886 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004887 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004888 brcmf_init_escan(cfg);
4889 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004890 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004891 return err;
4892}
4893
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004894static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004895{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004896 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004897 brcmf_abort_scanning(cfg);
4898 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004899}
4900
Arend van Sprield3c0b632013-02-08 15:53:37 +01004901static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4902{
4903 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004904 mutex_init(&event->vif_event_lock);
4905}
4906
Arend van Sprield9cb2592012-12-05 15:25:54 +01004907struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4908 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004909{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004910 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004911 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004912 struct wiphy *wiphy;
4913 struct brcmf_cfg80211_vif *vif;
4914 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004915 s32 err = 0;
Franky Lin83cf17a2013-04-11 13:28:50 +02004916 s32 io_type;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004917
4918 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004919 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004920 return NULL;
4921 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004922
Arend van Spriel3eacf862012-10-22 13:55:30 -07004923 ifp = netdev_priv(ndev);
4924 wiphy = brcmf_setup_wiphy(busdev);
4925 if (IS_ERR(wiphy))
4926 return NULL;
4927
4928 cfg = wiphy_priv(wiphy);
4929 cfg->wiphy = wiphy;
4930 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004931 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004932 INIT_LIST_HEAD(&cfg->vif_list);
4933
Arend van Sprield3c0b632013-02-08 15:53:37 +01004934 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004935 if (IS_ERR(vif)) {
4936 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004937 return NULL;
4938 }
4939
Arend van Sprield3c0b632013-02-08 15:53:37 +01004940 vif->ifp = ifp;
4941 vif->wdev.netdev = ndev;
4942 ndev->ieee80211_ptr = &vif->wdev;
4943 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4944
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004945 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004946 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004947 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004948 goto cfg80211_attach_out;
4949 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004950 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004951
4952 err = brcmf_p2p_attach(cfg);
4953 if (err) {
4954 brcmf_err("P2P initilisation failed (%d)\n", err);
4955 goto cfg80211_p2p_attach_out;
4956 }
Piotr Haber61730d42013-04-23 12:53:12 +02004957 err = brcmf_btcoex_attach(cfg);
4958 if (err) {
4959 brcmf_err("BT-coex initialisation failed (%d)\n", err);
4960 brcmf_p2p_detach(&cfg->p2p);
4961 goto cfg80211_p2p_attach_out;
4962 }
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004963
Arend van Spriel89c2f382013-08-10 12:27:25 +02004964 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
4965 if (err) {
4966 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
4967 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
4968 }
4969
Franky Lin83cf17a2013-04-11 13:28:50 +02004970 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
4971 &io_type);
4972 if (err) {
4973 brcmf_err("Failed to get D11 version (%d)\n", err);
4974 goto cfg80211_p2p_attach_out;
4975 }
4976 cfg->d11inf.io_type = (u8)io_type;
4977 brcmu_d11_attach(&cfg->d11inf);
4978
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004979 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004980
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004981cfg80211_p2p_attach_out:
4982 wl_deinit_priv(cfg);
4983
Arend van Spriel5b435de2011-10-05 13:19:03 +02004984cfg80211_attach_out:
Arend van Spriel427dec52014-01-06 12:40:47 +01004985 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004986 return NULL;
4987}
4988
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004989void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004990{
Arend van Spriele1479952014-01-06 12:40:48 +01004991 if (!cfg)
4992 return;
4993
Arend van Spriel427dec52014-01-06 12:40:47 +01004994 WARN_ON(!list_empty(&cfg->vif_list));
4995 wiphy_unregister(cfg->wiphy);
Piotr Haber61730d42013-04-23 12:53:12 +02004996 brcmf_btcoex_detach(cfg);
Arend van Spriel427dec52014-01-06 12:40:47 +01004997 wl_deinit_priv(cfg);
4998 wiphy_free(cfg->wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004999}
5000
Arend van Spriel5b435de2011-10-05 13:19:03 +02005001static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005002brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005003{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005004 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005005 __le32 roamtrigger[2];
5006 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005007
5008 /*
5009 * Setup timeout if Beacons are lost and roam is
5010 * off to report link down
5011 */
5012 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005013 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005014 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005015 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005016 goto dongle_rom_out;
5017 }
5018 }
5019
5020 /*
5021 * Enable/Disable built-in roaming to allow supplicant
5022 * to take care of roaming
5023 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005024 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07005025 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005026 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005027 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005028 goto dongle_rom_out;
5029 }
5030
Arend van Sprielf588bc02011-10-12 20:51:22 +02005031 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5032 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005033 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005034 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005035 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005036 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005037 goto dongle_rom_out;
5038 }
5039
Arend van Sprielf588bc02011-10-12 20:51:22 +02005040 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5041 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005042 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005043 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005044 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005045 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005046 goto dongle_rom_out;
5047 }
5048
5049dongle_rom_out:
5050 return err;
5051}
5052
5053static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005054brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005055 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005056{
5057 s32 err = 0;
5058
Arend van Sprielac24be62012-10-22 10:36:23 -07005059 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005060 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005061 if (err) {
5062 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005063 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005064 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005065 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005066 goto dongle_scantime_out;
5067 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005068 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005069 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005070 if (err) {
5071 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005072 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005073 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005074 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005075 goto dongle_scantime_out;
5076 }
5077
Arend van Sprielac24be62012-10-22 10:36:23 -07005078 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005079 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005080 if (err) {
5081 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005082 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005083 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005084 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005085 goto dongle_scantime_out;
5086 }
5087
5088dongle_scantime_out:
5089 return err;
5090}
5091
Hante Meulemand48200b2013-04-03 12:40:29 +02005092
Arend van Spriel2375d972014-01-06 12:40:41 +01005093static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
5094 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005095{
5096 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5097 struct ieee80211_channel *band_chan_arr;
5098 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005099 struct brcmu_chan ch;
Hante Meulemand48200b2013-04-03 12:40:29 +02005100 s32 err;
5101 u8 *pbuf;
5102 u32 i, j;
5103 u32 total;
Hante Meulemand48200b2013-04-03 12:40:29 +02005104 enum ieee80211_band band;
5105 u32 channel;
5106 u32 *n_cnt;
Hante Meulemand48200b2013-04-03 12:40:29 +02005107 u32 index;
5108 u32 ht40_flag;
5109 bool update;
5110 u32 array_size;
5111
5112 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5113
5114 if (pbuf == NULL)
5115 return -ENOMEM;
5116
5117 list = (struct brcmf_chanspec_list *)pbuf;
5118
5119 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5120 BRCMF_DCMD_MEDLEN);
5121 if (err) {
5122 brcmf_err("get chanspecs error (%d)\n", err);
5123 goto exit;
5124 }
5125
5126 __wl_band_2ghz.n_channels = 0;
5127 __wl_band_5ghz_a.n_channels = 0;
5128
5129 total = le32_to_cpu(list->count);
5130 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005131 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5132 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005133
Franky Lin83cf17a2013-04-11 13:28:50 +02005134 if (ch.band == BRCMU_CHAN_BAND_2G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005135 band_chan_arr = __wl_2ghz_channels;
5136 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5137 n_cnt = &__wl_band_2ghz.n_channels;
5138 band = IEEE80211_BAND_2GHZ;
Franky Lin83cf17a2013-04-11 13:28:50 +02005139 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005140 band_chan_arr = __wl_5ghz_a_channels;
5141 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
5142 n_cnt = &__wl_band_5ghz_a.n_channels;
5143 band = IEEE80211_BAND_5GHZ;
Hante Meulemand48200b2013-04-03 12:40:29 +02005144 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005145 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005146 continue;
5147 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005148 if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
5149 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005150 continue;
5151 update = false;
5152 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005153 if (band_chan_arr[j].hw_value == ch.chnum) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005154 update = true;
5155 break;
5156 }
5157 }
5158 if (update)
5159 index = j;
5160 else
5161 index = *n_cnt;
5162 if (index < array_size) {
5163 band_chan_arr[index].center_freq =
Franky Lin83cf17a2013-04-11 13:28:50 +02005164 ieee80211_channel_to_frequency(ch.chnum, band);
5165 band_chan_arr[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005166
Arend van Spriel2375d972014-01-06 12:40:41 +01005167 brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
5168 ch.chnum, band_chan_arr[index].center_freq,
5169 ch.bw, ch.sb);
5170 if (ch.bw == BRCMU_CHAN_BW_40) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005171 /* assuming the order is HT20, HT40 Upper,
5172 * HT40 lower from chanspecs
5173 */
5174 ht40_flag = band_chan_arr[index].flags &
5175 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005176 if (ch.sb == BRCMU_CHAN_SB_U) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005177 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5178 band_chan_arr[index].flags &=
5179 ~IEEE80211_CHAN_NO_HT40;
5180 band_chan_arr[index].flags |=
5181 IEEE80211_CHAN_NO_HT40PLUS;
5182 } else {
5183 /* It should be one of
5184 * IEEE80211_CHAN_NO_HT40 or
5185 * IEEE80211_CHAN_NO_HT40PLUS
5186 */
5187 band_chan_arr[index].flags &=
5188 ~IEEE80211_CHAN_NO_HT40;
5189 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5190 band_chan_arr[index].flags |=
5191 IEEE80211_CHAN_NO_HT40MINUS;
5192 }
5193 } else {
5194 band_chan_arr[index].flags =
5195 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005196 ch.bw = BRCMU_CHAN_BW_20;
5197 cfg->d11inf.encchspec(&ch);
5198 channel = ch.chspec;
Hante Meulemand48200b2013-04-03 12:40:29 +02005199 err = brcmf_fil_bsscfg_int_get(ifp,
5200 "per_chan_info",
5201 &channel);
5202 if (!err) {
5203 if (channel & WL_CHAN_RADAR)
5204 band_chan_arr[index].flags |=
5205 (IEEE80211_CHAN_RADAR |
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005206 IEEE80211_CHAN_NO_IR);
Hante Meulemand48200b2013-04-03 12:40:29 +02005207 if (channel & WL_CHAN_PASSIVE)
5208 band_chan_arr[index].flags |=
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005209 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005210 }
5211 }
5212 if (!update)
5213 (*n_cnt)++;
5214 }
5215 }
5216exit:
5217 kfree(pbuf);
5218 return err;
5219}
5220
Arend van Spriel2375d972014-01-06 12:40:41 +01005221static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5222{
5223 u32 band, mimo_bwcap;
5224 int err;
5225
5226 band = WLC_BAND_2G;
5227 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5228 if (!err) {
5229 bw_cap[IEEE80211_BAND_2GHZ] = band;
5230 band = WLC_BAND_5G;
5231 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5232 if (!err) {
5233 bw_cap[IEEE80211_BAND_5GHZ] = band;
5234 return;
5235 }
5236 WARN_ON(1);
5237 return;
5238 }
5239 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5240 mimo_bwcap = 0;
5241 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5242 if (err)
5243 /* assume 20MHz if firmware does not give a clue */
5244 mimo_bwcap = WLC_N_BW_20ALL;
5245
5246 switch (mimo_bwcap) {
5247 case WLC_N_BW_40ALL:
5248 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5249 /* fall-thru */
5250 case WLC_N_BW_20IN2G_40IN5G:
5251 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5252 /* fall-thru */
5253 case WLC_N_BW_20ALL:
5254 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5255 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5256 break;
5257 default:
5258 brcmf_err("invalid mimo_bw_cap value\n");
5259 }
5260}
Hante Meulemand48200b2013-04-03 12:40:29 +02005261
5262static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263{
Arend van Sprielac24be62012-10-22 10:36:23 -07005264 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005265 struct wiphy *wiphy;
5266 s32 phy_list;
Hante Meulemand48200b2013-04-03 12:40:29 +02005267 u32 band_list[3];
5268 u32 nmode;
Arend van Spriel2375d972014-01-06 12:40:41 +01005269 u32 bw_cap[2] = { 0, 0 };
Arend van Spriel5b435de2011-10-05 13:19:03 +02005270 s8 phy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005271 s32 err;
5272 u32 nband;
5273 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005274 struct ieee80211_supported_band *bands[2] = { NULL, NULL };
5275 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005276
Hante Meulemanb87e2c42012-11-14 18:46:23 -08005277 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005278 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005279 if (err) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005280 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005281 return err;
5282 }
5283
Hante Meuleman3ba81372012-09-19 22:21:13 +02005284 phy = ((char *)&phy_list)[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005285 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5286
5287
5288 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5289 &band_list, sizeof(band_list));
5290 if (err) {
5291 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5292 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005294 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5295 band_list[0], band_list[1], band_list[2]);
5296
5297 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5298 if (err) {
5299 brcmf_err("nmode error (%d)\n", err);
5300 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005301 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005302 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005303 brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
5304 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005305
5306 err = brcmf_construct_reginfo(cfg, bw_cap);
5307 if (err) {
5308 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5309 return err;
5310 }
5311
5312 nband = band_list[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005313
5314 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
Arend van Spriel2375d972014-01-06 12:40:41 +01005315 band = NULL;
Hante Meulemand48200b2013-04-03 12:40:29 +02005316 if ((band_list[i] == WLC_BAND_5G) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005317 (__wl_band_5ghz_a.n_channels > 0))
5318 band = &__wl_band_5ghz_a;
5319 else if ((band_list[i] == WLC_BAND_2G) &&
5320 (__wl_band_2ghz.n_channels > 0))
5321 band = &__wl_band_2ghz;
5322 else
5323 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005324
Arend van Spriel2375d972014-01-06 12:40:41 +01005325 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5326 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5327 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Hante Meulemand48200b2013-04-03 12:40:29 +02005328 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005329 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5330 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5331 band->ht_cap.ht_supported = true;
5332 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5333 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5334 /* An HT shall support all EQM rates for one spatial
5335 * stream
5336 */
5337 band->ht_cap.mcs.rx_mask[0] = 0xff;
5338 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5339 bands[band->band] = band;
Hante Meulemand48200b2013-04-03 12:40:29 +02005340 }
5341
5342 wiphy = cfg_to_wiphy(cfg);
5343 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5344 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5345 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005346
5347 return err;
5348}
5349
Hante Meulemand48200b2013-04-03 12:40:29 +02005350
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005351static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005352{
Hante Meulemand48200b2013-04-03 12:40:29 +02005353 return brcmf_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005354}
5355
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005356static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005357{
5358 struct net_device *ndev;
5359 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01005360 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005361 s32 power_mode;
5362 s32 err = 0;
5363
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005364 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005365 return err;
5366
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005367 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01005369 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005370
Hante Meuleman40a23292013-01-02 15:22:51 +01005371 /* make sure RF is ready for work */
5372 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5373
5374 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5375 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005376
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005377 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01005378 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005379 if (err)
5380 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005381 brcmf_dbg(INFO, "power save set to %s\n",
5382 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005383
Hante Meuleman40a23292013-01-02 15:22:51 +01005384 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005385 if (err)
5386 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005387 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5388 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01005389 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005391 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005392 if (err)
5393 goto default_conf_out;
5394
Hante Meulemanb3657452013-05-27 21:09:53 +02005395 brcmf_configure_arp_offload(ifp, true);
5396
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005397 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005398default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005399
5400 return err;
5401
5402}
5403
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005404static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005405{
Arend van Sprielc1179032012-10-22 13:55:33 -07005406 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005407
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005408 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005409}
5410
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005411static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005412{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005413 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005414
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415 /*
5416 * While going down, if associated with AP disassociate
5417 * from AP to save power
5418 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005419 if (check_vif_up(ifp->vif)) {
5420 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005421
5422 /* Make sure WPA_Supplicant receives all the event
5423 generated due to DISASSOC call to the fw to keep
5424 the state fw and WPA_Supplicant state consistent
5425 */
5426 brcmf_delay(500);
5427 }
5428
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005429 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005430 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005431
Arend van Spriel5b435de2011-10-05 13:19:03 +02005432 return 0;
5433}
5434
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005435s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005436{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005437 struct brcmf_if *ifp = netdev_priv(ndev);
5438 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 s32 err = 0;
5440
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005441 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005442 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005443 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005444
5445 return err;
5446}
5447
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005448s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005450 struct brcmf_if *ifp = netdev_priv(ndev);
5451 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005452 s32 err = 0;
5453
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005454 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005455 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005456 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005457
5458 return err;
5459}
5460
Arend van Spriela7965fb2013-04-11 17:08:37 +02005461enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5462{
5463 struct wireless_dev *wdev = &ifp->vif->wdev;
5464
5465 return wdev->iftype;
5466}
5467
Arend van Spriel9f440b72013-02-08 15:53:36 +01005468u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5469{
5470 struct brcmf_cfg80211_vif *vif;
5471 bool result = 0;
5472
5473 list_for_each_entry(vif, &cfg->vif_list, list) {
5474 if (test_bit(state, &vif->sme_state))
5475 result++;
5476 }
5477 return result;
5478}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005479
5480static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5481 u8 action)
5482{
5483 u8 evt_action;
5484
5485 mutex_lock(&event->vif_event_lock);
5486 evt_action = event->action;
5487 mutex_unlock(&event->vif_event_lock);
5488 return evt_action == action;
5489}
5490
5491void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5492 struct brcmf_cfg80211_vif *vif)
5493{
5494 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5495
5496 mutex_lock(&event->vif_event_lock);
5497 event->vif = vif;
5498 event->action = 0;
5499 mutex_unlock(&event->vif_event_lock);
5500}
5501
5502bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5503{
5504 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5505 bool armed;
5506
5507 mutex_lock(&event->vif_event_lock);
5508 armed = event->vif != NULL;
5509 mutex_unlock(&event->vif_event_lock);
5510
5511 return armed;
5512}
5513int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5514 u8 action, ulong timeout)
5515{
5516 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5517
5518 return wait_event_timeout(event->vif_wq,
5519 vif_event_equals(event, action), timeout);
5520}
5521