blob: 0c29bf61bb82cb7f17e372def131636c6a0e7072 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Franky Lin1bacb042014-06-21 12:11:16 +020022#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020024#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
Hante Meuleman122d3d02014-10-28 14:56:18 +010029#include "core.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010030#include "debug.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020031#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010032#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010033#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020034#include "btcoex.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010035#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020036#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070037#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020038#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020039#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010040#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010041#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
Arend van Spriele5806072012-09-19 22:21:08 +020043#define BRCMF_SCAN_IE_LEN_MAX 2048
44#define BRCMF_PNO_VERSION 2
45#define BRCMF_PNO_TIME 30
46#define BRCMF_PNO_REPEAT 4
47#define BRCMF_PNO_FREQ_EXPO_MAX 3
48#define BRCMF_PNO_MAX_PFN_COUNT 16
49#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
50#define BRCMF_PNO_HIDDEN_BIT 2
51#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
52#define BRCMF_PNO_SCAN_COMPLETE 1
53#define BRCMF_PNO_SCAN_INCOMPLETE 0
54
Hante Meuleman1a873342012-09-27 14:17:54 +020055#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
56#define WPA_OUI_TYPE 1
57#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
58#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010059#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020060
61#define VS_IE_FIXED_HDR_LEN 6
62#define WPA_IE_VERSION_LEN 2
63#define WPA_IE_MIN_OUI_LEN 4
64#define WPA_IE_SUITE_COUNT_LEN 2
65
66#define WPA_CIPHER_NONE 0 /* None */
67#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
68#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
69#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
70#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
71
72#define RSN_AKM_NONE 0 /* None (IBSS) */
73#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
74#define RSN_AKM_PSK 2 /* Pre-shared Key */
75#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
76#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
77
78#define VNDR_IE_CMD_LEN 4 /* length of the set command
79 * string :"add", "del" (+ NUL)
80 */
81#define VNDR_IE_COUNT_OFFSET 4
82#define VNDR_IE_PKTFLAG_OFFSET 8
83#define VNDR_IE_VSIE_OFFSET 12
84#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010085#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020086
87#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
88#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020089
Hante Meuleman89286dc2013-02-08 15:53:46 +010090#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
91#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
92#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
93
Arend van Spriel5b435de2011-10-05 13:19:03 +020094#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
95 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
96
Arend van Sprielce81e312012-10-22 13:55:37 -070097static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020098{
Arend van Sprielc1179032012-10-22 13:55:33 -070099 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100100 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
101 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200102 return false;
103 }
104 return true;
105}
106
Arend van Spriel5b435de2011-10-05 13:19:03 +0200107#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
108#define RATETAB_ENT(_rateid, _flags) \
109 { \
110 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
111 .hw_value = (_rateid), \
112 .flags = (_flags), \
113 }
114
115static struct ieee80211_rate __wl_rates[] = {
116 RATETAB_ENT(BRCM_RATE_1M, 0),
117 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
118 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
119 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
120 RATETAB_ENT(BRCM_RATE_6M, 0),
121 RATETAB_ENT(BRCM_RATE_9M, 0),
122 RATETAB_ENT(BRCM_RATE_12M, 0),
123 RATETAB_ENT(BRCM_RATE_18M, 0),
124 RATETAB_ENT(BRCM_RATE_24M, 0),
125 RATETAB_ENT(BRCM_RATE_36M, 0),
126 RATETAB_ENT(BRCM_RATE_48M, 0),
127 RATETAB_ENT(BRCM_RATE_54M, 0),
128};
129
Arend van Spriel5b435de2011-10-05 13:19:03 +0200130#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200131#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
132#define wl_a_rates (__wl_rates + 4)
133#define wl_a_rates_size (wl_g_rates_size - 4)
134
135#define CHAN2G(_channel, _freq) { \
136 .band = IEEE80211_BAND_2GHZ, \
137 .center_freq = (_freq), \
138 .hw_value = (_channel), \
139 .flags = IEEE80211_CHAN_DISABLED, \
140 .max_antenna_gain = 0, \
141 .max_power = 30, \
142}
143
144#define CHAN5G(_channel) { \
145 .band = IEEE80211_BAND_5GHZ, \
146 .center_freq = 5000 + (5 * (_channel)), \
147 .hw_value = (_channel), \
148 .flags = IEEE80211_CHAN_DISABLED, \
149 .max_antenna_gain = 0, \
150 .max_power = 30, \
151}
152
153static struct ieee80211_channel __wl_2ghz_channels[] = {
154 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
155 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
156 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
157 CHAN2G(13, 2472), CHAN2G(14, 2484)
158};
159
160static struct ieee80211_channel __wl_5ghz_channels[] = {
161 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
162 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
163 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
164 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
165 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
166 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
167};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200168
Arend van Sprielb48d8912014-07-12 08:49:41 +0200169/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200170 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200171 */
172static const struct ieee80211_supported_band __wl_band_2ghz = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200173 .band = IEEE80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200174 .bitrates = wl_g_rates,
175 .n_bitrates = wl_g_rates_size,
176};
177
Arend van Spriel58de92d2015-04-14 20:10:24 +0200178static const struct ieee80211_supported_band __wl_band_5ghz = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200179 .band = IEEE80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180 .bitrates = wl_a_rates,
181 .n_bitrates = wl_a_rates_size,
182};
183
Hante Meulemand48200b2013-04-03 12:40:29 +0200184/* This is to override regulatory domains defined in cfg80211 module (reg.c)
185 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200186 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
187 * With respect to these flags, wpa_supplicant doesn't * start p2p
188 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200189 * domain are to be done here.
190 */
191static const struct ieee80211_regdomain brcmf_regdom = {
192 .n_reg_rules = 4,
193 .alpha2 = "99",
194 .reg_rules = {
195 /* IEEE 802.11b/g, channels 1..11 */
196 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
197 /* If any */
198 /* IEEE 802.11 channel 14 - Only JP enables
199 * this and for 802.11b only
200 */
201 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
202 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200203 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200204 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200205 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200206};
207
208static const u32 __wl_cipher_suites[] = {
209 WLAN_CIPHER_SUITE_WEP40,
210 WLAN_CIPHER_SUITE_WEP104,
211 WLAN_CIPHER_SUITE_TKIP,
212 WLAN_CIPHER_SUITE_CCMP,
213 WLAN_CIPHER_SUITE_AES_CMAC,
214};
215
Hante Meuleman1a873342012-09-27 14:17:54 +0200216/* Vendor specific ie. id = 221, oui and type defines exact ie */
217struct brcmf_vs_tlv {
218 u8 id;
219 u8 len;
220 u8 oui[3];
221 u8 oui_type;
222};
223
224struct parsed_vndr_ie_info {
225 u8 *ie_ptr;
226 u32 ie_len; /* total length including id & length field */
227 struct brcmf_vs_tlv vndrie;
228};
229
230struct parsed_vndr_ies {
231 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100232 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200233};
234
Hante Meuleman68ca3952014-02-25 20:30:26 +0100235static int brcmf_roamoff;
236module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
237MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
238
Alwin Beukersef6ac172011-10-12 20:51:26 +0200239/* Quarter dBm units to mW
240 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
241 * Table is offset so the last entry is largest mW value that fits in
242 * a u16.
243 */
244
245#define QDBM_OFFSET 153 /* Offset for first entry */
246#define QDBM_TABLE_LEN 40 /* Table size */
247
248/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
249 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
250 */
251#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
252
253/* Largest mW value that will round down to the last table entry,
254 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
255 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
256 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
257 */
258#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
259
260static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
261/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
262/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
263/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
264/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
265/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
266/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
267};
268
269static u16 brcmf_qdbm_to_mw(u8 qdbm)
270{
271 uint factor = 1;
272 int idx = qdbm - QDBM_OFFSET;
273
274 if (idx >= QDBM_TABLE_LEN)
275 /* clamp to max u16 mW value */
276 return 0xFFFF;
277
278 /* scale the qdBm index up to the range of the table 0-40
279 * where an offset of 40 qdBm equals a factor of 10 mW.
280 */
281 while (idx < 0) {
282 idx += 40;
283 factor *= 10;
284 }
285
286 /* return the mW value scaled down to the correct factor of 10,
287 * adding in factor/2 to get proper rounding.
288 */
289 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
290}
291
292static u8 brcmf_mw_to_qdbm(u16 mw)
293{
294 u8 qdbm;
295 int offset;
296 uint mw_uint = mw;
297 uint boundary;
298
299 /* handle boundary case */
300 if (mw_uint <= 1)
301 return 0;
302
303 offset = QDBM_OFFSET;
304
305 /* move mw into the range of the table */
306 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
307 mw_uint *= 10;
308 offset -= 40;
309 }
310
311 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
312 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
313 nqdBm_to_mW_map[qdbm]) / 2;
314 if (mw_uint < boundary)
315 break;
316 }
317
318 qdbm += (u8) offset;
319
320 return qdbm;
321}
322
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200323static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
324 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200325{
326 struct brcmu_chan ch_inf;
327 s32 primary_offset;
328
329 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
330 ch->chan->center_freq, ch->center_freq1, ch->width);
331 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
332 primary_offset = ch->center_freq1 - ch->chan->center_freq;
333 switch (ch->width) {
334 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100335 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200336 ch_inf.bw = BRCMU_CHAN_BW_20;
337 WARN_ON(primary_offset != 0);
338 break;
339 case NL80211_CHAN_WIDTH_40:
340 ch_inf.bw = BRCMU_CHAN_BW_40;
341 if (primary_offset < 0)
342 ch_inf.sb = BRCMU_CHAN_SB_U;
343 else
344 ch_inf.sb = BRCMU_CHAN_SB_L;
345 break;
346 case NL80211_CHAN_WIDTH_80:
347 ch_inf.bw = BRCMU_CHAN_BW_80;
348 if (primary_offset < 0) {
349 if (primary_offset < -CH_10MHZ_APART)
350 ch_inf.sb = BRCMU_CHAN_SB_UU;
351 else
352 ch_inf.sb = BRCMU_CHAN_SB_UL;
353 } else {
354 if (primary_offset > CH_10MHZ_APART)
355 ch_inf.sb = BRCMU_CHAN_SB_LL;
356 else
357 ch_inf.sb = BRCMU_CHAN_SB_LU;
358 }
359 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100360 case NL80211_CHAN_WIDTH_80P80:
361 case NL80211_CHAN_WIDTH_160:
362 case NL80211_CHAN_WIDTH_5:
363 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200364 default:
365 WARN_ON_ONCE(1);
366 }
367 switch (ch->chan->band) {
368 case IEEE80211_BAND_2GHZ:
369 ch_inf.band = BRCMU_CHAN_BAND_2G;
370 break;
371 case IEEE80211_BAND_5GHZ:
372 ch_inf.band = BRCMU_CHAN_BAND_5G;
373 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100374 case IEEE80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200375 default:
376 WARN_ON_ONCE(1);
377 }
378 d11inf->encchspec(&ch_inf);
379
380 return ch_inf.chspec;
381}
382
Franky Lin83cf17a2013-04-11 13:28:50 +0200383u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
384 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700385{
Franky Lin83cf17a2013-04-11 13:28:50 +0200386 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700387
Franky Lin83cf17a2013-04-11 13:28:50 +0200388 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
389 ch_inf.bw = BRCMU_CHAN_BW_20;
390 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700391
Franky Lin83cf17a2013-04-11 13:28:50 +0200392 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700393}
394
Hante Meuleman89286dc2013-02-08 15:53:46 +0100395/* Traverse a string of 1-byte tag/1-byte length/variable-length value
396 * triples, returning a pointer to the substring whose first element
397 * matches tag
398 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100399const struct brcmf_tlv *
400brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100401{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100402 const struct brcmf_tlv *elt = buf;
403 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100404
405 /* find tagged parameter */
406 while (totlen >= TLV_HDR_LEN) {
407 int len = elt->len;
408
409 /* validate remaining totlen */
410 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
411 return elt;
412
413 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
414 totlen -= (len + TLV_HDR_LEN);
415 }
416
417 return NULL;
418}
419
420/* Is any of the tlvs the expected entry? If
421 * not update the tlvs buffer pointer/length.
422 */
423static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100424brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
425 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100426{
427 /* If the contents match the OUI and the type */
428 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
429 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
430 type == ie[TLV_BODY_OFF + oui_len]) {
431 return true;
432 }
433
434 if (tlvs == NULL)
435 return false;
436 /* point to the next ie */
437 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
438 /* calculate the length of the rest of the buffer */
439 *tlvs_len -= (int)(ie - *tlvs);
440 /* update the pointer to the start of the buffer */
441 *tlvs = ie;
442
443 return false;
444}
445
446static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100447brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100448{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100449 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100450
451 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100452 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100453 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
454 return (struct brcmf_vs_tlv *)ie;
455 }
456 return NULL;
457}
458
459static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100460brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100461{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100462 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100463
464 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
465 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
466 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
467 return (struct brcmf_vs_tlv *)ie;
468 }
469 return NULL;
470}
471
Arend van Spriel39504a22015-08-20 22:06:05 +0200472static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
473 struct brcmf_cfg80211_vif *vif,
474 enum nl80211_iftype new_type)
475{
476 int iftype_num[NUM_NL80211_IFTYPES];
477 struct brcmf_cfg80211_vif *pos;
478
479 memset(&iftype_num[0], 0, sizeof(iftype_num));
480 list_for_each_entry(pos, &cfg->vif_list, list)
481 if (pos == vif)
482 iftype_num[new_type]++;
483 else
484 iftype_num[pos->wdev.iftype]++;
485
486 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
487}
488
489static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
490 enum nl80211_iftype new_type)
491{
492 int iftype_num[NUM_NL80211_IFTYPES];
493 struct brcmf_cfg80211_vif *pos;
494
495 memset(&iftype_num[0], 0, sizeof(iftype_num));
496 list_for_each_entry(pos, &cfg->vif_list, list)
497 iftype_num[pos->wdev.iftype]++;
498
499 iftype_num[new_type]++;
500 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
501}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100502
Arend van Spriel5b435de2011-10-05 13:19:03 +0200503static void convert_key_from_CPU(struct brcmf_wsec_key *key,
504 struct brcmf_wsec_key_le *key_le)
505{
506 key_le->index = cpu_to_le32(key->index);
507 key_le->len = cpu_to_le32(key->len);
508 key_le->algo = cpu_to_le32(key->algo);
509 key_le->flags = cpu_to_le32(key->flags);
510 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
511 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
512 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
513 memcpy(key_le->data, key->data, sizeof(key->data));
514 memcpy(key_le->ea, key->ea, sizeof(key->ea));
515}
516
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200517static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100518send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200519{
520 int err;
521 struct brcmf_wsec_key_le key_le;
522
523 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200524
Hante Meuleman118eb302014-12-21 12:43:49 +0100525 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700526
Hante Meuleman118eb302014-12-21 12:43:49 +0100527 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700528 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200529
Arend van Spriel5b435de2011-10-05 13:19:03 +0200530 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100531 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200532 return err;
533}
534
Hante Meulemanb3657452013-05-27 21:09:53 +0200535static s32
536brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
537{
538 s32 err;
539 u32 mode;
540
541 if (enable)
542 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
543 else
544 mode = 0;
545
546 /* Try to set and enable ARP offload feature, this may fail, then it */
547 /* is simply not supported and err 0 will be returned */
548 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
549 if (err) {
550 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
551 mode, err);
552 err = 0;
553 } else {
554 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
555 if (err) {
556 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
557 enable, err);
558 err = 0;
559 } else
560 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
561 enable, mode);
562 }
563
564 return err;
565}
566
Hante Meuleman8851cce2014-07-30 13:20:02 +0200567static void
568brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
569{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200570 struct brcmf_cfg80211_vif *vif;
571 struct brcmf_if *ifp;
572
573 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
574 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200575
576 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
577 (wdev->iftype == NL80211_IFTYPE_AP) ||
578 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
579 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
580 ADDR_DIRECT);
581 else
582 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
583 ADDR_INDIRECT);
584}
585
Hante Meulemana44aa402014-12-03 21:05:33 +0100586static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
587{
588 struct brcmf_mbss_ssid_le mbss_ssid_le;
589 int bsscfgidx;
590 int err;
591
592 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
593 bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr);
594 if (bsscfgidx < 0)
595 return bsscfgidx;
596
597 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
598 mbss_ssid_le.SSID_len = cpu_to_le32(5);
599 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
600
601 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
602 sizeof(mbss_ssid_le));
603 if (err < 0)
604 brcmf_err("setting ssid failed %d\n", err);
605
606 return err;
607}
608
609/**
610 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
611 *
612 * @wiphy: wiphy device of new interface.
613 * @name: name of the new interface.
614 * @flags: not used.
615 * @params: contains mac address for AP device.
616 */
617static
618struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
619 u32 *flags, struct vif_params *params)
620{
621 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
622 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
623 struct brcmf_cfg80211_vif *vif;
624 int err;
625
626 if (brcmf_cfg80211_vif_event_armed(cfg))
627 return ERR_PTR(-EBUSY);
628
629 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
630
631 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false);
632 if (IS_ERR(vif))
633 return (struct wireless_dev *)vif;
634
635 brcmf_cfg80211_arm_vif_event(cfg, vif);
636
637 err = brcmf_cfg80211_request_ap_if(ifp);
638 if (err) {
639 brcmf_cfg80211_arm_vif_event(cfg, NULL);
640 goto fail;
641 }
642
643 /* wait for firmware event */
644 err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
645 msecs_to_jiffies(1500));
646 brcmf_cfg80211_arm_vif_event(cfg, NULL);
647 if (!err) {
648 brcmf_err("timeout occurred\n");
649 err = -EIO;
650 goto fail;
651 }
652
653 /* interface created in firmware */
654 ifp = vif->ifp;
655 if (!ifp) {
656 brcmf_err("no if pointer provided\n");
657 err = -ENOENT;
658 goto fail;
659 }
660
661 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
662 err = brcmf_net_attach(ifp, true);
663 if (err) {
664 brcmf_err("Registering netdevice failed\n");
665 goto fail;
666 }
667
668 return &ifp->vif->wdev;
669
670fail:
671 brcmf_free_vif(vif);
672 return ERR_PTR(err);
673}
674
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100675static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
676{
677 enum nl80211_iftype iftype;
678
679 iftype = vif->wdev.iftype;
680 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
681}
682
683static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
684{
685 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
686}
687
Arend van Spriel9f440b72013-02-08 15:53:36 +0100688static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
689 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100690 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100691 enum nl80211_iftype type,
692 u32 *flags,
693 struct vif_params *params)
694{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200695 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200696 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200697
Arend van Spriel9f440b72013-02-08 15:53:36 +0100698 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200699 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
700 if (err) {
701 brcmf_err("iface validation failed: err=%d\n", err);
702 return ERR_PTR(err);
703 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100704 switch (type) {
705 case NL80211_IFTYPE_ADHOC:
706 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100707 case NL80211_IFTYPE_AP_VLAN:
708 case NL80211_IFTYPE_WDS:
709 case NL80211_IFTYPE_MONITOR:
710 case NL80211_IFTYPE_MESH_POINT:
711 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100712 case NL80211_IFTYPE_AP:
713 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
714 if (!IS_ERR(wdev))
715 brcmf_cfg80211_update_proto_addr_mode(wdev);
716 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100717 case NL80211_IFTYPE_P2P_CLIENT:
718 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200719 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100720 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Hante Meuleman8851cce2014-07-30 13:20:02 +0200721 if (!IS_ERR(wdev))
722 brcmf_cfg80211_update_proto_addr_mode(wdev);
723 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100724 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100725 default:
726 return ERR_PTR(-EINVAL);
727 }
728}
729
Daniel Kim5e787f72014-06-21 12:11:18 +0200730static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
731{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200732 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200733 brcmf_set_mpc(ifp, mpc);
734}
735
Arend van Sprielf96aa072013-04-05 10:57:48 +0200736void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100737{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100738 s32 err = 0;
739
740 if (check_vif_up(ifp->vif)) {
741 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
742 if (err) {
743 brcmf_err("fail to set mpc\n");
744 return;
745 }
746 brcmf_dbg(INFO, "MPC : %d\n", mpc);
747 }
748}
749
Arend van Spriela0f472a2013-04-05 10:57:49 +0200750s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
751 struct brcmf_if *ifp, bool aborted,
752 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100753{
754 struct brcmf_scan_params_le params_le;
755 struct cfg80211_scan_request *scan_request;
756 s32 err = 0;
757
758 brcmf_dbg(SCAN, "Enter\n");
759
760 /* clear scan request, because the FW abort can cause a second call */
761 /* to this functon and might cause a double cfg80211_scan_done */
762 scan_request = cfg->scan_request;
763 cfg->scan_request = NULL;
764
765 if (timer_pending(&cfg->escan_timeout))
766 del_timer_sync(&cfg->escan_timeout);
767
768 if (fw_abort) {
769 /* Do a scan abort to stop the driver's scan engine */
770 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
771 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800772 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100773 params_le.bss_type = DOT11_BSSTYPE_ANY;
774 params_le.scan_type = 0;
775 params_le.channel_num = cpu_to_le32(1);
776 params_le.nprobes = cpu_to_le32(1);
777 params_le.active_time = cpu_to_le32(-1);
778 params_le.passive_time = cpu_to_le32(-1);
779 params_le.home_time = cpu_to_le32(-1);
780 /* Scan is aborted by setting channel_list[0] to -1 */
781 params_le.channel_list[0] = cpu_to_le16(-1);
782 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200783 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100784 &params_le, sizeof(params_le));
785 if (err)
786 brcmf_err("Scan abort failed\n");
787 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200788
Daniel Kim5e787f72014-06-21 12:11:18 +0200789 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200790
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100791 /*
792 * e-scan can be initiated by scheduled scan
793 * which takes precedence.
794 */
795 if (cfg->sched_escan) {
796 brcmf_dbg(SCAN, "scheduled scan completed\n");
797 cfg->sched_escan = false;
798 if (!aborted)
799 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100800 } else if (scan_request) {
801 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
802 aborted ? "Aborted" : "Done");
803 cfg80211_scan_done(scan_request, aborted);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100804 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100805 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
806 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100807
808 return err;
809}
810
Arend van Spriel9f440b72013-02-08 15:53:36 +0100811static
812int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
813{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100814 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
815 struct net_device *ndev = wdev->netdev;
816
817 /* vif event pending in firmware */
818 if (brcmf_cfg80211_vif_event_armed(cfg))
819 return -EBUSY;
820
821 if (ndev) {
822 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200823 cfg->escan_info.ifp == netdev_priv(ndev))
824 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
825 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100826
827 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
828 }
829
Arend van Spriel9f440b72013-02-08 15:53:36 +0100830 switch (wdev->iftype) {
831 case NL80211_IFTYPE_ADHOC:
832 case NL80211_IFTYPE_STATION:
833 case NL80211_IFTYPE_AP:
834 case NL80211_IFTYPE_AP_VLAN:
835 case NL80211_IFTYPE_WDS:
836 case NL80211_IFTYPE_MONITOR:
837 case NL80211_IFTYPE_MESH_POINT:
838 return -EOPNOTSUPP;
839 case NL80211_IFTYPE_P2P_CLIENT:
840 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200841 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100842 return brcmf_p2p_del_vif(wiphy, wdev);
843 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100844 default:
845 return -EINVAL;
846 }
847 return -EOPNOTSUPP;
848}
849
Arend van Spriel5b435de2011-10-05 13:19:03 +0200850static s32
851brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
852 enum nl80211_iftype type, u32 *flags,
853 struct vif_params *params)
854{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100855 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700856 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100857 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200858 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200859 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860 s32 err = 0;
861
Arend van Spriel39504a22015-08-20 22:06:05 +0200862 brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type);
863 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
864 if (err) {
865 brcmf_err("iface validation failed: err=%d\n", err);
866 return err;
867 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200868 switch (type) {
869 case NL80211_IFTYPE_MONITOR:
870 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100871 brcmf_err("type (%d) : currently we do not support this type\n",
872 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200873 return -EOPNOTSUPP;
874 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200875 infra = 0;
876 break;
877 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100878 /* Ignore change for p2p IF. Unclear why supplicant does this */
879 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
880 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
881 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
882 /* WAR: It is unexpected to get a change of VIF for P2P
883 * IF, but it happens. The request can not be handled
884 * but returning EPERM causes a crash. Returning 0
885 * without setting ieee80211_ptr->iftype causes trace
886 * (WARN_ON) but it works with wpa_supplicant
887 */
888 return 0;
889 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200890 infra = 1;
891 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200892 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100893 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200894 ap = 1;
895 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200896 default:
897 err = -EINVAL;
898 goto done;
899 }
900
Hante Meuleman1a873342012-09-27 14:17:54 +0200901 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100902 if (type == NL80211_IFTYPE_P2P_GO) {
903 brcmf_dbg(INFO, "IF Type = P2P GO\n");
904 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
905 }
906 if (!err) {
907 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
908 brcmf_dbg(INFO, "IF Type = AP\n");
909 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200910 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100911 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200912 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100913 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200914 err = -EAGAIN;
915 goto done;
916 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100917 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100918 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200919 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200920 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200921
Hante Meuleman8851cce2014-07-30 13:20:02 +0200922 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
923
Arend van Spriel5b435de2011-10-05 13:19:03 +0200924done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100925 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200926
927 return err;
928}
929
Franky Lin83cf17a2013-04-11 13:28:50 +0200930static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
931 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200932 struct cfg80211_scan_request *request)
933{
934 u32 n_ssids;
935 u32 n_channels;
936 s32 i;
937 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200938 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200939 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200940 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200941
Joe Perches93803b32015-03-02 19:54:49 -0800942 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200943 params_le->bss_type = DOT11_BSSTYPE_ANY;
944 params_le->scan_type = 0;
945 params_le->channel_num = 0;
946 params_le->nprobes = cpu_to_le32(-1);
947 params_le->active_time = cpu_to_le32(-1);
948 params_le->passive_time = cpu_to_le32(-1);
949 params_le->home_time = cpu_to_le32(-1);
950 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
951
952 /* if request is null exit so it will be all channel broadcast scan */
953 if (!request)
954 return;
955
956 n_ssids = request->n_ssids;
957 n_channels = request->n_channels;
958 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100959 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
960 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200961 if (n_channels > 0) {
962 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200963 chanspec = channel_to_chanspec(&cfg->d11inf,
964 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100965 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
966 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200967 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200968 }
969 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100970 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200971 }
972 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100973 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200974 if (n_ssids > 0) {
975 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
976 n_channels * sizeof(u16);
977 offset = roundup(offset, sizeof(u32));
978 ptr = (char *)params_le + offset;
979 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200980 memset(&ssid_le, 0, sizeof(ssid_le));
981 ssid_le.SSID_len =
982 cpu_to_le32(request->ssids[i].ssid_len);
983 memcpy(ssid_le.SSID, request->ssids[i].ssid,
984 request->ssids[i].ssid_len);
985 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100986 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200987 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100988 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
989 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200990 memcpy(ptr, &ssid_le, sizeof(ssid_le));
991 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200992 }
993 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100994 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200995 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100996 brcmf_dbg(SCAN, "SSID %s len=%d\n",
997 params_le->ssid_le.SSID,
998 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200999 params_le->ssid_le.SSID_len =
1000 cpu_to_le32(request->ssids->ssid_len);
1001 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1002 request->ssids->ssid_len);
1003 }
1004 }
1005 /* Adding mask to channel numbers */
1006 params_le->channel_num =
1007 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1008 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1009}
1010
1011static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001012brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02001013 struct cfg80211_scan_request *request, u16 action)
1014{
1015 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1016 offsetof(struct brcmf_escan_params_le, params_le);
1017 struct brcmf_escan_params_le *params;
1018 s32 err = 0;
1019
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001020 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001021
1022 if (request != NULL) {
1023 /* Allocate space for populating ssids in struct */
1024 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1025
1026 /* Allocate space for populating ssids in struct */
1027 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
1028 }
1029
1030 params = kzalloc(params_size, GFP_KERNEL);
1031 if (!params) {
1032 err = -ENOMEM;
1033 goto exit;
1034 }
1035 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001036 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001037 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
1038 params->action = cpu_to_le16(action);
1039 params->sync_id = cpu_to_le16(0x1234);
1040
Arend van Spriela0f472a2013-04-05 10:57:49 +02001041 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001042 if (err) {
1043 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001044 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001045 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001046 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001047 }
1048
1049 kfree(params);
1050exit:
1051 return err;
1052}
1053
1054static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001055brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001056 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001057{
1058 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001059 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001060 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001061 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001062
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001063 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001064 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001065 escan->wiphy = wiphy;
1066 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001067 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001068 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001069 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001070 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001071 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001072 return err;
1073 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001074 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001075 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001076 results->version = 0;
1077 results->count = 0;
1078 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1079
Arend van Spriela0f472a2013-04-05 10:57:49 +02001080 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001081 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001082 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001083 return err;
1084}
1085
1086static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001087brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001088 struct cfg80211_scan_request *request,
1089 struct cfg80211_ssid *this_ssid)
1090{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001091 struct brcmf_if *ifp = vif->ifp;
1092 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001093 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -08001094 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001095 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001096 bool escan_req;
1097 bool spec_scan;
1098 s32 err;
1099 u32 SSID_len;
1100
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001101 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001102
Arend van Sprielc1179032012-10-22 13:55:33 -07001103 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001104 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001105 return -EAGAIN;
1106 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001107 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001108 brcmf_err("Scanning being aborted: status (%lu)\n",
1109 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001110 return -EAGAIN;
1111 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001112 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1113 brcmf_err("Scanning suppressed: status (%lu)\n",
1114 cfg->scan_status);
1115 return -EAGAIN;
1116 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001117 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001118 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001119 return -EAGAIN;
1120 }
1121
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001122 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001123 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1124 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001125
Hante Meulemane756af52012-09-11 21:18:52 +02001126 escan_req = false;
1127 if (request) {
1128 /* scan bss */
1129 ssids = request->ssids;
1130 escan_req = true;
1131 } else {
1132 /* scan in ibss */
1133 /* we don't do escan in ibss */
1134 ssids = this_ssid;
1135 }
1136
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001137 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001138 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001139 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001140 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001141 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001142 if (err)
1143 goto scan_out;
1144
Arend van Spriela0f472a2013-04-05 10:57:49 +02001145 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001146 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001147 goto scan_out;
1148 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001149 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1150 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001151 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
1152 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
1153 sr->ssid_le.SSID_len = cpu_to_le32(0);
1154 spec_scan = false;
1155 if (SSID_len) {
1156 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
1157 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
1158 spec_scan = true;
1159 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001160 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001161
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001162 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001163 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001164 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001165 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001166 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001167 goto scan_out;
1168 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001169 brcmf_scan_config_mpc(ifp, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -07001170 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -07001171 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001172 if (err) {
1173 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001174 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
1175 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001176 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001177 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001178
Daniel Kim5e787f72014-06-21 12:11:18 +02001179 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001180 goto scan_out;
1181 }
1182 }
1183
Hante Meuleman661fa952015-02-06 18:36:47 +01001184 /* Arm scan timeout timer */
1185 mod_timer(&cfg->escan_timeout, jiffies +
1186 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
1187
Hante Meulemane756af52012-09-11 21:18:52 +02001188 return 0;
1189
1190scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001191 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001192 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001193 return err;
1194}
1195
Arend van Spriel5b435de2011-10-05 13:19:03 +02001196static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001197brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001198{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001199 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001200 s32 err = 0;
1201
Arend van Sprield96b8012012-12-05 15:26:02 +01001202 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001203 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1204 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001205 return -EIO;
1206
Arend van Spriela0f472a2013-04-05 10:57:49 +02001207 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001208
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001210 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211
Arend van Sprield96b8012012-12-05 15:26:02 +01001212 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001213 return err;
1214}
1215
1216static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1217{
1218 s32 err = 0;
1219
Arend van Sprielac24be62012-10-22 10:36:23 -07001220 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1221 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001223 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001224
1225 return err;
1226}
1227
1228static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1229{
1230 s32 err = 0;
1231
Arend van Sprielac24be62012-10-22 10:36:23 -07001232 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1233 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001234 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001235 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001236
1237 return err;
1238}
1239
1240static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1241{
1242 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001243 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001244
Arend van Sprielac24be62012-10-22 10:36:23 -07001245 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001246 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001247 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 return err;
1249 }
1250 return err;
1251}
1252
1253static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1254{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001255 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1256 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001257 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001258 s32 err = 0;
1259
Arend van Sprield96b8012012-12-05 15:26:02 +01001260 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001261 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262 return -EIO;
1263
1264 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001265 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1266 cfg->conf->rts_threshold = wiphy->rts_threshold;
1267 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001268 if (!err)
1269 goto done;
1270 }
1271 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001272 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1273 cfg->conf->frag_threshold = wiphy->frag_threshold;
1274 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 if (!err)
1276 goto done;
1277 }
1278 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001279 && (cfg->conf->retry_long != wiphy->retry_long)) {
1280 cfg->conf->retry_long = wiphy->retry_long;
1281 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001282 if (!err)
1283 goto done;
1284 }
1285 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001286 && (cfg->conf->retry_short != wiphy->retry_short)) {
1287 cfg->conf->retry_short = wiphy->retry_short;
1288 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001289 if (!err)
1290 goto done;
1291 }
1292
1293done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001294 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295 return err;
1296}
1297
Arend van Spriel5b435de2011-10-05 13:19:03 +02001298static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1299{
1300 memset(prof, 0, sizeof(*prof));
1301}
1302
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001303static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1304{
1305 u16 reason;
1306
1307 switch (e->event_code) {
1308 case BRCMF_E_DEAUTH:
1309 case BRCMF_E_DEAUTH_IND:
1310 case BRCMF_E_DISASSOC_IND:
1311 reason = e->reason;
1312 break;
1313 case BRCMF_E_LINK:
1314 default:
1315 reason = 0;
1316 break;
1317 }
1318 return reason;
1319}
1320
1321static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001322{
Piotr Haber61730d42013-04-23 12:53:12 +02001323 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324 s32 err = 0;
1325
Arend van Sprield96b8012012-12-05 15:26:02 +01001326 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001327
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001328 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001329 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001330 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001331 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001332 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001333 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001334 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001335 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001336 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
Johannes Berg80279fb2015-05-22 16:22:20 +02001337 true, GFP_KERNEL);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001338
Arend van Spriel5b435de2011-10-05 13:19:03 +02001339 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001340 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001341 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1342 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001343 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001344}
1345
1346static s32
1347brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1348 struct cfg80211_ibss_params *params)
1349{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001350 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001351 struct brcmf_if *ifp = netdev_priv(ndev);
1352 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353 struct brcmf_join_params join_params;
1354 size_t join_params_size = 0;
1355 s32 err = 0;
1356 s32 wsec = 0;
1357 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001358 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001359
Arend van Sprield96b8012012-12-05 15:26:02 +01001360 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001361 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001362 return -EIO;
1363
1364 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001365 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001366 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001367 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001368 return -EOPNOTSUPP;
1369 }
1370
Arend van Sprielc1179032012-10-22 13:55:33 -07001371 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001372
1373 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001374 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001375 else
Arend van Spriel16886732012-12-05 15:26:04 +01001376 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001377
Johannes Berg683b6d32012-11-08 21:25:48 +01001378 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001379 brcmf_dbg(CONN, "channel: %d\n",
1380 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001381 else
Arend van Spriel16886732012-12-05 15:26:04 +01001382 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001383
1384 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001385 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001386 else
Arend van Spriel16886732012-12-05 15:26:04 +01001387 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001388
1389 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001390 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001391 else
Arend van Spriel16886732012-12-05 15:26:04 +01001392 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001393
1394 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001395 brcmf_dbg(CONN, "beacon interval: %d\n",
1396 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001397 else
Arend van Spriel16886732012-12-05 15:26:04 +01001398 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399
1400 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001401 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 else
Arend van Spriel16886732012-12-05 15:26:04 +01001403 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404
1405 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001406 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001407 else
Arend van Spriel16886732012-12-05 15:26:04 +01001408 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001409
1410 /* Configure Privacy for starter */
1411 if (params->privacy)
1412 wsec |= WEP_ENABLED;
1413
Arend van Sprielc1179032012-10-22 13:55:33 -07001414 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001416 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 goto done;
1418 }
1419
1420 /* Configure Beacon Interval for starter */
1421 if (params->beacon_interval)
1422 bcnprd = params->beacon_interval;
1423 else
1424 bcnprd = 100;
1425
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001426 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001428 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 goto done;
1430 }
1431
1432 /* Configure required join parameter */
1433 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1434
1435 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001436 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1437 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1438 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1439 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001441
1442 /* BSSID */
1443 if (params->bssid) {
1444 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1445 join_params_size = sizeof(join_params.ssid_le) +
1446 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001447 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001448 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001449 eth_broadcast_addr(join_params.params_le.bssid);
1450 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001451 }
1452
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001454 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001455 u32 target_channel;
1456
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001457 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001459 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001460 if (params->channel_fixed) {
1461 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001462 chanspec = chandef_to_chanspec(&cfg->d11inf,
1463 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001464 join_params.params_le.chanspec_list[0] =
1465 cpu_to_le16(chanspec);
1466 join_params.params_le.chanspec_num = cpu_to_le32(1);
1467 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001468 }
1469
1470 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001471 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001472 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001473 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001475 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001476 goto done;
1477 }
1478 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001479 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001481 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482
1483
Arend van Sprielc1179032012-10-22 13:55:33 -07001484 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001485 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001486 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001487 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001488 goto done;
1489 }
1490
1491done:
1492 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001493 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001494 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 return err;
1496}
1497
1498static s32
1499brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1500{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001501 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001502
Arend van Sprield96b8012012-12-05 15:26:02 +01001503 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001504 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505 return -EIO;
1506
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001507 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001508
Arend van Sprield96b8012012-12-05 15:26:02 +01001509 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001511 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512}
1513
1514static s32 brcmf_set_wpa_version(struct net_device *ndev,
1515 struct cfg80211_connect_params *sme)
1516{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001517 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518 struct brcmf_cfg80211_security *sec;
1519 s32 val = 0;
1520 s32 err = 0;
1521
1522 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1523 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1524 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1525 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1526 else
1527 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001528 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001529 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001531 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001532 return err;
1533 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001534 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001535 sec->wpa_versions = sme->crypto.wpa_versions;
1536 return err;
1537}
1538
1539static s32 brcmf_set_auth_type(struct net_device *ndev,
1540 struct cfg80211_connect_params *sme)
1541{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001542 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543 struct brcmf_cfg80211_security *sec;
1544 s32 val = 0;
1545 s32 err = 0;
1546
1547 switch (sme->auth_type) {
1548 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1549 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001550 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 break;
1552 case NL80211_AUTHTYPE_SHARED_KEY:
1553 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001554 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001555 break;
1556 case NL80211_AUTHTYPE_AUTOMATIC:
1557 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001558 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001559 break;
1560 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001561 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001562 default:
1563 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001564 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565 break;
1566 }
1567
Hante Meuleman89286dc2013-02-08 15:53:46 +01001568 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001570 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001571 return err;
1572 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001573 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 sec->auth_type = sme->auth_type;
1575 return err;
1576}
1577
1578static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001579brcmf_set_wsec_mode(struct net_device *ndev,
1580 struct cfg80211_connect_params *sme, bool mfp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001581{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001582 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001583 struct brcmf_cfg80211_security *sec;
1584 s32 pval = 0;
1585 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001586 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587 s32 err = 0;
1588
1589 if (sme->crypto.n_ciphers_pairwise) {
1590 switch (sme->crypto.ciphers_pairwise[0]) {
1591 case WLAN_CIPHER_SUITE_WEP40:
1592 case WLAN_CIPHER_SUITE_WEP104:
1593 pval = WEP_ENABLED;
1594 break;
1595 case WLAN_CIPHER_SUITE_TKIP:
1596 pval = TKIP_ENABLED;
1597 break;
1598 case WLAN_CIPHER_SUITE_CCMP:
1599 pval = AES_ENABLED;
1600 break;
1601 case WLAN_CIPHER_SUITE_AES_CMAC:
1602 pval = AES_ENABLED;
1603 break;
1604 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001605 brcmf_err("invalid cipher pairwise (%d)\n",
1606 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001607 return -EINVAL;
1608 }
1609 }
1610 if (sme->crypto.cipher_group) {
1611 switch (sme->crypto.cipher_group) {
1612 case WLAN_CIPHER_SUITE_WEP40:
1613 case WLAN_CIPHER_SUITE_WEP104:
1614 gval = WEP_ENABLED;
1615 break;
1616 case WLAN_CIPHER_SUITE_TKIP:
1617 gval = TKIP_ENABLED;
1618 break;
1619 case WLAN_CIPHER_SUITE_CCMP:
1620 gval = AES_ENABLED;
1621 break;
1622 case WLAN_CIPHER_SUITE_AES_CMAC:
1623 gval = AES_ENABLED;
1624 break;
1625 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001626 brcmf_err("invalid cipher group (%d)\n",
1627 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001628 return -EINVAL;
1629 }
1630 }
1631
Arend van Spriel16886732012-12-05 15:26:04 +01001632 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001633 /* In case of privacy, but no security and WPS then simulate */
1634 /* setting AES. WPS-2.0 allows no security */
1635 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1636 sme->privacy)
1637 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001638
1639 if (mfp)
1640 wsec = pval | gval | MFP_CAPABLE;
1641 else
1642 wsec = pval | gval;
1643 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001644 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001645 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 return err;
1647 }
1648
Arend van Spriel06bb1232012-09-27 14:17:56 +02001649 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001650 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1651 sec->cipher_group = sme->crypto.cipher_group;
1652
1653 return err;
1654}
1655
1656static s32
1657brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1658{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001659 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001660 struct brcmf_cfg80211_security *sec;
1661 s32 val = 0;
1662 s32 err = 0;
1663
1664 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001665 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1666 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001667 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001668 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001669 return err;
1670 }
1671 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1672 switch (sme->crypto.akm_suites[0]) {
1673 case WLAN_AKM_SUITE_8021X:
1674 val = WPA_AUTH_UNSPECIFIED;
1675 break;
1676 case WLAN_AKM_SUITE_PSK:
1677 val = WPA_AUTH_PSK;
1678 break;
1679 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001680 brcmf_err("invalid cipher group (%d)\n",
1681 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001682 return -EINVAL;
1683 }
1684 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1685 switch (sme->crypto.akm_suites[0]) {
1686 case WLAN_AKM_SUITE_8021X:
1687 val = WPA2_AUTH_UNSPECIFIED;
1688 break;
1689 case WLAN_AKM_SUITE_PSK:
1690 val = WPA2_AUTH_PSK;
1691 break;
1692 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001693 brcmf_err("invalid cipher group (%d)\n",
1694 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001695 return -EINVAL;
1696 }
1697 }
1698
Arend van Spriel16886732012-12-05 15:26:04 +01001699 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001700 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1701 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001702 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001703 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001704 return err;
1705 }
1706 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001707 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001708 sec->wpa_auth = sme->crypto.akm_suites[0];
1709
1710 return err;
1711}
1712
1713static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001714brcmf_set_sharedkey(struct net_device *ndev,
1715 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001716{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001717 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001718 struct brcmf_cfg80211_security *sec;
1719 struct brcmf_wsec_key key;
1720 s32 val;
1721 s32 err = 0;
1722
Arend van Spriel16886732012-12-05 15:26:04 +01001723 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001724
Roland Vossena718e2f2011-10-12 20:51:24 +02001725 if (sme->key_len == 0)
1726 return 0;
1727
Arend van Spriel06bb1232012-09-27 14:17:56 +02001728 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001729 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1730 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001731
1732 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1733 return 0;
1734
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001735 if (!(sec->cipher_pairwise &
1736 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1737 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001738
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001739 memset(&key, 0, sizeof(key));
1740 key.len = (u32) sme->key_len;
1741 key.index = (u32) sme->key_idx;
1742 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001743 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001744 return -EINVAL;
1745 }
1746 memcpy(key.data, sme->key, key.len);
1747 key.flags = BRCMF_PRIMARY_KEY;
1748 switch (sec->cipher_pairwise) {
1749 case WLAN_CIPHER_SUITE_WEP40:
1750 key.algo = CRYPTO_ALGO_WEP1;
1751 break;
1752 case WLAN_CIPHER_SUITE_WEP104:
1753 key.algo = CRYPTO_ALGO_WEP128;
1754 break;
1755 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001756 brcmf_err("Invalid algorithm (%d)\n",
1757 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001758 return -EINVAL;
1759 }
1760 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001761 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1762 key.len, key.index, key.algo);
1763 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001764 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001765 if (err)
1766 return err;
1767
1768 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001769 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001770 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001771 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001772 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001773 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001774 }
1775 return err;
1776}
1777
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001778static
1779enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1780 enum nl80211_auth_type type)
1781{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001782 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1783 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1784 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1785 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001786 }
1787 return type;
1788}
1789
Arend van Spriel5b435de2011-10-05 13:19:03 +02001790static s32
1791brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001792 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001793{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001794 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001795 struct brcmf_if *ifp = netdev_priv(ndev);
1796 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 struct ieee80211_channel *chan = sme->channel;
1798 struct brcmf_join_params join_params;
1799 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001800 const struct brcmf_tlv *rsn_ie;
1801 const struct brcmf_vs_tlv *wpa_ie;
1802 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001803 u32 ie_len;
1804 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001805 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001806 s32 err = 0;
1807
Arend van Sprield96b8012012-12-05 15:26:02 +01001808 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001809 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001810 return -EIO;
1811
1812 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001813 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001814 return -EOPNOTSUPP;
1815 }
1816
Hante Meuleman89286dc2013-02-08 15:53:46 +01001817 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1818 /* A normal (non P2P) connection request setup. */
1819 ie = NULL;
1820 ie_len = 0;
1821 /* find the WPA_IE */
1822 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1823 if (wpa_ie) {
1824 ie = wpa_ie;
1825 ie_len = wpa_ie->len + TLV_HDR_LEN;
1826 } else {
1827 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001828 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1829 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001830 WLAN_EID_RSN);
1831 if (rsn_ie) {
1832 ie = rsn_ie;
1833 ie_len = rsn_ie->len + TLV_HDR_LEN;
1834 }
1835 }
1836 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1837 }
1838
1839 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1840 sme->ie, sme->ie_len);
1841 if (err)
1842 brcmf_err("Set Assoc REQ IE Failed\n");
1843 else
1844 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1845
Arend van Sprielc1179032012-10-22 13:55:33 -07001846 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001847
1848 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001849 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001850 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001851 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001852 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1853 cfg->channel, chan->center_freq, chanspec);
1854 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001855 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001856 chanspec = 0;
1857 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001858
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001859 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001860
1861 err = brcmf_set_wpa_version(ndev, sme);
1862 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001863 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001864 goto done;
1865 }
1866
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001867 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001868 err = brcmf_set_auth_type(ndev, sme);
1869 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001870 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001871 goto done;
1872 }
1873
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001874 err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001875 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001876 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001877 goto done;
1878 }
1879
1880 err = brcmf_set_key_mgmt(ndev, sme);
1881 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001882 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001883 goto done;
1884 }
1885
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001886 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001887 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001888 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 goto done;
1890 }
1891
Hante Meuleman89286dc2013-02-08 15:53:46 +01001892 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1893 (u32)sme->ssid_len);
1894 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1895 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1896 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1897 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1898 profile->ssid.SSID_len);
1899 }
1900
1901 /* Join with specific BSSID and cached SSID
1902 * If SSID is zero join based on BSSID only
1903 */
1904 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1905 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1906 if (cfg->channel)
1907 join_params_size += sizeof(u16);
1908 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1909 if (ext_join_params == NULL) {
1910 err = -ENOMEM;
1911 goto done;
1912 }
1913 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1914 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1915 profile->ssid.SSID_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001916
Hante Meuleman89286dc2013-02-08 15:53:46 +01001917 /* Set up join scan parameters */
1918 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001919 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1920
1921 if (sme->bssid)
1922 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1923 else
Joe Perches93803b32015-03-02 19:54:49 -08001924 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001925
1926 if (cfg->channel) {
1927 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1928
1929 ext_join_params->assoc_le.chanspec_list[0] =
1930 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001931 /* Increase dwell time to receive probe response or detect
1932 * beacon from target AP at a noisy air only during connect
1933 * command.
1934 */
1935 ext_join_params->scan_le.active_time =
1936 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1937 ext_join_params->scan_le.passive_time =
1938 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1939 /* To sync with presence period of VSDB GO send probe request
1940 * more frequently. Probe request will be stopped when it gets
1941 * probe response from target AP/GO.
1942 */
1943 ext_join_params->scan_le.nprobes =
1944 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1945 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1946 } else {
1947 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
1948 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
1949 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001950 }
1951
1952 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1953 join_params_size);
1954 kfree(ext_join_params);
1955 if (!err)
1956 /* This is it. join command worked, we are done */
1957 goto done;
1958
1959 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001960 memset(&join_params, 0, sizeof(join_params));
1961 join_params_size = sizeof(join_params.ssid_le);
1962
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001963 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001964 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965
Hante Meuleman89286dc2013-02-08 15:53:46 +01001966 if (sme->bssid)
1967 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1968 else
Joe Perches93803b32015-03-02 19:54:49 -08001969 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001970
Hante Meuleman17012612013-02-06 18:40:44 +01001971 if (cfg->channel) {
1972 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1973 join_params.params_le.chanspec_num = cpu_to_le32(1);
1974 join_params_size += sizeof(join_params.params_le);
1975 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001976 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001977 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001978 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001979 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001980
1981done:
1982 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001983 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001984 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 return err;
1986}
1987
1988static s32
1989brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1990 u16 reason_code)
1991{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001992 struct brcmf_if *ifp = netdev_priv(ndev);
1993 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001994 struct brcmf_scb_val_le scbval;
1995 s32 err = 0;
1996
Arend van Sprield96b8012012-12-05 15:26:02 +01001997 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001998 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999 return -EIO;
2000
Arend van Sprielc1179032012-10-22 13:55:33 -07002001 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002002 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002003 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002004
Arend van Spriel06bb1232012-09-27 14:17:56 +02002005 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002006 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002007 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002008 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002009 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002010 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002011
Arend van Sprield96b8012012-12-05 15:26:02 +01002012 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002013 return err;
2014}
2015
2016static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002017brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002018 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002019{
2020
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002021 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002022 struct net_device *ndev = cfg_to_ndev(cfg);
2023 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002024 u16 txpwrmw;
2025 s32 err = 0;
2026 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002027 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002028
Arend van Sprield96b8012012-12-05 15:26:02 +01002029 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002030 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002031 return -EIO;
2032
2033 switch (type) {
2034 case NL80211_TX_POWER_AUTOMATIC:
2035 break;
2036 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002037 case NL80211_TX_POWER_FIXED:
2038 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002039 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002040 err = -EINVAL;
2041 goto done;
2042 }
2043 break;
2044 }
2045 /* Make sure radio is off or on as far as software is concerned */
2046 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002047 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002049 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050
2051 if (dbm > 0xffff)
2052 txpwrmw = 0xffff;
2053 else
2054 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07002055 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
2056 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002058 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002059 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002060
2061done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002062 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002063 return err;
2064}
2065
Johannes Bergc8442112012-10-24 10:17:18 +02002066static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
2067 struct wireless_dev *wdev,
2068 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002070 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002071 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 s32 txpwrdbm;
2073 u8 result;
2074 s32 err = 0;
2075
Arend van Sprield96b8012012-12-05 15:26:02 +01002076 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002077 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002078 return -EIO;
2079
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002080 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002081 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002082 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002083 goto done;
2084 }
2085
2086 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02002087 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088
2089done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002090 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002091 return err;
2092}
2093
2094static s32
2095brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
2096 u8 key_idx, bool unicast, bool multicast)
2097{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002098 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002099 u32 index;
2100 u32 wsec;
2101 s32 err = 0;
2102
Arend van Sprield96b8012012-12-05 15:26:02 +01002103 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002104 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002105 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002106 return -EIO;
2107
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002108 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002109 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002110 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002111 goto done;
2112 }
2113
2114 if (wsec & WEP_ENABLED) {
2115 /* Just select a new current key */
2116 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002117 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002118 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002120 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002121 }
2122done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002123 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002124 return err;
2125}
2126
2127static s32
2128brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
2129 u8 key_idx, const u8 *mac_addr, struct key_params *params)
2130{
Hante Meuleman992f6062013-04-02 21:06:17 +02002131 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002133 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02002134 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135
2136 memset(&key, 0, sizeof(key));
2137 key.index = (u32) key_idx;
2138 /* Instead of bcast for ea address for default wep keys,
2139 driver needs it to be Null */
2140 if (!is_multicast_ether_addr(mac_addr))
2141 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
2142 key.len = (u32) params->key_len;
2143 /* check for key index change */
2144 if (key.len == 0) {
2145 /* key delete */
Hante Meuleman118eb302014-12-21 12:43:49 +01002146 err = send_key_to_dongle(ifp, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002148 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 } else {
2150 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002151 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152 return -EINVAL;
2153 }
2154
Arend van Spriel16886732012-12-05 15:26:04 +01002155 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002156 memcpy(key.data, params->key, key.len);
2157
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002158 if (!brcmf_is_apmode(ifp->vif) &&
Hante Meuleman992f6062013-04-02 21:06:17 +02002159 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
2160 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002161 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2162 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2163 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2164 }
2165
2166 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
2167 if (params->seq && params->seq_len == 6) {
2168 /* rx iv */
2169 u8 *ivptr;
2170 ivptr = (u8 *) params->seq;
2171 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2172 (ivptr[3] << 8) | ivptr[2];
2173 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2174 key.iv_initialized = true;
2175 }
2176
2177 switch (params->cipher) {
2178 case WLAN_CIPHER_SUITE_WEP40:
2179 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01002180 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181 break;
2182 case WLAN_CIPHER_SUITE_WEP104:
2183 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01002184 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002185 break;
2186 case WLAN_CIPHER_SUITE_TKIP:
2187 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002188 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 break;
2190 case WLAN_CIPHER_SUITE_AES_CMAC:
2191 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01002192 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002193 break;
2194 case WLAN_CIPHER_SUITE_CCMP:
2195 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01002196 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002197 break;
2198 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002199 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002200 return -EINVAL;
2201 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002202 err = send_key_to_dongle(ifp, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002203 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002204 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002205 }
2206 return err;
2207}
2208
2209static s32
2210brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
2211 u8 key_idx, bool pairwise, const u8 *mac_addr,
2212 struct key_params *params)
2213{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002214 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002215 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002216 s32 val;
2217 s32 wsec;
2218 s32 err = 0;
2219 u8 keybuf[8];
2220
Arend van Sprield96b8012012-12-05 15:26:02 +01002221 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002222 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002223 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002224 return -EIO;
2225
Hante Meuleman118eb302014-12-21 12:43:49 +01002226 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2227 /* we ignore this key index in this case */
2228 brcmf_err("invalid key index (%d)\n", key_idx);
2229 return -EINVAL;
2230 }
2231
Daniel Kim787eb032014-01-29 15:32:23 +01002232 if (mac_addr &&
2233 (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2234 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01002235 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
2237 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
Hante Meuleman118eb302014-12-21 12:43:49 +01002239 key = &ifp->vif->profile.key[key_idx];
2240 memset(key, 0, sizeof(*key));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002241
Hante Meuleman118eb302014-12-21 12:43:49 +01002242 if (params->key_len > sizeof(key->data)) {
2243 brcmf_err("Too long key length (%u)\n", params->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244 err = -EINVAL;
2245 goto done;
2246 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002247 key->len = params->key_len;
2248 key->index = key_idx;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002249
Hante Meuleman118eb302014-12-21 12:43:49 +01002250 memcpy(key->data, params->key, key->len);
2251
2252 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002253 switch (params->cipher) {
2254 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002255 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002256 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002257 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002258 break;
2259 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002260 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002261 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002262 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263 break;
2264 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002265 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002266 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002267 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2268 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2269 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002270 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002271 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002272 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002273 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002274 break;
2275 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002276 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002277 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002278 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002279 break;
2280 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002281 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002282 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002283 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284 break;
2285 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002286 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002287 err = -EINVAL;
2288 goto done;
2289 }
2290
Hante Meuleman118eb302014-12-21 12:43:49 +01002291 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 if (err)
2293 goto done;
2294
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002295 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002296 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002297 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002298 goto done;
2299 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002300 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002301 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002302 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002303 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002304 goto done;
2305 }
2306
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002308 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002309 return err;
2310}
2311
2312static s32
2313brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2314 u8 key_idx, bool pairwise, const u8 *mac_addr)
2315{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002316 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002317 struct brcmf_wsec_key key;
2318 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002319
Arend van Sprield96b8012012-12-05 15:26:02 +01002320 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002321 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322 return -EIO;
2323
Hante Meuleman118eb302014-12-21 12:43:49 +01002324 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
Hante Meuleman256c3742012-11-05 16:22:28 -08002325 /* we ignore this key index in this case */
Hante Meuleman256c3742012-11-05 16:22:28 -08002326 return -EINVAL;
2327 }
2328
Arend van Spriel5b435de2011-10-05 13:19:03 +02002329 memset(&key, 0, sizeof(key));
2330
2331 key.index = (u32) key_idx;
2332 key.flags = BRCMF_PRIMARY_KEY;
2333 key.algo = CRYPTO_ALGO_OFF;
2334
Arend van Spriel16886732012-12-05 15:26:04 +01002335 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336
2337 /* Set the new key/index */
Hante Meuleman118eb302014-12-21 12:43:49 +01002338 err = send_key_to_dongle(ifp, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339
Arend van Sprield96b8012012-12-05 15:26:02 +01002340 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002341 return err;
2342}
2343
2344static s32
2345brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2346 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2347 void (*callback) (void *cookie, struct key_params * params))
2348{
2349 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002350 struct brcmf_if *ifp = netdev_priv(ndev);
2351 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352 struct brcmf_cfg80211_security *sec;
2353 s32 wsec;
2354 s32 err = 0;
2355
Arend van Sprield96b8012012-12-05 15:26:02 +01002356 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002357 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002358 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002359 return -EIO;
2360
2361 memset(&params, 0, sizeof(params));
2362
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002363 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002364 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002365 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 /* Ignore this error, may happen during DISASSOC */
2367 err = -EAGAIN;
2368 goto done;
2369 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002370 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002371 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2373 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002374 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002375 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2376 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002377 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002379 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002380 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002381 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002382 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002383 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002384 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002385 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002386 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002387 err = -EINVAL;
2388 goto done;
2389 }
2390 callback(cookie, &params);
2391
2392done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002393 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 return err;
2395}
2396
2397static s32
2398brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2399 struct net_device *ndev, u8 key_idx)
2400{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002401 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002402
2403 return -EOPNOTSUPP;
2404}
2405
Hante Meuleman118eb302014-12-21 12:43:49 +01002406static void
2407brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2408{
2409 s32 err;
2410 u8 key_idx;
2411 struct brcmf_wsec_key *key;
2412 s32 wsec;
2413
2414 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2415 key = &ifp->vif->profile.key[key_idx];
2416 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2417 (key->algo == CRYPTO_ALGO_WEP128))
2418 break;
2419 }
2420 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2421 return;
2422
2423 err = send_key_to_dongle(ifp, key);
2424 if (err) {
2425 brcmf_err("Setting WEP key failed (%d)\n", err);
2426 return;
2427 }
2428 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2429 if (err) {
2430 brcmf_err("get wsec error (%d)\n", err);
2431 return;
2432 }
2433 wsec |= WEP_ENABLED;
2434 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2435 if (err)
2436 brcmf_err("set wsec error (%d)\n", err);
2437}
2438
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002439static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2440{
2441 struct nl80211_sta_flag_update *sfu;
2442
2443 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2444 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2445 sfu = &si->sta_flags;
2446 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2447 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2448 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2449 BIT(NL80211_STA_FLAG_AUTHORIZED);
2450 if (fw_sta_flags & BRCMF_STA_WME)
2451 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2452 if (fw_sta_flags & BRCMF_STA_AUTHE)
2453 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2454 if (fw_sta_flags & BRCMF_STA_ASSOC)
2455 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2456 if (fw_sta_flags & BRCMF_STA_AUTHO)
2457 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2458}
2459
2460static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2461{
2462 struct {
2463 __le32 len;
2464 struct brcmf_bss_info_le bss_le;
2465 } *buf;
2466 u16 capability;
2467 int err;
2468
2469 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2470 if (!buf)
2471 return;
2472
2473 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2474 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2475 WL_BSS_INFO_MAX);
2476 if (err) {
2477 brcmf_err("Failed to get bss info (%d)\n", err);
2478 return;
2479 }
2480 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2481 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2482 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2483 capability = le16_to_cpu(buf->bss_le.capability);
2484 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2485 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2486 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2487 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2488 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2489 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2490}
2491
Arend van Spriel5b435de2011-10-05 13:19:03 +02002492static s32
2493brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002494 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002495{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002496 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002498 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002499 u32 sta_flags;
2500 u32 is_tdls_peer;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002501
Arend van Sprield96b8012012-12-05 15:26:02 +01002502 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002503 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002504 return -EIO;
2505
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002506 memset(&sta_info_le, 0, sizeof(sta_info_le));
2507 memcpy(&sta_info_le, mac, ETH_ALEN);
2508 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2509 &sta_info_le,
2510 sizeof(sta_info_le));
2511 is_tdls_peer = !err;
2512 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002513 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002514 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002515 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002516 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002517 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002518 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002519 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002520 }
2521 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2522 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2523 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2524 sta_flags = le32_to_cpu(sta_info_le.flags);
2525 brcmf_convert_sta_flags(sta_flags, sinfo);
2526 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2527 if (is_tdls_peer)
2528 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2529 else
2530 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2531 if (sta_flags & BRCMF_STA_ASSOC) {
2532 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2533 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2534 brcmf_fill_bss_param(ifp, sinfo);
2535 }
2536 if (sta_flags & BRCMF_STA_SCBSTATS) {
2537 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2538 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2539 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2540 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2541 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2542 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2543 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2544 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2545 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002546 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002547 sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
2548 sinfo->txrate.legacy /= 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002549 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002550 if (sinfo->rx_packets) {
2551 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
2552 sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
2553 sinfo->rxrate.legacy /= 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002554 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002555 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2556 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2557 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2558 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2559 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2560 }
2561 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002562done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002563 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002564 return err;
2565}
2566
2567static s32
2568brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2569 bool enabled, s32 timeout)
2570{
2571 s32 pm;
2572 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002573 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002574 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002575
Arend van Sprield96b8012012-12-05 15:26:02 +01002576 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002577
2578 /*
2579 * Powersave enable/disable request is coming from the
2580 * cfg80211 even before the interface is up. In that
2581 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002582 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002583 * FW later while initializing the dongle
2584 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002585 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002586 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002587
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002588 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002589 goto done;
2590 }
2591
2592 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002593 /* Do not enable the power save after assoc if it is a p2p interface */
2594 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2595 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2596 pm = PM_OFF;
2597 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002598 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002599
Arend van Sprielc1179032012-10-22 13:55:33 -07002600 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002601 if (err) {
2602 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002603 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002604 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002605 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002606 }
2607done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002608 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002609 return err;
2610}
2611
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002612static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002613 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002614{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002615 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002616 struct ieee80211_channel *notify_channel;
2617 struct cfg80211_bss *bss;
2618 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002619 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002620 u16 channel;
2621 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002622 u16 notify_capability;
2623 u16 notify_interval;
2624 u8 *notify_ie;
2625 size_t notify_ielen;
2626 s32 notify_signal;
2627
2628 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002629 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002630 return 0;
2631 }
2632
Franky Lin83cf17a2013-04-11 13:28:50 +02002633 if (!bi->ctl_ch) {
2634 ch.chspec = le16_to_cpu(bi->chanspec);
2635 cfg->d11inf.decchspec(&ch);
2636 bi->ctl_ch = ch.chnum;
2637 }
2638 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002639
2640 if (channel <= CH_MAX_2G_CHANNEL)
2641 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2642 else
2643 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2644
2645 freq = ieee80211_channel_to_frequency(channel, band->band);
2646 notify_channel = ieee80211_get_channel(wiphy, freq);
2647
Arend van Spriel5b435de2011-10-05 13:19:03 +02002648 notify_capability = le16_to_cpu(bi->capability);
2649 notify_interval = le16_to_cpu(bi->beacon_period);
2650 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2651 notify_ielen = le32_to_cpu(bi->ie_length);
2652 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2653
Arend van Spriel16886732012-12-05 15:26:04 +01002654 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2655 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2656 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2657 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2658 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002659
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002660 bss = cfg80211_inform_bss(wiphy, notify_channel,
2661 CFG80211_BSS_FTYPE_UNKNOWN,
2662 (const u8 *)bi->BSSID,
2663 0, notify_capability,
2664 notify_interval, notify_ie,
2665 notify_ielen, notify_signal,
2666 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002667
Franky Line78946e2011-11-10 20:30:34 +01002668 if (!bss)
2669 return -ENOMEM;
2670
Johannes Berg5b112d32013-02-01 01:49:58 +01002671 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002672
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002673 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002674}
2675
Roland Vossen6f09be02011-10-18 14:03:02 +02002676static struct brcmf_bss_info_le *
2677next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2678{
2679 if (bss == NULL)
2680 return list->bss_info_le;
2681 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2682 le32_to_cpu(bss->length));
2683}
2684
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002685static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002686{
2687 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002688 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002689 s32 err = 0;
2690 int i;
2691
Hante Meulemanef8596e2014-09-30 10:23:13 +02002692 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002693 if (bss_list->count != 0 &&
2694 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002695 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2696 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002697 return -EOPNOTSUPP;
2698 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002699 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002700 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002701 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002702 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002703 if (err)
2704 break;
2705 }
2706 return err;
2707}
2708
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002709static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710 struct net_device *ndev, const u8 *bssid)
2711{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002712 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002713 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002714 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002715 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002716 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002717 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718 u8 *buf = NULL;
2719 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002720 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002721 u16 notify_capability;
2722 u16 notify_interval;
2723 u8 *notify_ie;
2724 size_t notify_ielen;
2725 s32 notify_signal;
2726
Arend van Sprield96b8012012-12-05 15:26:02 +01002727 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002728
2729 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2730 if (buf == NULL) {
2731 err = -ENOMEM;
2732 goto CleanUp;
2733 }
2734
2735 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2736
Arend van Sprielac24be62012-10-22 10:36:23 -07002737 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2738 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002740 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002741 goto CleanUp;
2742 }
2743
Roland Vossend34bf642011-10-18 14:03:01 +02002744 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002745
Franky Lin83cf17a2013-04-11 13:28:50 +02002746 ch.chspec = le16_to_cpu(bi->chanspec);
2747 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002748
Franky Lin83cf17a2013-04-11 13:28:50 +02002749 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002750 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2751 else
2752 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2753
Franky Lin83cf17a2013-04-11 13:28:50 +02002754 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002755 notify_channel = ieee80211_get_channel(wiphy, freq);
2756
Arend van Spriel5b435de2011-10-05 13:19:03 +02002757 notify_capability = le16_to_cpu(bi->capability);
2758 notify_interval = le16_to_cpu(bi->beacon_period);
2759 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2760 notify_ielen = le32_to_cpu(bi->ie_length);
2761 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2762
Franky Lin83cf17a2013-04-11 13:28:50 +02002763 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002764 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2765 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2766 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002767
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002768 bss = cfg80211_inform_bss(wiphy, notify_channel,
2769 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2770 notify_capability, notify_interval,
2771 notify_ie, notify_ielen, notify_signal,
2772 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002773
Franky Line78946e2011-11-10 20:30:34 +01002774 if (!bss) {
2775 err = -ENOMEM;
2776 goto CleanUp;
2777 }
2778
Johannes Berg5b112d32013-02-01 01:49:58 +01002779 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002780
Arend van Spriel5b435de2011-10-05 13:19:03 +02002781CleanUp:
2782
2783 kfree(buf);
2784
Arend van Sprield96b8012012-12-05 15:26:02 +01002785 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002786
2787 return err;
2788}
2789
Hante Meuleman89286dc2013-02-08 15:53:46 +01002790static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2791 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002792{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002793 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002794 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002795 struct brcmf_ssid *ssid;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002796 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 u16 beacon_interval;
2798 u8 dtim_period;
2799 size_t ie_len;
2800 u8 *ie;
2801 s32 err = 0;
2802
Arend van Sprield96b8012012-12-05 15:26:02 +01002803 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002804 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002805 return err;
2806
Arend van Spriel06bb1232012-09-27 14:17:56 +02002807 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002808
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002809 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002810 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002811 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002812 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002813 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814 goto update_bss_info_out;
2815 }
2816
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002817 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2818 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819 if (err)
2820 goto update_bss_info_out;
2821
2822 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2823 ie_len = le32_to_cpu(bi->ie_length);
2824 beacon_interval = le16_to_cpu(bi->beacon_period);
2825
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002826 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002827 if (tim)
2828 dtim_period = tim->data[1];
2829 else {
2830 /*
2831 * active scan was done so we could not get dtim
2832 * information out of probe response.
2833 * so we speficially query dtim information to dongle.
2834 */
2835 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002836 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002838 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002839 goto update_bss_info_out;
2840 }
2841 dtim_period = (u8)var;
2842 }
2843
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002845 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002846 return err;
2847}
2848
Hante Meuleman18e2f612013-02-08 15:53:49 +01002849void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002850{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002851 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002852
Arend van Sprielc1179032012-10-22 13:55:33 -07002853 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002854 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002855 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002856 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002857 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002858 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2859 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860}
2861
Hante Meulemane756af52012-09-11 21:18:52 +02002862static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2863{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002864 struct brcmf_cfg80211_info *cfg =
2865 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002866 escan_timeout_work);
2867
Hante Meulemanef8596e2014-09-30 10:23:13 +02002868 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002869 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002870}
2871
2872static void brcmf_escan_timeout(unsigned long data)
2873{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002874 struct brcmf_cfg80211_info *cfg =
2875 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002876
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002877 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002878 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002879 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002880 }
2881}
2882
2883static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002884brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2885 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002886 struct brcmf_bss_info_le *bss_info_le)
2887{
Franky Lin83cf17a2013-04-11 13:28:50 +02002888 struct brcmu_chan ch_bss, ch_bss_info_le;
2889
2890 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2891 cfg->d11inf.decchspec(&ch_bss);
2892 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2893 cfg->d11inf.decchspec(&ch_bss_info_le);
2894
Hante Meulemane756af52012-09-11 21:18:52 +02002895 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002896 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002897 bss_info_le->SSID_len == bss->SSID_len &&
2898 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002899 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2900 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002901 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2902 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2903
Hante Meulemane756af52012-09-11 21:18:52 +02002904 /* preserve max RSSI if the measurements are
2905 * both on-channel or both off-channel
2906 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002907 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002908 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002909 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2910 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002911 /* preserve the on-channel rssi measurement
2912 * if the new measurement is off channel
2913 */
2914 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002915 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002916 }
2917 return 1;
2918 }
2919 return 0;
2920}
2921
2922static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002923brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002924 const struct brcmf_event_msg *e, void *data)
2925{
Arend van Spriel19937322012-11-05 16:22:32 -08002926 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002927 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02002928 struct brcmf_escan_result_le *escan_result_le;
2929 struct brcmf_bss_info_le *bss_info_le;
2930 struct brcmf_bss_info_le *bss = NULL;
2931 u32 bi_length;
2932 struct brcmf_scan_results *list;
2933 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002934 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002935
Arend van Spriel5c36b992012-11-14 18:46:05 -08002936 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002937
Arend van Spriela0f472a2013-04-05 10:57:49 +02002938 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2939 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002940 return -EPERM;
2941 }
2942
2943 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002944 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002945 escan_result_le = (struct brcmf_escan_result_le *) data;
2946 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002947 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002948 goto exit;
2949 }
Hante Meulemane756af52012-09-11 21:18:52 +02002950 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002951 brcmf_err("Invalid bss_count %d: ignoring\n",
2952 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002953 goto exit;
2954 }
2955 bss_info_le = &escan_result_le->bss_info_le;
2956
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002957 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2958 goto exit;
2959
2960 if (!cfg->scan_request) {
2961 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2962 goto exit;
2963 }
2964
Hante Meulemane756af52012-09-11 21:18:52 +02002965 bi_length = le32_to_cpu(bss_info_le->length);
2966 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2967 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002968 brcmf_err("Invalid bss_info length %d: ignoring\n",
2969 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002970 goto exit;
2971 }
2972
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002973 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002974 BIT(NL80211_IFTYPE_ADHOC))) {
2975 if (le16_to_cpu(bss_info_le->capability) &
2976 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002977 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002978 goto exit;
2979 }
2980 }
2981
2982 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002983 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002984 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002985 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002986 goto exit;
2987 }
2988
2989 for (i = 0; i < list->count; i++) {
2990 bss = bss ? (struct brcmf_bss_info_le *)
2991 ((unsigned char *)bss +
2992 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002993 if (brcmf_compare_update_same_bss(cfg, bss,
2994 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002995 goto exit;
2996 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002997 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002998 bss_info_le, bi_length);
2999 list->version = le32_to_cpu(bss_info_le->version);
3000 list->buflen += bi_length;
3001 list->count++;
3002 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003003 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003004 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3005 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003006 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003007 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003008 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003009 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003010 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003011 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3012 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003013 }
3014exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003015 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003016}
3017
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003018static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003019{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003020 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3021 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003022 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3023 /* Init scan_timeout timer */
3024 init_timer(&cfg->escan_timeout);
3025 cfg->escan_timeout.data = (unsigned long) cfg;
3026 cfg->escan_timeout.function = brcmf_escan_timeout;
3027 INIT_WORK(&cfg->escan_timeout_work,
3028 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003029}
3030
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003031static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003032{
3033 if (ms < 1000 / HZ) {
3034 cond_resched();
3035 mdelay(ms);
3036 } else {
3037 msleep(ms);
3038 }
3039}
3040
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003041static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3042 u8 *pattern, u32 patternsize, u8 *mask,
3043 u32 packet_offset)
3044{
3045 struct brcmf_fil_wowl_pattern_le *filter;
3046 u32 masksize;
3047 u32 patternoffset;
3048 u8 *buf;
3049 u32 bufsize;
3050 s32 ret;
3051
3052 masksize = (patternsize + 7) / 8;
3053 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3054
3055 bufsize = sizeof(*filter) + patternsize + masksize;
3056 buf = kzalloc(bufsize, GFP_KERNEL);
3057 if (!buf)
3058 return -ENOMEM;
3059 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3060
3061 memcpy(filter->cmd, cmd, 4);
3062 filter->masksize = cpu_to_le32(masksize);
3063 filter->offset = cpu_to_le32(packet_offset);
3064 filter->patternoffset = cpu_to_le32(patternoffset);
3065 filter->patternsize = cpu_to_le32(patternsize);
3066 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3067
3068 if ((mask) && (masksize))
3069 memcpy(buf + sizeof(*filter), mask, masksize);
3070 if ((pattern) && (patternsize))
3071 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3072
3073 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3074
3075 kfree(buf);
3076 return ret;
3077}
3078
Arend van Spriel5b435de2011-10-05 13:19:03 +02003079static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3080{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003081 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3082 struct net_device *ndev = cfg_to_ndev(cfg);
3083 struct brcmf_if *ifp = netdev_priv(ndev);
3084
Arend van Sprield96b8012012-12-05 15:26:02 +01003085 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003086
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003087 if (cfg->wowl_enabled) {
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003088 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003089 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
3090 cfg->pre_wowl_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003091 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003092 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003093 cfg->wowl_enabled = false;
3094 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003095 return 0;
3096}
3097
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003098static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3099 struct brcmf_if *ifp,
3100 struct cfg80211_wowlan *wowl)
3101{
3102 u32 wowl_config;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003103 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003104
3105 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3106
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003107 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003108 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
3109 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3110
3111 wowl_config = 0;
3112 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003113 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003114 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003115 wowl_config |= BRCMF_WOWL_MAGIC;
3116 if ((wowl->patterns) && (wowl->n_patterns)) {
3117 wowl_config |= BRCMF_WOWL_NET;
3118 for (i = 0; i < wowl->n_patterns; i++) {
3119 brcmf_config_wowl_pattern(ifp, "add",
3120 (u8 *)wowl->patterns[i].pattern,
3121 wowl->patterns[i].pattern_len,
3122 (u8 *)wowl->patterns[i].mask,
3123 wowl->patterns[i].pkt_offset);
3124 }
3125 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003126 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3127 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3128 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
3129 cfg->wowl_enabled = true;
3130}
3131
Arend van Spriel5b435de2011-10-05 13:19:03 +02003132static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003133 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003134{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003135 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3136 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003137 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003138 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003139
Arend van Sprield96b8012012-12-05 15:26:02 +01003140 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003141
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003142 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003143 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003144 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003145 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003146 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003147
Arend van Spriel7d641072012-10-22 13:55:39 -07003148 /* end any scanning */
3149 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003150 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003151
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003152 if (wowl == NULL) {
3153 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3154 list_for_each_entry(vif, &cfg->vif_list, list) {
3155 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3156 continue;
3157 /* While going to suspend if associated with AP
3158 * disassociate from AP to save power while system is
3159 * in suspended state
3160 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003161 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003162 /* Make sure WPA_Supplicant receives all the event
3163 * generated due to DISASSOC call to the fw to keep
3164 * the state fw and WPA_Supplicant state consistent
3165 */
3166 brcmf_delay(500);
3167 }
3168 /* Configure MPC */
3169 brcmf_set_mpc(ifp, 1);
3170
3171 } else {
3172 /* Configure WOWL paramaters */
3173 brcmf_configure_wowl(cfg, ifp, wowl);
3174 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003175
Arend van Spriel7d641072012-10-22 13:55:39 -07003176exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003177 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003178 /* clear any scanning activity */
3179 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003180 return 0;
3181}
3182
3183static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02003184brcmf_update_pmklist(struct net_device *ndev,
3185 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
3186{
3187 int i, j;
Arend van Sprielc15d7892014-11-20 22:26:59 +01003188 u32 pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003189
Arend van Spriel40c8e952011-10-12 20:51:20 +02003190 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
3191
Arend van Spriel16886732012-12-05 15:26:04 +01003192 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003193 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01003194 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
3195 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003196 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01003197 brcmf_dbg(CONN, "%02x\n",
3198 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003199 }
3200
3201 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07003202 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
3203 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003204
3205 return err;
3206}
3207
3208static s32
3209brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3210 struct cfg80211_pmksa *pmksa)
3211{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003212 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003213 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003214 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003215 s32 err = 0;
Arend van Sprielc15d7892014-11-20 22:26:59 +01003216 u32 pmkid_len, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003217
Arend van Sprield96b8012012-12-05 15:26:02 +01003218 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003219 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003220 return -EIO;
3221
Arend van Spriel40c8e952011-10-12 20:51:20 +02003222 pmkid_len = le32_to_cpu(pmkids->npmkid);
3223 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003224 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
3225 break;
3226 if (i < WL_NUM_PMKIDS_MAX) {
3227 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
3228 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003229 if (i == pmkid_len) {
3230 pmkid_len++;
3231 pmkids->npmkid = cpu_to_le32(pmkid_len);
3232 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003233 } else
3234 err = -EINVAL;
3235
Arend van Spriel16886732012-12-05 15:26:04 +01003236 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
3237 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003238 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01003239 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003240
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003241 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003242
Arend van Sprield96b8012012-12-05 15:26:02 +01003243 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003244 return err;
3245}
3246
3247static s32
3248brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3249 struct cfg80211_pmksa *pmksa)
3250{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003251 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003252 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003253 struct pmkid_list pmkid;
3254 s32 err = 0;
Arend van Sprielc15d7892014-11-20 22:26:59 +01003255 u32 pmkid_len, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003256
Arend van Sprield96b8012012-12-05 15:26:02 +01003257 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003258 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003259 return -EIO;
3260
3261 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
3262 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
3263
Arend van Spriel16886732012-12-05 15:26:04 +01003264 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3265 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003266 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01003267 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003268
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003269 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003270 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003271 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003272 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003273 ETH_ALEN))
3274 break;
3275
Arend van Spriel40c8e952011-10-12 20:51:20 +02003276 if ((pmkid_len > 0)
3277 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003278 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003279 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02003280 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003281 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
3282 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003283 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003284 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
3285 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003286 WLAN_PMKID_LEN);
3287 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003288 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003289 } else
3290 err = -EINVAL;
3291
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003292 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003293
Arend van Sprield96b8012012-12-05 15:26:02 +01003294 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003295 return err;
3296
3297}
3298
3299static s32
3300brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3301{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003302 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003303 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003304 s32 err = 0;
3305
Arend van Sprield96b8012012-12-05 15:26:02 +01003306 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003307 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003308 return -EIO;
3309
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003310 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
3311 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003312
Arend van Sprield96b8012012-12-05 15:26:02 +01003313 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003314 return err;
3315
3316}
3317
Arend van Spriele5806072012-09-19 22:21:08 +02003318/*
3319 * PFN result doesn't have all the info which are
3320 * required by the supplicant
3321 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3322 * via wl_inform_single_bss in the required format. Escan does require the
3323 * scan request in the form of cfg80211_scan_request. For timebeing, create
3324 * cfg80211_scan_request one out of the received PNO event.
3325 */
3326static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003327brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02003328 const struct brcmf_event_msg *e, void *data)
3329{
Arend van Spriel19937322012-11-05 16:22:32 -08003330 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02003331 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3332 struct cfg80211_scan_request *request = NULL;
3333 struct cfg80211_ssid *ssid = NULL;
3334 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003335 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003336 int err = 0;
3337 int channel_req = 0;
3338 int band = 0;
3339 struct brcmf_pno_scanresults_le *pfn_result;
3340 u32 result_count;
3341 u32 status;
3342
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003343 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003344
Arend van Spriel5c36b992012-11-14 18:46:05 -08003345 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003346 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003347 return 0;
3348 }
3349
3350 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3351 result_count = le32_to_cpu(pfn_result->count);
3352 status = le32_to_cpu(pfn_result->status);
3353
3354 /*
3355 * PFN event is limited to fit 512 bytes so we may get
3356 * multiple NET_FOUND events. For now place a warning here.
3357 */
3358 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003359 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02003360 if (result_count > 0) {
3361 int i;
3362
3363 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03003364 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3365 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02003366 if (!request || !ssid || !channel) {
3367 err = -ENOMEM;
3368 goto out_err;
3369 }
3370
3371 request->wiphy = wiphy;
3372 data += sizeof(struct brcmf_pno_scanresults_le);
3373 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3374
3375 for (i = 0; i < result_count; i++) {
3376 netinfo = &netinfo_start[i];
3377 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003378 brcmf_err("Invalid netinfo ptr. index: %d\n",
3379 i);
Arend van Spriele5806072012-09-19 22:21:08 +02003380 err = -EINVAL;
3381 goto out_err;
3382 }
3383
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003384 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3385 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02003386 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3387 ssid[i].ssid_len = netinfo->SSID_len;
3388 request->n_ssids++;
3389
3390 channel_req = netinfo->channel;
3391 if (channel_req <= CH_MAX_2G_CHANNEL)
3392 band = NL80211_BAND_2GHZ;
3393 else
3394 band = NL80211_BAND_5GHZ;
3395 channel[i].center_freq =
3396 ieee80211_channel_to_frequency(channel_req,
3397 band);
3398 channel[i].band = band;
3399 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3400 request->channels[i] = &channel[i];
3401 request->n_channels++;
3402 }
3403
3404 /* assign parsed ssid array */
3405 if (request->n_ssids)
3406 request->ssids = &ssid[0];
3407
Arend van Sprielc1179032012-10-22 13:55:33 -07003408 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02003409 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003410 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003411 }
3412
Arend van Sprielc1179032012-10-22 13:55:33 -07003413 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel2668b0b2014-01-13 22:20:28 +01003414 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003415 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02003416 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003417 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003418 goto out_err;
3419 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003420 cfg->sched_escan = true;
3421 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02003422 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003423 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003424 goto out_err;
3425 }
3426
3427 kfree(ssid);
3428 kfree(channel);
3429 kfree(request);
3430 return 0;
3431
3432out_err:
3433 kfree(ssid);
3434 kfree(channel);
3435 kfree(request);
3436 cfg80211_sched_scan_stopped(wiphy);
3437 return err;
3438}
3439
Arend van Spriele5806072012-09-19 22:21:08 +02003440static int brcmf_dev_pno_clean(struct net_device *ndev)
3441{
Arend van Spriele5806072012-09-19 22:21:08 +02003442 int ret;
3443
3444 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003445 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003446 if (ret == 0) {
3447 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003448 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3449 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003450 }
3451 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003452 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003453
3454 return ret;
3455}
3456
3457static int brcmf_dev_pno_config(struct net_device *ndev)
3458{
3459 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003460
3461 memset(&pfn_param, 0, sizeof(pfn_param));
3462 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3463
3464 /* set extra pno params */
3465 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3466 pfn_param.repeat = BRCMF_PNO_REPEAT;
3467 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3468
3469 /* set up pno scan fr */
3470 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3471
Arend van Sprielac24be62012-10-22 10:36:23 -07003472 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3473 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003474}
3475
3476static int
3477brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3478 struct net_device *ndev,
3479 struct cfg80211_sched_scan_request *request)
3480{
Arend van Sprielc1179032012-10-22 13:55:33 -07003481 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003482 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003483 struct brcmf_pno_net_param_le pfn;
3484 int i;
3485 int ret = 0;
3486
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003487 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003488 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003489 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003490 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003491 return -EAGAIN;
3492 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003493 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3494 brcmf_err("Scanning suppressed: status (%lu)\n",
3495 cfg->scan_status);
3496 return -EAGAIN;
3497 }
Arend van Spriele5806072012-09-19 22:21:08 +02003498
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003499 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel181f2d12014-05-27 12:56:13 +02003500 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003501 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003502 return -EINVAL;
3503 }
3504
3505 if (request->n_ssids > 0) {
3506 for (i = 0; i < request->n_ssids; i++) {
3507 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003508 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3509 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003510
3511 /*
3512 * match_set ssids is a supert set of n_ssid list,
3513 * so we need not add these set seperately.
3514 */
3515 }
3516 }
3517
3518 if (request->n_match_sets > 0) {
3519 /* clean up everything */
3520 ret = brcmf_dev_pno_clean(ndev);
3521 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003522 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003523 return ret;
3524 }
3525
3526 /* configure pno */
3527 ret = brcmf_dev_pno_config(ndev);
3528 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003529 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003530 return -EINVAL;
3531 }
3532
3533 /* configure each match set */
3534 for (i = 0; i < request->n_match_sets; i++) {
3535 struct cfg80211_ssid *ssid;
3536 u32 ssid_len;
3537
3538 ssid = &request->match_sets[i].ssid;
3539 ssid_len = ssid->ssid_len;
3540
3541 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003542 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003543 continue;
3544 }
3545 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3546 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3547 pfn.wsec = cpu_to_le32(0);
3548 pfn.infra = cpu_to_le32(1);
3549 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3550 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3551 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003552 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003553 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003554 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3555 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003556 }
3557 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003558 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003559 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003560 return -EINVAL;
3561 }
3562 } else {
3563 return -EINVAL;
3564 }
3565
3566 return 0;
3567}
3568
3569static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3570 struct net_device *ndev)
3571{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003572 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003573
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003574 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003575 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003576 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003577 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003578 return 0;
3579}
Arend van Spriele5806072012-09-19 22:21:08 +02003580
Hante Meuleman1f170112013-02-06 18:40:38 +01003581static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003582{
3583 s32 err;
3584
3585 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003586 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003587 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003588 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003589 return err;
3590 }
3591 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003592 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003593 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003594 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003595 return err;
3596 }
3597 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003598 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003599 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003600 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003601 return err;
3602 }
3603
3604 return 0;
3605}
3606
3607static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3608{
3609 if (is_rsn_ie)
3610 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3611
3612 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3613}
3614
3615static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003616brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003617 const struct brcmf_vs_tlv *wpa_ie,
3618 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003619{
3620 u32 auth = 0; /* d11 open authentication */
3621 u16 count;
3622 s32 err = 0;
3623 s32 len = 0;
3624 u32 i;
3625 u32 wsec;
3626 u32 pval = 0;
3627 u32 gval = 0;
3628 u32 wpa_auth = 0;
3629 u32 offset;
3630 u8 *data;
3631 u16 rsn_cap;
3632 u32 wme_bss_disable;
3633
Arend van Sprield96b8012012-12-05 15:26:02 +01003634 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003635 if (wpa_ie == NULL)
3636 goto exit;
3637
3638 len = wpa_ie->len + TLV_HDR_LEN;
3639 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003640 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003641 if (!is_rsn_ie)
3642 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003643 else
3644 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003645
3646 /* check for multicast cipher suite */
3647 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3648 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003649 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003650 goto exit;
3651 }
3652
3653 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3654 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003655 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003656 goto exit;
3657 }
3658 offset += TLV_OUI_LEN;
3659
3660 /* pick up multicast cipher */
3661 switch (data[offset]) {
3662 case WPA_CIPHER_NONE:
3663 gval = 0;
3664 break;
3665 case WPA_CIPHER_WEP_40:
3666 case WPA_CIPHER_WEP_104:
3667 gval = WEP_ENABLED;
3668 break;
3669 case WPA_CIPHER_TKIP:
3670 gval = TKIP_ENABLED;
3671 break;
3672 case WPA_CIPHER_AES_CCM:
3673 gval = AES_ENABLED;
3674 break;
3675 default:
3676 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003677 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003678 goto exit;
3679 }
3680
3681 offset++;
3682 /* walk thru unicast cipher list and pick up what we recognize */
3683 count = data[offset] + (data[offset + 1] << 8);
3684 offset += WPA_IE_SUITE_COUNT_LEN;
3685 /* Check for unicast suite(s) */
3686 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3687 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003688 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003689 goto exit;
3690 }
3691 for (i = 0; i < count; i++) {
3692 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3693 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003694 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003695 goto exit;
3696 }
3697 offset += TLV_OUI_LEN;
3698 switch (data[offset]) {
3699 case WPA_CIPHER_NONE:
3700 break;
3701 case WPA_CIPHER_WEP_40:
3702 case WPA_CIPHER_WEP_104:
3703 pval |= WEP_ENABLED;
3704 break;
3705 case WPA_CIPHER_TKIP:
3706 pval |= TKIP_ENABLED;
3707 break;
3708 case WPA_CIPHER_AES_CCM:
3709 pval |= AES_ENABLED;
3710 break;
3711 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003712 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003713 }
3714 offset++;
3715 }
3716 /* walk thru auth management suite list and pick up what we recognize */
3717 count = data[offset] + (data[offset + 1] << 8);
3718 offset += WPA_IE_SUITE_COUNT_LEN;
3719 /* Check for auth key management suite(s) */
3720 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3721 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003722 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003723 goto exit;
3724 }
3725 for (i = 0; i < count; i++) {
3726 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3727 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003728 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003729 goto exit;
3730 }
3731 offset += TLV_OUI_LEN;
3732 switch (data[offset]) {
3733 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003734 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003735 wpa_auth |= WPA_AUTH_NONE;
3736 break;
3737 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003738 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003739 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3740 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3741 break;
3742 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003743 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003744 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3745 (wpa_auth |= WPA_AUTH_PSK);
3746 break;
3747 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003748 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003749 }
3750 offset++;
3751 }
3752
3753 if (is_rsn_ie) {
3754 wme_bss_disable = 1;
3755 if ((offset + RSN_CAP_LEN) <= len) {
3756 rsn_cap = data[offset] + (data[offset + 1] << 8);
3757 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3758 wme_bss_disable = 0;
3759 }
3760 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003761 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003762 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003763 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003764 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003765 goto exit;
3766 }
3767 }
3768 /* FOR WPS , set SES_OW_ENABLED */
3769 wsec = (pval | gval | SES_OW_ENABLED);
3770
3771 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003772 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003773 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003774 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003775 goto exit;
3776 }
3777 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003778 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003779 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003780 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003781 goto exit;
3782 }
3783 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003784 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003785 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003786 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003787 goto exit;
3788 }
3789
3790exit:
3791 return err;
3792}
3793
3794static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003795brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003796 struct parsed_vndr_ies *vndr_ies)
3797{
Hante Meuleman1a873342012-09-27 14:17:54 +02003798 struct brcmf_vs_tlv *vndrie;
3799 struct brcmf_tlv *ie;
3800 struct parsed_vndr_ie_info *parsed_info;
3801 s32 remaining_len;
3802
3803 remaining_len = (s32)vndr_ie_len;
3804 memset(vndr_ies, 0, sizeof(*vndr_ies));
3805
3806 ie = (struct brcmf_tlv *)vndr_ie_buf;
3807 while (ie) {
3808 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3809 goto next;
3810 vndrie = (struct brcmf_vs_tlv *)ie;
3811 /* len should be bigger than OUI length + one */
3812 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003813 brcmf_err("invalid vndr ie. length is too small %d\n",
3814 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003815 goto next;
3816 }
3817 /* if wpa or wme ie, do not add ie */
3818 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3819 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3820 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003821 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003822 goto next;
3823 }
3824
3825 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3826
3827 /* save vndr ie information */
3828 parsed_info->ie_ptr = (char *)vndrie;
3829 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3830 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3831
3832 vndr_ies->count++;
3833
Arend van Sprield96b8012012-12-05 15:26:02 +01003834 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3835 parsed_info->vndrie.oui[0],
3836 parsed_info->vndrie.oui[1],
3837 parsed_info->vndrie.oui[2],
3838 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003839
Arend van Spriel9f440b72013-02-08 15:53:36 +01003840 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003841 break;
3842next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003843 remaining_len -= (ie->len + TLV_HDR_LEN);
3844 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003845 ie = NULL;
3846 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003847 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3848 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003849 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003850 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02003851}
3852
3853static u32
3854brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3855{
3856
Hante Meuleman1a873342012-09-27 14:17:54 +02003857 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3858 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3859
Vaishali Thakkar362126c2015-01-16 21:36:14 +05303860 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003861
Vaishali Thakkar362126c2015-01-16 21:36:14 +05303862 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003863
3864 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3865
3866 return ie_len + VNDR_IE_HDR_SIZE;
3867}
3868
Arend van Spriel1332e262012-11-05 16:22:18 -08003869s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3870 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003871{
Arend van Spriel1332e262012-11-05 16:22:18 -08003872 struct brcmf_if *ifp;
3873 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003874 s32 err = 0;
3875 u8 *iovar_ie_buf;
3876 u8 *curr_ie_buf;
3877 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003878 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003879 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003880 u32 del_add_ie_buf_len = 0;
3881 u32 total_ie_buf_len = 0;
3882 u32 parsed_ie_buf_len = 0;
3883 struct parsed_vndr_ies old_vndr_ies;
3884 struct parsed_vndr_ies new_vndr_ies;
3885 struct parsed_vndr_ie_info *vndrie_info;
3886 s32 i;
3887 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003888 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003889
Arend van Spriel1332e262012-11-05 16:22:18 -08003890 if (!vif)
3891 return -ENODEV;
3892 ifp = vif->ifp;
3893 saved_ie = &vif->saved_ie;
3894
Arend van Sprield96b8012012-12-05 15:26:02 +01003895 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003896 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3897 if (!iovar_ie_buf)
3898 return -ENOMEM;
3899 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003900 switch (pktflag) {
3901 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3902 mgmt_ie_buf = saved_ie->probe_req_ie;
3903 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3904 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3905 break;
3906 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3907 mgmt_ie_buf = saved_ie->probe_res_ie;
3908 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3909 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3910 break;
3911 case BRCMF_VNDR_IE_BEACON_FLAG:
3912 mgmt_ie_buf = saved_ie->beacon_ie;
3913 mgmt_ie_len = &saved_ie->beacon_ie_len;
3914 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3915 break;
3916 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3917 mgmt_ie_buf = saved_ie->assoc_req_ie;
3918 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3919 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3920 break;
3921 default:
3922 err = -EPERM;
3923 brcmf_err("not suitable type\n");
3924 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003925 }
3926
3927 if (vndr_ie_len > mgmt_ie_buf_len) {
3928 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003929 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003930 goto exit;
3931 }
3932
3933 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3934 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3935 ptr = curr_ie_buf;
3936 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3937 for (i = 0; i < new_vndr_ies.count; i++) {
3938 vndrie_info = &new_vndr_ies.ie_info[i];
3939 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3940 vndrie_info->ie_len);
3941 parsed_ie_buf_len += vndrie_info->ie_len;
3942 }
3943 }
3944
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003945 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003946 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3947 (memcmp(mgmt_ie_buf, curr_ie_buf,
3948 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003949 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003950 goto exit;
3951 }
3952
3953 /* parse old vndr_ie */
3954 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3955
3956 /* make a command to delete old ie */
3957 for (i = 0; i < old_vndr_ies.count; i++) {
3958 vndrie_info = &old_vndr_ies.ie_info[i];
3959
Arend van Sprield96b8012012-12-05 15:26:02 +01003960 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3961 vndrie_info->vndrie.id,
3962 vndrie_info->vndrie.len,
3963 vndrie_info->vndrie.oui[0],
3964 vndrie_info->vndrie.oui[1],
3965 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003966
3967 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3968 vndrie_info->ie_ptr,
3969 vndrie_info->ie_len,
3970 "del");
3971 curr_ie_buf += del_add_ie_buf_len;
3972 total_ie_buf_len += del_add_ie_buf_len;
3973 }
3974 }
3975
3976 *mgmt_ie_len = 0;
3977 /* Add if there is any extra IE */
3978 if (mgmt_ie_buf && parsed_ie_buf_len) {
3979 ptr = mgmt_ie_buf;
3980
3981 remained_buf_len = mgmt_ie_buf_len;
3982
3983 /* make a command to add new ie */
3984 for (i = 0; i < new_vndr_ies.count; i++) {
3985 vndrie_info = &new_vndr_ies.ie_info[i];
3986
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003987 /* verify remained buf size before copy data */
3988 if (remained_buf_len < (vndrie_info->vndrie.len +
3989 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003990 brcmf_err("no space in mgmt_ie_buf: len left %d",
3991 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003992 break;
3993 }
3994 remained_buf_len -= (vndrie_info->ie_len +
3995 VNDR_IE_VSIE_OFFSET);
3996
Arend van Sprield96b8012012-12-05 15:26:02 +01003997 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3998 vndrie_info->vndrie.id,
3999 vndrie_info->vndrie.len,
4000 vndrie_info->vndrie.oui[0],
4001 vndrie_info->vndrie.oui[1],
4002 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004003
4004 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4005 vndrie_info->ie_ptr,
4006 vndrie_info->ie_len,
4007 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004008
4009 /* save the parsed IE in wl struct */
4010 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4011 vndrie_info->ie_len);
4012 *mgmt_ie_len += vndrie_info->ie_len;
4013
4014 curr_ie_buf += del_add_ie_buf_len;
4015 total_ie_buf_len += del_add_ie_buf_len;
4016 }
4017 }
4018 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004019 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004020 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004021 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004022 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004023 }
4024
4025exit:
4026 kfree(iovar_ie_buf);
4027 return err;
4028}
4029
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004030s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4031{
4032 s32 pktflags[] = {
4033 BRCMF_VNDR_IE_PRBREQ_FLAG,
4034 BRCMF_VNDR_IE_PRBRSP_FLAG,
4035 BRCMF_VNDR_IE_BEACON_FLAG
4036 };
4037 int i;
4038
4039 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4040 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4041
4042 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4043 return 0;
4044}
4045
Hante Meuleman1a873342012-09-27 14:17:54 +02004046static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004047brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4048 struct cfg80211_beacon_data *beacon)
4049{
4050 s32 err;
4051
4052 /* Set Beacon IEs to FW */
4053 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4054 beacon->tail, beacon->tail_len);
4055 if (err) {
4056 brcmf_err("Set Beacon IE Failed\n");
4057 return err;
4058 }
4059 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4060
4061 /* Set Probe Response IEs to FW */
4062 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4063 beacon->proberesp_ies,
4064 beacon->proberesp_ies_len);
4065 if (err)
4066 brcmf_err("Set Probe Resp IE Failed\n");
4067 else
4068 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4069
4070 return err;
4071}
4072
4073static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004074brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4075 struct cfg80211_ap_settings *settings)
4076{
4077 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004078 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004079 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004080 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004081 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004082 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004083 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004084 const struct brcmf_tlv *rsn_ie;
4085 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004086 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004087 enum nl80211_iftype dev_role;
4088 struct brcmf_fil_bss_enable_le bss_enable;
Arend van Spriel06c01582014-05-12 10:47:37 +02004089 u16 chanspec;
Hante Meulemana44aa402014-12-03 21:05:33 +01004090 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004091 int is_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004092
Arend van Spriel06c01582014-05-12 10:47:37 +02004093 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4094 settings->chandef.chan->hw_value,
4095 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004096 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004097 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4098 settings->ssid, settings->ssid_len, settings->auth_type,
4099 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004100 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004101 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004102
Arend van Spriel98027762014-12-21 12:43:53 +01004103 /* store current 11d setting */
4104 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4105 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4106 settings->beacon.tail_len,
4107 WLAN_EID_COUNTRY);
4108 is_11d = country_ie ? 1 : 0;
4109
Hante Meuleman1a873342012-09-27 14:17:54 +02004110 memset(&ssid_le, 0, sizeof(ssid_le));
4111 if (settings->ssid == NULL || settings->ssid_len == 0) {
4112 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4113 ssid_ie = brcmf_parse_tlvs(
4114 (u8 *)&settings->beacon.head[ie_offset],
4115 settings->beacon.head_len - ie_offset,
4116 WLAN_EID_SSID);
4117 if (!ssid_ie)
4118 return -EINVAL;
4119
4120 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4121 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004122 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004123 } else {
4124 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4125 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4126 }
4127
Hante Meulemana44aa402014-12-03 21:05:33 +01004128 if (!mbss) {
4129 brcmf_set_mpc(ifp, 0);
4130 brcmf_configure_arp_offload(ifp, false);
4131 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004132
4133 /* find the RSN_IE */
4134 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4135 settings->beacon.tail_len, WLAN_EID_RSN);
4136
4137 /* find the WPA_IE */
4138 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4139 settings->beacon.tail_len);
4140
Hante Meuleman1a873342012-09-27 14:17:54 +02004141 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004142 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004143 if (wpa_ie != NULL) {
4144 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004145 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004146 if (err < 0)
4147 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004148 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004149 struct brcmf_vs_tlv *tmp_ie;
4150
4151 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4152
Hante Meuleman1a873342012-09-27 14:17:54 +02004153 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004154 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004155 if (err < 0)
4156 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004157 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004158 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004159 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004160 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004161 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004162
Hante Meulemana0f07952013-02-08 15:53:47 +01004163 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004164
Hante Meulemana44aa402014-12-03 21:05:33 +01004165 if (!mbss) {
4166 chanspec = chandef_to_chanspec(&cfg->d11inf,
4167 &settings->chandef);
4168 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004169 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004170 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4171 chanspec, err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004172 goto exit;
4173 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004174
Arend van Spriel98027762014-12-21 12:43:53 +01004175 if (is_11d != ifp->vif->is_11d) {
4176 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4177 is_11d);
4178 if (err < 0) {
4179 brcmf_err("Regulatory Set Error, %d\n", err);
4180 goto exit;
4181 }
4182 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004183 if (settings->beacon_interval) {
4184 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4185 settings->beacon_interval);
4186 if (err < 0) {
4187 brcmf_err("Beacon Interval Set Error, %d\n",
4188 err);
4189 goto exit;
4190 }
4191 }
4192 if (settings->dtim_period) {
4193 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4194 settings->dtim_period);
4195 if (err < 0) {
4196 brcmf_err("DTIM Interval Set Error, %d\n", err);
4197 goto exit;
4198 }
4199 }
4200
4201 if (dev_role == NL80211_IFTYPE_AP) {
4202 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4203 if (err < 0) {
4204 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4205 goto exit;
4206 }
4207 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4208 }
4209
4210 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004211 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004212 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004213 goto exit;
4214 }
Arend van Spriel98027762014-12-21 12:43:53 +01004215 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4216 /* Multiple-BSS should use same 11d configuration */
4217 err = -EINVAL;
4218 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004219 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004220 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004221 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4222 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4223
Hante Meulemana0f07952013-02-08 15:53:47 +01004224 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4225 if (err < 0) {
4226 brcmf_err("setting AP mode failed %d\n", err);
4227 goto exit;
4228 }
4229 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4230 if (err < 0) {
4231 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4232 goto exit;
4233 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004234 /* On DOWN the firmware removes the WEP keys, reconfigure
4235 * them if they were set.
4236 */
4237 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004238
4239 memset(&join_params, 0, sizeof(join_params));
4240 /* join parameters starts with ssid */
4241 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4242 /* create softap */
4243 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4244 &join_params, sizeof(join_params));
4245 if (err < 0) {
4246 brcmf_err("SET SSID error (%d)\n", err);
4247 goto exit;
4248 }
4249 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4250 } else {
4251 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4252 sizeof(ssid_le));
4253 if (err < 0) {
4254 brcmf_err("setting ssid failed %d\n", err);
4255 goto exit;
4256 }
4257 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
4258 bss_enable.enable = cpu_to_le32(1);
4259 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4260 sizeof(bss_enable));
4261 if (err < 0) {
4262 brcmf_err("bss_enable config failed %d\n", err);
4263 goto exit;
4264 }
4265
4266 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4267 }
Arend van Sprielc1179032012-10-22 13:55:33 -07004268 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4269 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02004270
4271exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004272 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004273 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02004274 brcmf_configure_arp_offload(ifp, true);
4275 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004276 return err;
4277}
4278
4279static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4280{
Arend van Sprielc1179032012-10-22 13:55:33 -07004281 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004282 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004283 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004284 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004285
Arend van Sprield96b8012012-12-05 15:26:02 +01004286 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004287
Hante Meuleman426d0a52013-02-08 15:53:53 +01004288 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004289 /* Due to most likely deauths outstanding we sleep */
4290 /* first to make sure they get processed by fw. */
4291 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004292
Hante Meulemana44aa402014-12-03 21:05:33 +01004293 if (ifp->vif->mbss) {
4294 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4295 return err;
4296 }
4297
Hante Meuleman5c33a942013-04-02 21:06:18 +02004298 memset(&join_params, 0, sizeof(join_params));
4299 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4300 &join_params, sizeof(join_params));
4301 if (err < 0)
4302 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004303 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004304 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004305 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004306 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4307 if (err < 0)
4308 brcmf_err("setting AP mode failed %d\n", err);
4309 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4310 if (err < 0)
4311 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004312 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4313 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Arend van Spriel98027762014-12-21 12:43:53 +01004314 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4315 ifp->vif->is_11d);
4316 if (err < 0)
4317 brcmf_err("restoring REGULATORY setting failed %d\n",
4318 err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004319 /* Bring device back up so it can be used again */
4320 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4321 if (err < 0)
4322 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004323 } else {
4324 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
4325 bss_enable.enable = cpu_to_le32(0);
4326 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4327 sizeof(bss_enable));
4328 if (err < 0)
4329 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004330 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004331 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02004332 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004333 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4334 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
4335
Hante Meuleman1a873342012-09-27 14:17:54 +02004336 return err;
4337}
4338
Hante Meulemana0f07952013-02-08 15:53:47 +01004339static s32
4340brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4341 struct cfg80211_beacon_data *info)
4342{
Hante Meulemana0f07952013-02-08 15:53:47 +01004343 struct brcmf_if *ifp = netdev_priv(ndev);
4344 s32 err;
4345
4346 brcmf_dbg(TRACE, "Enter\n");
4347
Hante Meulemana0f07952013-02-08 15:53:47 +01004348 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4349
4350 return err;
4351}
4352
Hante Meuleman1a873342012-09-27 14:17:54 +02004353static int
4354brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004355 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004356{
Hante Meulemana0f07952013-02-08 15:53:47 +01004357 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004358 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004359 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004360 s32 err;
4361
Jouni Malinen89c771e2014-10-10 20:52:40 +03004362 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004363 return -EFAULT;
4364
Jouni Malinen89c771e2014-10-10 20:52:40 +03004365 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004366
Hante Meulemana0f07952013-02-08 15:53:47 +01004367 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4368 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004369 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004370 return -EIO;
4371
Jouni Malinen89c771e2014-10-10 20:52:40 +03004372 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004373 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004374 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004375 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004376 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004377 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004378
Arend van Sprield96b8012012-12-05 15:26:02 +01004379 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004380 return err;
4381}
4382
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004383static int
4384brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4385 const u8 *mac, struct station_parameters *params)
4386{
4387 struct brcmf_if *ifp = netdev_priv(ndev);
4388 s32 err;
4389
4390 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4391 params->sta_flags_mask, params->sta_flags_set);
4392
4393 /* Ignore all 00 MAC */
4394 if (is_zero_ether_addr(mac))
4395 return 0;
4396
4397 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4398 return 0;
4399
4400 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4401 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4402 (void *)mac, ETH_ALEN);
4403 else
4404 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4405 (void *)mac, ETH_ALEN);
4406 if (err < 0)
4407 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4408
4409 return err;
4410}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004411
4412static void
4413brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4414 struct wireless_dev *wdev,
4415 u16 frame_type, bool reg)
4416{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004417 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004418 u16 mgmt_type;
4419
4420 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4421
4422 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004423 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004424 if (reg)
4425 vif->mgmt_rx_reg |= BIT(mgmt_type);
4426 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004427 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004428}
4429
4430
4431static int
4432brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004433 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004434{
4435 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004436 struct ieee80211_channel *chan = params->chan;
4437 const u8 *buf = params->buf;
4438 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004439 const struct ieee80211_mgmt *mgmt;
4440 struct brcmf_cfg80211_vif *vif;
4441 s32 err = 0;
4442 s32 ie_offset;
4443 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004444 struct brcmf_fil_action_frame_le *action_frame;
4445 struct brcmf_fil_af_params_le *af_params;
4446 bool ack;
4447 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004448 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004449
4450 brcmf_dbg(TRACE, "Enter\n");
4451
4452 *cookie = 0;
4453
4454 mgmt = (const struct ieee80211_mgmt *)buf;
4455
Hante Meulemana0f07952013-02-08 15:53:47 +01004456 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4457 brcmf_err("Driver only allows MGMT packet type\n");
4458 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004459 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004460
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004461 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4462
Hante Meulemana0f07952013-02-08 15:53:47 +01004463 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4464 /* Right now the only reason to get a probe response */
4465 /* is for p2p listen response or for p2p GO from */
4466 /* wpa_supplicant. Unfortunately the probe is send */
4467 /* on primary ndev, while dongle wants it on the p2p */
4468 /* vif. Since this is only reason for a probe */
4469 /* response to be sent, the vif is taken from cfg. */
4470 /* If ever desired to send proberesp for non p2p */
4471 /* response then data should be checked for */
4472 /* "DIRECT-". Note in future supplicant will take */
4473 /* dedicated p2p wdev to do this and then this 'hack'*/
4474 /* is not needed anymore. */
4475 ie_offset = DOT11_MGMT_HDR_LEN +
4476 DOT11_BCN_PRB_FIXED_LEN;
4477 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004478 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4479 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4480 err = brcmf_vif_set_mgmt_ie(vif,
4481 BRCMF_VNDR_IE_PRBRSP_FLAG,
4482 &buf[ie_offset],
4483 ie_len);
4484 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4485 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004486 } else if (ieee80211_is_action(mgmt->frame_control)) {
4487 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4488 if (af_params == NULL) {
4489 brcmf_err("unable to allocate frame\n");
4490 err = -ENOMEM;
4491 goto exit;
4492 }
4493 action_frame = &af_params->action_frame;
4494 /* Add the packet Id */
4495 action_frame->packet_id = cpu_to_le32(*cookie);
4496 /* Add BSSID */
4497 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4498 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4499 /* Add the length exepted for 802.11 header */
4500 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004501 /* Add the channel. Use the one specified as parameter if any or
4502 * the current one (got from the firmware) otherwise
4503 */
4504 if (chan)
4505 freq = chan->center_freq;
4506 else
4507 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4508 &freq);
4509 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004510 af_params->channel = cpu_to_le32(chan_nr);
4511
4512 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4513 le16_to_cpu(action_frame->len));
4514
4515 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004516 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004517
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004518 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004519 af_params);
4520
4521 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4522 GFP_KERNEL);
4523 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004524 } else {
4525 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4526 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4527 }
4528
Hante Meuleman18e2f612013-02-08 15:53:49 +01004529exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004530 return err;
4531}
4532
4533
4534static int
4535brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4536 struct wireless_dev *wdev,
4537 u64 cookie)
4538{
4539 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4540 struct brcmf_cfg80211_vif *vif;
4541 int err = 0;
4542
4543 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4544
4545 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4546 if (vif == NULL) {
4547 brcmf_err("No p2p device available for probe response\n");
4548 err = -ENODEV;
4549 goto exit;
4550 }
4551 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4552exit:
4553 return err;
4554}
4555
Piotr Haber61730d42013-04-23 12:53:12 +02004556static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4557 struct wireless_dev *wdev,
4558 enum nl80211_crit_proto_id proto,
4559 u16 duration)
4560{
4561 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4562 struct brcmf_cfg80211_vif *vif;
4563
4564 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4565
4566 /* only DHCP support for now */
4567 if (proto != NL80211_CRIT_PROTO_DHCP)
4568 return -EINVAL;
4569
4570 /* suppress and abort scanning */
4571 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4572 brcmf_abort_scanning(cfg);
4573
4574 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4575}
4576
4577static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4578 struct wireless_dev *wdev)
4579{
4580 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4581 struct brcmf_cfg80211_vif *vif;
4582
4583 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4584
4585 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4586 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4587}
4588
Hante Meuleman70b7d942014-07-30 13:20:07 +02004589static s32
4590brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4591 const struct brcmf_event_msg *e, void *data)
4592{
4593 switch (e->reason) {
4594 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4595 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4596 break;
4597 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4598 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4599 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4600 break;
4601 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4602 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4603 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4604 break;
4605 }
4606
4607 return 0;
4608}
4609
Arend van Spriel89c2f382013-08-10 12:27:25 +02004610static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4611{
4612 int ret;
4613
4614 switch (oper) {
4615 case NL80211_TDLS_DISCOVERY_REQ:
4616 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4617 break;
4618 case NL80211_TDLS_SETUP:
4619 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4620 break;
4621 case NL80211_TDLS_TEARDOWN:
4622 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4623 break;
4624 default:
4625 brcmf_err("unsupported operation: %d\n", oper);
4626 ret = -EOPNOTSUPP;
4627 }
4628 return ret;
4629}
4630
4631static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02004632 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004633 enum nl80211_tdls_operation oper)
4634{
4635 struct brcmf_if *ifp;
4636 struct brcmf_tdls_iovar_le info;
4637 int ret = 0;
4638
4639 ret = brcmf_convert_nl80211_tdls_oper(oper);
4640 if (ret < 0)
4641 return ret;
4642
4643 ifp = netdev_priv(ndev);
4644 memset(&info, 0, sizeof(info));
4645 info.mode = (u8)ret;
4646 if (peer)
4647 memcpy(info.ea, peer, ETH_ALEN);
4648
4649 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4650 &info, sizeof(info));
4651 if (ret < 0)
4652 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4653
4654 return ret;
4655}
4656
Arend van Spriel5b435de2011-10-05 13:19:03 +02004657static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004658 .add_virtual_intf = brcmf_cfg80211_add_iface,
4659 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004660 .change_virtual_intf = brcmf_cfg80211_change_iface,
4661 .scan = brcmf_cfg80211_scan,
4662 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4663 .join_ibss = brcmf_cfg80211_join_ibss,
4664 .leave_ibss = brcmf_cfg80211_leave_ibss,
4665 .get_station = brcmf_cfg80211_get_station,
4666 .set_tx_power = brcmf_cfg80211_set_tx_power,
4667 .get_tx_power = brcmf_cfg80211_get_tx_power,
4668 .add_key = brcmf_cfg80211_add_key,
4669 .del_key = brcmf_cfg80211_del_key,
4670 .get_key = brcmf_cfg80211_get_key,
4671 .set_default_key = brcmf_cfg80211_config_default_key,
4672 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4673 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004674 .connect = brcmf_cfg80211_connect,
4675 .disconnect = brcmf_cfg80211_disconnect,
4676 .suspend = brcmf_cfg80211_suspend,
4677 .resume = brcmf_cfg80211_resume,
4678 .set_pmksa = brcmf_cfg80211_set_pmksa,
4679 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004680 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004681 .start_ap = brcmf_cfg80211_start_ap,
4682 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004683 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004684 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004685 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004686 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4687 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004688 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4689 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4690 .remain_on_channel = brcmf_p2p_remain_on_channel,
4691 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004692 .start_p2p_device = brcmf_p2p_start_device,
4693 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004694 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4695 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004696 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004697};
4698
Arend van Spriel3eacf862012-10-22 13:55:30 -07004699struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004700 enum nl80211_iftype type,
4701 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004702{
Hante Meulemana44aa402014-12-03 21:05:33 +01004703 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004704 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01004705 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004706
Arend van Spriel33a6b152013-02-08 15:53:39 +01004707 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004708 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004709 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4710 if (!vif)
4711 return ERR_PTR(-ENOMEM);
4712
4713 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004714 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004715
Arend van Spriel3eacf862012-10-22 13:55:30 -07004716 vif->pm_block = pm_block;
4717 vif->roam_off = -1;
4718
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004719 brcmf_init_prof(&vif->profile);
4720
Hante Meulemana44aa402014-12-03 21:05:33 +01004721 if (type == NL80211_IFTYPE_AP) {
4722 mbss = false;
4723 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
4724 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
4725 mbss = true;
4726 break;
4727 }
4728 }
4729 vif->mbss = mbss;
4730 }
4731
Arend van Spriel3eacf862012-10-22 13:55:30 -07004732 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004733 return vif;
4734}
4735
Arend van Spriel427dec52014-01-06 12:40:47 +01004736void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004737{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004738 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004739 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004740}
4741
Arend van Spriel9df4d542014-01-06 12:40:49 +01004742void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4743{
4744 struct brcmf_cfg80211_vif *vif;
4745 struct brcmf_if *ifp;
4746
4747 ifp = netdev_priv(ndev);
4748 vif = ifp->vif;
4749
4750 brcmf_free_vif(vif);
4751 free_netdev(ndev);
4752}
4753
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004754static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004755{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004756 u32 event = e->event_code;
4757 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004758
4759 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004760 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004761 return true;
4762 }
4763
4764 return false;
4765}
4766
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004767static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004768{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004769 u32 event = e->event_code;
4770 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004771
Hante Meuleman68ca3952014-02-25 20:30:26 +01004772 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
4773 (event == BRCMF_E_DISASSOC_IND) ||
4774 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004775 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004776 return true;
4777 }
4778 return false;
4779}
4780
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004781static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004782 const struct brcmf_event_msg *e)
4783{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004784 u32 event = e->event_code;
4785 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004786
4787 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004788 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4789 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004790 return true;
4791 }
4792
4793 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004794 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004795 return true;
4796 }
4797
4798 return false;
4799}
4800
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004801static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004802{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004803 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004804
4805 kfree(conn_info->req_ie);
4806 conn_info->req_ie = NULL;
4807 conn_info->req_ie_len = 0;
4808 kfree(conn_info->resp_ie);
4809 conn_info->resp_ie = NULL;
4810 conn_info->resp_ie_len = 0;
4811}
4812
Hante Meuleman89286dc2013-02-08 15:53:46 +01004813static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4814 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004815{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004816 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004817 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004818 u32 req_len;
4819 u32 resp_len;
4820 s32 err = 0;
4821
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004822 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004823
Arend van Sprielac24be62012-10-22 10:36:23 -07004824 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4825 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004826 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004827 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004828 return err;
4829 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004830 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004831 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004832 req_len = le32_to_cpu(assoc_info->req_len);
4833 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004834 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004835 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004836 cfg->extra_buf,
4837 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004838 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004839 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004840 return err;
4841 }
4842 conn_info->req_ie_len = req_len;
4843 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004844 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004845 GFP_KERNEL);
4846 } else {
4847 conn_info->req_ie_len = 0;
4848 conn_info->req_ie = NULL;
4849 }
4850 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004851 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004852 cfg->extra_buf,
4853 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004854 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004855 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004856 return err;
4857 }
4858 conn_info->resp_ie_len = resp_len;
4859 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004860 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004861 GFP_KERNEL);
4862 } else {
4863 conn_info->resp_ie_len = 0;
4864 conn_info->resp_ie = NULL;
4865 }
Arend van Spriel16886732012-12-05 15:26:04 +01004866 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4867 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004868
4869 return err;
4870}
4871
4872static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004873brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004874 struct net_device *ndev,
4875 const struct brcmf_event_msg *e)
4876{
Arend van Sprielc1179032012-10-22 13:55:33 -07004877 struct brcmf_if *ifp = netdev_priv(ndev);
4878 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004879 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4880 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004881 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004882 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004883 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004884 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004885 u32 freq;
4886 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004887 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004888
Arend van Sprield96b8012012-12-05 15:26:02 +01004889 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004890
Hante Meuleman89286dc2013-02-08 15:53:46 +01004891 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004892 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004893 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004894
Franky Lina180b832012-10-10 11:13:09 -07004895 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4896 if (buf == NULL) {
4897 err = -ENOMEM;
4898 goto done;
4899 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004900
Franky Lina180b832012-10-10 11:13:09 -07004901 /* data sent to dongle has to be little endian */
4902 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004903 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004904 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004905
4906 if (err)
4907 goto done;
4908
4909 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004910 ch.chspec = le16_to_cpu(bi->chanspec);
4911 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004912
Franky Lin83cf17a2013-04-11 13:28:50 +02004913 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004914 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4915 else
4916 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4917
Franky Lin83cf17a2013-04-11 13:28:50 +02004918 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004919 notify_channel = ieee80211_get_channel(wiphy, freq);
4920
Franky Lina180b832012-10-10 11:13:09 -07004921done:
4922 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004923 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004924 conn_info->req_ie, conn_info->req_ie_len,
4925 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004926 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004927
Arend van Sprielc1179032012-10-22 13:55:33 -07004928 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004929 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004930 return err;
4931}
4932
4933static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004934brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004935 struct net_device *ndev, const struct brcmf_event_msg *e,
4936 bool completed)
4937{
Arend van Sprielc1179032012-10-22 13:55:33 -07004938 struct brcmf_if *ifp = netdev_priv(ndev);
4939 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004940 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004941
Arend van Sprield96b8012012-12-05 15:26:02 +01004942 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004943
Arend van Sprielc1179032012-10-22 13:55:33 -07004944 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4945 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004946 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004947 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004948 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004949 brcmf_update_bss_info(cfg, ifp);
4950 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4951 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004952 }
4953 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004954 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004955 conn_info->req_ie,
4956 conn_info->req_ie_len,
4957 conn_info->resp_ie,
4958 conn_info->resp_ie_len,
4959 completed ? WLAN_STATUS_SUCCESS :
4960 WLAN_STATUS_AUTH_TIMEOUT,
4961 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004962 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4963 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004964 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004965 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004966 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004967}
4968
4969static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004970brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004971 struct net_device *ndev,
4972 const struct brcmf_event_msg *e, void *data)
4973{
Hante Meulemana44aa402014-12-03 21:05:33 +01004974 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman7ee29602013-02-06 18:40:43 +01004975 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004976 u32 event = e->event_code;
4977 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004978 struct station_info sinfo;
4979
Arend van Spriel16886732012-12-05 15:26:04 +01004980 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004981 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4982 ndev != cfg_to_ndev(cfg)) {
4983 brcmf_dbg(CONN, "AP mode link down\n");
4984 complete(&cfg->vif_disabled);
Hante Meulemana44aa402014-12-03 21:05:33 +01004985 if (ifp->vif->mbss)
Arend van Sprielee6e3a32015-08-26 22:14:55 +02004986 brcmf_remove_interface(ifp);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004987 return 0;
4988 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004989
Hante Meuleman1a873342012-09-27 14:17:54 +02004990 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004991 (reason == BRCMF_E_STATUS_SUCCESS)) {
4992 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004993 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004994 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004995 return -EINVAL;
4996 }
4997 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004998 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004999 generation++;
5000 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005001 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005002 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5003 (event == BRCMF_E_DEAUTH_IND) ||
5004 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005005 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005006 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005007 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005008}
5009
5010static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005011brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005012 const struct brcmf_event_msg *e, void *data)
5013{
Arend van Spriel19937322012-11-05 16:22:32 -08005014 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5015 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005016 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005017 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005018 s32 err = 0;
5019
Hante Meuleman8851cce2014-07-30 13:20:02 +02005020 if ((e->event_code == BRCMF_E_DEAUTH) ||
5021 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5022 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5023 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5024 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5025 }
5026
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005027 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005028 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005029 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005030 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005031 if (brcmf_is_ibssmode(ifp->vif)) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005032 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005033 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005034 wl_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005035 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005036 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5037 &ifp->vif->sme_state);
5038 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5039 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005040 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005041 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005042 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005043 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005044 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005045 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005046 }
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01005047 brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e));
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005048 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005049 if (ndev != cfg_to_ndev(cfg))
5050 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005051 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005052 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005053 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5054 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005055 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005056 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005057 }
5058
5059 return err;
5060}
5061
5062static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005063brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005064 const struct brcmf_event_msg *e, void *data)
5065{
Arend van Spriel19937322012-11-05 16:22:32 -08005066 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005067 u32 event = e->event_code;
5068 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005069
5070 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005071 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005072 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005073 else
Arend van Spriel19937322012-11-05 16:22:32 -08005074 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005075 }
5076
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005077 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005078}
5079
5080static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005081brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005082 const struct brcmf_event_msg *e, void *data)
5083{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005084 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005085 enum nl80211_key_type key_type;
5086
5087 if (flags & BRCMF_EVENT_MSG_GROUP)
5088 key_type = NL80211_KEYTYPE_GROUP;
5089 else
5090 key_type = NL80211_KEYTYPE_PAIRWISE;
5091
Arend van Spriel19937322012-11-05 16:22:32 -08005092 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005093 NULL, GFP_KERNEL);
5094
5095 return 0;
5096}
5097
Arend van Sprield3c0b632013-02-08 15:53:37 +01005098static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5099 const struct brcmf_event_msg *e, void *data)
5100{
5101 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5102 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5103 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5104 struct brcmf_cfg80211_vif *vif;
5105
5106 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
5107 ifevent->action, ifevent->flags, ifevent->ifidx,
5108 ifevent->bssidx);
5109
Arend van Sprield3c0b632013-02-08 15:53:37 +01005110 mutex_lock(&event->vif_event_lock);
5111 event->action = ifevent->action;
5112 vif = event->vif;
5113
5114 switch (ifevent->action) {
5115 case BRCMF_E_IF_ADD:
5116 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005117 if (!cfg->vif_event.vif) {
5118 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005119 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005120 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005121
5122 ifp->vif = vif;
5123 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005124 if (ifp->ndev) {
5125 vif->wdev.netdev = ifp->ndev;
5126 ifp->ndev->ieee80211_ptr = &vif->wdev;
5127 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5128 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005129 mutex_unlock(&event->vif_event_lock);
5130 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005131 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005132
5133 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005134 mutex_unlock(&event->vif_event_lock);
5135 /* event may not be upon user request */
5136 if (brcmf_cfg80211_vif_event_armed(cfg))
5137 wake_up(&event->vif_wq);
5138 return 0;
5139
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005140 case BRCMF_E_IF_CHANGE:
5141 mutex_unlock(&event->vif_event_lock);
5142 wake_up(&event->vif_wq);
5143 return 0;
5144
Arend van Sprield3c0b632013-02-08 15:53:37 +01005145 default:
5146 mutex_unlock(&event->vif_event_lock);
5147 break;
5148 }
5149 return -EINVAL;
5150}
5151
Arend van Spriel5b435de2011-10-05 13:19:03 +02005152static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5153{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005154 conf->frag_threshold = (u32)-1;
5155 conf->rts_threshold = (u32)-1;
5156 conf->retry_short = (u32)-1;
5157 conf->retry_long = (u32)-1;
5158 conf->tx_power = -1;
5159}
5160
Arend van Spriel5c36b992012-11-14 18:46:05 -08005161static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005162{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005163 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5164 brcmf_notify_connect_status);
5165 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5166 brcmf_notify_connect_status);
5167 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5168 brcmf_notify_connect_status);
5169 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5170 brcmf_notify_connect_status);
5171 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5172 brcmf_notify_connect_status);
5173 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5174 brcmf_notify_connect_status);
5175 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5176 brcmf_notify_roaming_status);
5177 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5178 brcmf_notify_mic_status);
5179 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5180 brcmf_notify_connect_status);
5181 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5182 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005183 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5184 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005185 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005186 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005187 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5188 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005189 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5190 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005191 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5192 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005193 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5194 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005195}
5196
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005197static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005198{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005199 kfree(cfg->conf);
5200 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005201 kfree(cfg->escan_ioctl_buf);
5202 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005203 kfree(cfg->extra_buf);
5204 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005205 kfree(cfg->pmk_list);
5206 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005207}
5208
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005209static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005210{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005211 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5212 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005213 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005214 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5215 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02005216 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005217 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5218 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005219 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005220 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
5221 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005222 goto init_priv_mem_out;
5223
5224 return 0;
5225
5226init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005227 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005228
5229 return -ENOMEM;
5230}
5231
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005232static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005233{
5234 s32 err = 0;
5235
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005236 cfg->scan_request = NULL;
5237 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005238 cfg->active_scan = true; /* we do active scan per default */
5239 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005240 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005241 if (err)
5242 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005243 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005244 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005245 brcmf_init_escan(cfg);
5246 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005247 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005248 return err;
5249}
5250
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005251static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005252{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005253 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005254 brcmf_abort_scanning(cfg);
5255 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005256}
5257
Arend van Sprield3c0b632013-02-08 15:53:37 +01005258static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5259{
5260 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005261 mutex_init(&event->vif_event_lock);
5262}
5263
Arend van Spriel5b435de2011-10-05 13:19:03 +02005264static s32
Hante Meuleman68ca3952014-02-25 20:30:26 +01005265brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005266{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005267 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005268 __le32 roamtrigger[2];
5269 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005270
5271 /*
5272 * Setup timeout if Beacons are lost and roam is
5273 * off to report link down
5274 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005275 if (brcmf_roamoff) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005276 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005277 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005278 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005279 goto dongle_rom_out;
5280 }
5281 }
5282
5283 /*
5284 * Enable/Disable built-in roaming to allow supplicant
5285 * to take care of roaming
5286 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005287 brcmf_dbg(INFO, "Internal Roaming = %s\n",
5288 brcmf_roamoff ? "Off" : "On");
5289 err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005290 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005291 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005292 goto dongle_rom_out;
5293 }
5294
Arend van Sprielf588bc02011-10-12 20:51:22 +02005295 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5296 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005297 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005298 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005299 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005300 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005301 goto dongle_rom_out;
5302 }
5303
Arend van Sprielf588bc02011-10-12 20:51:22 +02005304 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5305 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005306 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005307 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005308 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005309 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005310 goto dongle_rom_out;
5311 }
5312
5313dongle_rom_out:
5314 return err;
5315}
5316
5317static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005318brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005319 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005320{
5321 s32 err = 0;
5322
Arend van Sprielac24be62012-10-22 10:36:23 -07005323 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005324 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005325 if (err) {
5326 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005327 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005329 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005330 goto dongle_scantime_out;
5331 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005332 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005333 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005334 if (err) {
5335 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005336 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005337 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005338 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005339 goto dongle_scantime_out;
5340 }
5341
Arend van Sprielac24be62012-10-22 10:36:23 -07005342 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005343 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005344 if (err) {
5345 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005346 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005347 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005348 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005349 goto dongle_scantime_out;
5350 }
5351
5352dongle_scantime_out:
5353 return err;
5354}
5355
Arend van Sprielb48d8912014-07-12 08:49:41 +02005356static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5357 struct brcmu_chan *ch)
5358{
5359 u32 ht40_flag;
5360
5361 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5362 if (ch->sb == BRCMU_CHAN_SB_U) {
5363 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5364 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5365 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5366 } else {
5367 /* It should be one of
5368 * IEEE80211_CHAN_NO_HT40 or
5369 * IEEE80211_CHAN_NO_HT40PLUS
5370 */
5371 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5372 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5373 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5374 }
5375}
5376
5377static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5378 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005379{
5380 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005381 struct ieee80211_supported_band *band;
5382 struct ieee80211_channel *channel;
5383 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005384 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005385 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005386 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005387 u8 *pbuf;
5388 u32 i, j;
5389 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005390 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005391 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005392
5393 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5394
5395 if (pbuf == NULL)
5396 return -ENOMEM;
5397
5398 list = (struct brcmf_chanspec_list *)pbuf;
5399
5400 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5401 BRCMF_DCMD_MEDLEN);
5402 if (err) {
5403 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005404 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005405 }
5406
Arend van Sprielb48d8912014-07-12 08:49:41 +02005407 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel58de92d2015-04-14 20:10:24 +02005408 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5409 if (band)
5410 for (i = 0; i < band->n_channels; i++)
5411 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5412 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5413 if (band)
5414 for (i = 0; i < band->n_channels; i++)
5415 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005416
5417 total = le32_to_cpu(list->count);
5418 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005419 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5420 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005421
Franky Lin83cf17a2013-04-11 13:28:50 +02005422 if (ch.band == BRCMU_CHAN_BAND_2G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005423 band = wiphy->bands[IEEE80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005424 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005425 band = wiphy->bands[IEEE80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005426 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005427 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005428 continue;
5429 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005430 if (!band)
5431 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005432 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005433 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005434 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005435 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005436 ch.bw == BRCMU_CHAN_BW_80)
5437 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005438
5439 channel = band->channels;
5440 index = band->n_channels;
5441 for (j = 0; j < band->n_channels; j++) {
5442 if (channel[j].hw_value == ch.chnum) {
5443 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005444 break;
5445 }
5446 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005447 channel[index].center_freq =
5448 ieee80211_channel_to_frequency(ch.chnum, band->band);
5449 channel[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005450
Arend van Sprielb48d8912014-07-12 08:49:41 +02005451 /* assuming the chanspecs order is HT20,
5452 * HT40 upper, HT40 lower, and VHT80.
5453 */
5454 if (ch.bw == BRCMU_CHAN_BW_80) {
5455 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5456 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5457 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5458 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005459 /* enable the channel and disable other bandwidths
5460 * for now as mentioned order assure they are enabled
5461 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005462 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005463 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5464 IEEE80211_CHAN_NO_80MHZ;
5465 ch.bw = BRCMU_CHAN_BW_20;
5466 cfg->d11inf.encchspec(&ch);
5467 chaninfo = ch.chspec;
5468 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5469 &chaninfo);
5470 if (!err) {
5471 if (chaninfo & WL_CHAN_RADAR)
5472 channel[index].flags |=
5473 (IEEE80211_CHAN_RADAR |
5474 IEEE80211_CHAN_NO_IR);
5475 if (chaninfo & WL_CHAN_PASSIVE)
5476 channel[index].flags |=
5477 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005478 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005479 }
5480 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005481
Arend van Sprielb48d8912014-07-12 08:49:41 +02005482fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005483 kfree(pbuf);
5484 return err;
5485}
5486
Arend van Sprielb48d8912014-07-12 08:49:41 +02005487static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005488{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005489 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5490 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005491 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005492 struct brcmf_chanspec_list *list;
5493 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005494 u32 val;
5495 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005496 struct brcmu_chan ch;
5497 u32 num_chan;
5498 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005499
5500 /* verify support for bw_cap command */
5501 val = WLC_BAND_5G;
5502 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5503
5504 if (!err) {
5505 /* only set 2G bandwidth using bw_cap command */
5506 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5507 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5508 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5509 sizeof(band_bwcap));
5510 } else {
5511 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5512 val = WLC_N_BW_40ALL;
5513 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5514 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005515
5516 if (!err) {
5517 /* update channel info in 2G band */
5518 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5519
5520 if (pbuf == NULL)
5521 return -ENOMEM;
5522
5523 ch.band = BRCMU_CHAN_BAND_2G;
5524 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005525 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005526 ch.chnum = 0;
5527 cfg->d11inf.encchspec(&ch);
5528
5529 /* pass encoded chanspec in query */
5530 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5531
5532 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5533 BRCMF_DCMD_MEDLEN);
5534 if (err) {
5535 brcmf_err("get chanspecs error (%d)\n", err);
5536 kfree(pbuf);
5537 return err;
5538 }
5539
5540 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5541 list = (struct brcmf_chanspec_list *)pbuf;
5542 num_chan = le32_to_cpu(list->count);
5543 for (i = 0; i < num_chan; i++) {
5544 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5545 cfg->d11inf.decchspec(&ch);
5546 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5547 continue;
5548 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5549 continue;
5550 for (j = 0; j < band->n_channels; j++) {
5551 if (band->channels[j].hw_value == ch.chnum)
5552 break;
5553 }
5554 if (WARN_ON(j == band->n_channels))
5555 continue;
5556
5557 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5558 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005559 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005560 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005561 return err;
5562}
5563
Arend van Spriel2375d972014-01-06 12:40:41 +01005564static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5565{
5566 u32 band, mimo_bwcap;
5567 int err;
5568
5569 band = WLC_BAND_2G;
5570 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5571 if (!err) {
5572 bw_cap[IEEE80211_BAND_2GHZ] = band;
5573 band = WLC_BAND_5G;
5574 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5575 if (!err) {
5576 bw_cap[IEEE80211_BAND_5GHZ] = band;
5577 return;
5578 }
5579 WARN_ON(1);
5580 return;
5581 }
5582 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5583 mimo_bwcap = 0;
5584 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5585 if (err)
5586 /* assume 20MHz if firmware does not give a clue */
5587 mimo_bwcap = WLC_N_BW_20ALL;
5588
5589 switch (mimo_bwcap) {
5590 case WLC_N_BW_40ALL:
5591 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5592 /* fall-thru */
5593 case WLC_N_BW_20IN2G_40IN5G:
5594 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5595 /* fall-thru */
5596 case WLC_N_BW_20ALL:
5597 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5598 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5599 break;
5600 default:
5601 brcmf_err("invalid mimo_bw_cap value\n");
5602 }
5603}
Hante Meulemand48200b2013-04-03 12:40:29 +02005604
Arend van Spriel18d6c532014-05-12 10:47:35 +02005605static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5606 u32 bw_cap[2], u32 nchain)
5607{
5608 band->ht_cap.ht_supported = true;
5609 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5610 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5611 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5612 }
5613 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5614 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5615 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5616 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5617 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5618 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5619}
5620
5621static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5622{
5623 u16 mcs_map;
5624 int i;
5625
5626 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5627 mcs_map = (mcs_map << 2) | supp;
5628
5629 return cpu_to_le16(mcs_map);
5630}
5631
5632static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
5633 u32 bw_cap[2], u32 nchain)
5634{
5635 __le16 mcs_map;
5636
5637 /* not allowed in 2.4G band */
5638 if (band->band == IEEE80211_BAND_2GHZ)
5639 return;
5640
5641 band->vht_cap.vht_supported = true;
5642 /* 80MHz is mandatory */
5643 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5644 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5645 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5646 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5647 }
5648 /* all support 256-QAM */
5649 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5650 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5651 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
5652}
5653
Arend van Sprielb48d8912014-07-12 08:49:41 +02005654static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005655{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005656 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07005657 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02005658 u32 nmode = 0;
5659 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005660 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005661 u32 rxchain;
5662 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005663 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005664 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005665 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005666
Arend van Spriel18d6c532014-05-12 10:47:35 +02005667 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02005668 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5669 if (err) {
5670 brcmf_err("nmode error (%d)\n", err);
5671 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005672 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005673 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005674 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5675 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5676 bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005677
Daniel Kim4aca7a12014-02-25 20:30:36 +01005678 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5679 if (err) {
5680 brcmf_err("rxchain error (%d)\n", err);
5681 nchain = 1;
5682 } else {
5683 for (nchain = 0; rxchain; nchain++)
5684 rxchain = rxchain & (rxchain - 1);
5685 }
5686 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5687
Arend van Sprielb48d8912014-07-12 08:49:41 +02005688 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005689 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005690 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02005691 return err;
5692 }
5693
Arend van Sprielb48d8912014-07-12 08:49:41 +02005694 wiphy = cfg_to_wiphy(cfg);
5695 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5696 band = wiphy->bands[i];
5697 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01005698 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005699
Arend van Spriel18d6c532014-05-12 10:47:35 +02005700 if (nmode)
5701 brcmf_update_ht_cap(band, bw_cap, nchain);
5702 if (vhtmode)
5703 brcmf_update_vht_cap(band, bw_cap, nchain);
Hante Meulemand48200b2013-04-03 12:40:29 +02005704 }
5705
Arend van Sprielb48d8912014-07-12 08:49:41 +02005706 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005707}
5708
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005709static const struct ieee80211_txrx_stypes
5710brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5711 [NL80211_IFTYPE_STATION] = {
5712 .tx = 0xffff,
5713 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5714 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5715 },
5716 [NL80211_IFTYPE_P2P_CLIENT] = {
5717 .tx = 0xffff,
5718 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5719 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5720 },
5721 [NL80211_IFTYPE_P2P_GO] = {
5722 .tx = 0xffff,
5723 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
5724 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
5725 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
5726 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
5727 BIT(IEEE80211_STYPE_AUTH >> 4) |
5728 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
5729 BIT(IEEE80211_STYPE_ACTION >> 4)
5730 },
5731 [NL80211_IFTYPE_P2P_DEVICE] = {
5732 .tx = 0xffff,
5733 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5734 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5735 }
5736};
5737
Arend van Spriel0882dda2015-08-20 22:06:03 +02005738/**
5739 * brcmf_setup_ifmodes() - determine interface modes and combinations.
5740 *
5741 * @wiphy: wiphy object.
5742 * @ifp: interface object needed for feat module api.
5743 *
5744 * The interface modes and combinations are determined dynamically here
5745 * based on firmware functionality.
5746 *
5747 * no p2p and no mbss:
5748 *
5749 * #STA <= 1, #AP <= 1, channels = 1, 2 total
5750 *
5751 * no p2p and mbss:
5752 *
5753 * #STA <= 1, #AP <= 1, channels = 1, 2 total
5754 * #AP <= 4, matching BI, channels = 1, 4 total
5755 *
5756 * p2p, no mchan, and mbss:
5757 *
5758 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
5759 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
5760 * #AP <= 4, matching BI, channels = 1, 4 total
5761 *
5762 * p2p, mchan, and mbss:
5763 *
5764 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
5765 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
5766 * #AP <= 4, matching BI, channels = 1, 4 total
5767 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005768static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
5769{
5770 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02005771 struct ieee80211_iface_limit *c0_limits = NULL;
5772 struct ieee80211_iface_limit *p2p_limits = NULL;
5773 struct ieee80211_iface_limit *mbss_limits = NULL;
5774 bool mbss, p2p;
5775 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005776
Arend van Spriel0882dda2015-08-20 22:06:03 +02005777 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
5778 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
5779
5780 n_combos = 1 + !!p2p + !!mbss;
5781 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005782 if (!combo)
5783 goto err;
5784
Arend van Spriel0882dda2015-08-20 22:06:03 +02005785 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
5786 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005787 goto err;
5788
Arend van Spriel0882dda2015-08-20 22:06:03 +02005789 if (p2p) {
5790 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
5791 if (!p2p_limits)
5792 goto err;
5793 }
5794
5795 if (mbss) {
5796 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
5797 if (!mbss_limits)
5798 goto err;
5799 }
5800
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005801 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
5802 BIT(NL80211_IFTYPE_ADHOC) |
5803 BIT(NL80211_IFTYPE_AP);
5804
Arend van Spriel0882dda2015-08-20 22:06:03 +02005805 c = 0;
5806 i = 0;
5807 combo[c].num_different_channels = 1;
5808 c0_limits[i].max = 1;
5809 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
5810 if (p2p) {
5811 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
5812 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005813 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
5814 BIT(NL80211_IFTYPE_P2P_GO) |
5815 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02005816 c0_limits[i].max = 1;
5817 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
5818 c0_limits[i].max = 1;
5819 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
5820 BIT(NL80211_IFTYPE_P2P_GO);
5821 } else {
5822 c0_limits[i].max = 1;
5823 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005824 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02005825 combo[c].max_interfaces = i;
5826 combo[c].n_limits = i;
5827 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005828
Arend van Spriel0882dda2015-08-20 22:06:03 +02005829 if (p2p) {
5830 c++;
5831 i = 0;
5832 combo[c].num_different_channels = 1;
5833 p2p_limits[i].max = 1;
5834 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
5835 p2p_limits[i].max = 1;
5836 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
5837 p2p_limits[i].max = 1;
5838 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
5839 p2p_limits[i].max = 1;
5840 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
5841 combo[c].max_interfaces = i;
5842 combo[c].n_limits = i;
5843 combo[c].limits = p2p_limits;
5844 }
5845
5846 if (mbss) {
5847 c++;
5848 combo[c].beacon_int_infra_match = true;
5849 combo[c].num_different_channels = 1;
5850 mbss_limits[0].max = 4;
5851 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
5852 combo[c].max_interfaces = 4;
5853 combo[c].n_limits = 1;
5854 combo[c].limits = mbss_limits;
5855 }
5856 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005857 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005858 return 0;
5859
5860err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02005861 kfree(c0_limits);
5862 kfree(p2p_limits);
5863 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005864 kfree(combo);
5865 return -ENOMEM;
5866}
5867
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005868static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
5869{
5870 /* scheduled scan settings */
5871 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
5872 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
5873 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5874 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
5875}
5876
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005877#ifdef CONFIG_PM
5878static const struct wiphy_wowlan_support brcmf_wowlan_support = {
5879 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01005880 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
5881 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
5882 .pattern_min_len = 1,
5883 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005884};
5885#endif
5886
5887static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
5888{
5889#ifdef CONFIG_PM
5890 /* wowl settings */
5891 wiphy->wowlan = &brcmf_wowlan_support;
5892#endif
5893}
5894
Arend van Sprielb48d8912014-07-12 08:49:41 +02005895static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005896{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02005897 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005898 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02005899 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005900 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02005901 __le32 bandlist[3];
5902 u32 n_bands;
5903 int err, i;
5904
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005905 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
5906 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5907 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005908
5909 err = brcmf_setup_ifmodes(wiphy, ifp);
5910 if (err)
5911 return err;
5912
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005913 for (i = 0, combo = wiphy->iface_combinations;
5914 i < wiphy->n_iface_combinations; i++, combo++) {
5915 max_interfaces = max(max_interfaces, combo->max_interfaces);
5916 }
5917
5918 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
5919 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02005920 u8 *addr = drvr->addresses[i].addr;
5921
5922 memcpy(addr, drvr->mac, ETH_ALEN);
5923 if (i) {
5924 addr[0] |= BIT(1);
5925 addr[ETH_ALEN - 1] ^= i;
5926 }
5927 }
5928 wiphy->addresses = drvr->addresses;
5929 wiphy->n_addresses = i;
5930
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005931 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
5932 wiphy->cipher_suites = __wl_cipher_suites;
5933 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
5934 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
5935 WIPHY_FLAG_OFFCHAN_TX |
5936 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
5937 WIPHY_FLAG_SUPPORTS_TDLS;
5938 if (!brcmf_roamoff)
5939 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
5940 wiphy->mgmt_stypes = brcmf_txrx_stypes;
5941 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02005942 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
5943 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005944
5945 /* vendor commands/events support */
5946 wiphy->vendor_commands = brcmf_vendor_cmds;
5947 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
5948
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005949 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
5950 brcmf_wiphy_wowl_params(wiphy);
5951
Arend van Spriel58de92d2015-04-14 20:10:24 +02005952 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
5953 sizeof(bandlist));
5954 if (err) {
5955 brcmf_err("could not obtain band info: err=%d\n", err);
5956 return err;
5957 }
5958 /* first entry in bandlist is number of bands */
5959 n_bands = le32_to_cpu(bandlist[0]);
5960 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
5961 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
5962 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
5963 GFP_KERNEL);
5964 if (!band)
5965 return -ENOMEM;
5966
5967 band->channels = kmemdup(&__wl_2ghz_channels,
5968 sizeof(__wl_2ghz_channels),
5969 GFP_KERNEL);
5970 if (!band->channels) {
5971 kfree(band);
5972 return -ENOMEM;
5973 }
5974
5975 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
5976 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
5977 }
5978 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
5979 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
5980 GFP_KERNEL);
5981 if (!band)
5982 return -ENOMEM;
5983
5984 band->channels = kmemdup(&__wl_5ghz_channels,
5985 sizeof(__wl_5ghz_channels),
5986 GFP_KERNEL);
5987 if (!band->channels) {
5988 kfree(band);
5989 return -ENOMEM;
5990 }
5991
5992 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
5993 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
5994 }
5995 }
5996 err = brcmf_setup_wiphybands(wiphy);
5997 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005998}
5999
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006000static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006001{
6002 struct net_device *ndev;
6003 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006004 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006005 s32 power_mode;
6006 s32 err = 0;
6007
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006008 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006009 return err;
6010
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006011 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006012 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006013 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006014
Hante Meuleman40a23292013-01-02 15:22:51 +01006015 /* make sure RF is ready for work */
6016 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6017
6018 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
6019 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006020
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006021 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006022 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006023 if (err)
6024 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006025 brcmf_dbg(INFO, "power save set to %s\n",
6026 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006027
Hante Meuleman68ca3952014-02-25 20:30:26 +01006028 err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006029 if (err)
6030 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006031 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6032 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006033 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006034 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006035
Hante Meulemanb3657452013-05-27 21:09:53 +02006036 brcmf_configure_arp_offload(ifp, true);
6037
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006038 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006039default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006040
6041 return err;
6042
6043}
6044
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006045static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006046{
Arend van Sprielc1179032012-10-22 13:55:33 -07006047 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006048
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006049 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006050}
6051
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006052static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006053{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006054 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006055
Arend van Spriel5b435de2011-10-05 13:19:03 +02006056 /*
6057 * While going down, if associated with AP disassociate
6058 * from AP to save power
6059 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006060 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006061 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006062
6063 /* Make sure WPA_Supplicant receives all the event
6064 generated due to DISASSOC call to the fw to keep
6065 the state fw and WPA_Supplicant state consistent
6066 */
6067 brcmf_delay(500);
6068 }
6069
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006070 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006071 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006072
Arend van Spriel5b435de2011-10-05 13:19:03 +02006073 return 0;
6074}
6075
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006076s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006077{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006078 struct brcmf_if *ifp = netdev_priv(ndev);
6079 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006080 s32 err = 0;
6081
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006082 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006083 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006084 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006085
6086 return err;
6087}
6088
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006089s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006090{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006091 struct brcmf_if *ifp = netdev_priv(ndev);
6092 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006093 s32 err = 0;
6094
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006095 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006096 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006097 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006098
6099 return err;
6100}
6101
Arend van Spriela7965fb2013-04-11 17:08:37 +02006102enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6103{
6104 struct wireless_dev *wdev = &ifp->vif->wdev;
6105
6106 return wdev->iftype;
6107}
6108
Hante Meulemanbfe81972014-10-28 14:56:16 +01006109bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6110 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006111{
6112 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006113
6114 list_for_each_entry(vif, &cfg->vif_list, list) {
6115 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006116 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006117 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006118 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006119}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006120
6121static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6122 u8 action)
6123{
6124 u8 evt_action;
6125
6126 mutex_lock(&event->vif_event_lock);
6127 evt_action = event->action;
6128 mutex_unlock(&event->vif_event_lock);
6129 return evt_action == action;
6130}
6131
6132void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6133 struct brcmf_cfg80211_vif *vif)
6134{
6135 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6136
6137 mutex_lock(&event->vif_event_lock);
6138 event->vif = vif;
6139 event->action = 0;
6140 mutex_unlock(&event->vif_event_lock);
6141}
6142
6143bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6144{
6145 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6146 bool armed;
6147
6148 mutex_lock(&event->vif_event_lock);
6149 armed = event->vif != NULL;
6150 mutex_unlock(&event->vif_event_lock);
6151
6152 return armed;
6153}
6154int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
6155 u8 action, ulong timeout)
6156{
6157 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6158
6159 return wait_event_timeout(event->vif_wq,
6160 vif_event_equals(event, action), timeout);
6161}
6162
Arend van Spriel63db1a42014-12-21 12:43:51 +01006163static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6164 struct regulatory_request *req)
6165{
6166 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6167 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6168 struct brcmf_fil_country_le ccreq;
6169 int i;
6170
6171 brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
6172 req->alpha2[0], req->alpha2[1]);
6173
6174 /* ignore non-ISO3166 country codes */
6175 for (i = 0; i < sizeof(req->alpha2); i++)
6176 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
6177 brcmf_err("not a ISO3166 code\n");
6178 return;
6179 }
6180 memset(&ccreq, 0, sizeof(ccreq));
6181 ccreq.rev = cpu_to_le32(-1);
6182 memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006183 if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
6184 brcmf_err("firmware rejected country setting\n");
6185 return;
6186 }
6187 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006188}
6189
Arend van Sprielb48d8912014-07-12 08:49:41 +02006190static void brcmf_free_wiphy(struct wiphy *wiphy)
6191{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006192 int i;
6193
Arend van Spriel58de92d2015-04-14 20:10:24 +02006194 if (!wiphy)
6195 return;
6196
Arend van Spriel0882dda2015-08-20 22:06:03 +02006197 if (wiphy->iface_combinations) {
6198 for (i = 0; i < wiphy->n_iface_combinations; i++)
6199 kfree(wiphy->iface_combinations[i].limits);
6200 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006201 kfree(wiphy->iface_combinations);
6202 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6203 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6204 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6205 }
6206 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6207 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6208 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6209 }
6210 wiphy_free(wiphy);
6211}
6212
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006213struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
6214 struct device *busdev)
6215{
6216 struct net_device *ndev = drvr->iflist[0]->ndev;
6217 struct brcmf_cfg80211_info *cfg;
6218 struct wiphy *wiphy;
6219 struct brcmf_cfg80211_vif *vif;
6220 struct brcmf_if *ifp;
6221 s32 err = 0;
6222 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006223 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006224
6225 if (!ndev) {
6226 brcmf_err("ndev is invalid\n");
6227 return NULL;
6228 }
6229
6230 ifp = netdev_priv(ndev);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006231 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
6232 if (!wiphy) {
6233 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006234 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006235 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006236 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006237 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006238
6239 cfg = wiphy_priv(wiphy);
6240 cfg->wiphy = wiphy;
6241 cfg->pub = drvr;
6242 init_vif_event(&cfg->vif_event);
6243 INIT_LIST_HEAD(&cfg->vif_list);
6244
6245 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006246 if (IS_ERR(vif))
6247 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006248
6249 vif->ifp = ifp;
6250 vif->wdev.netdev = ndev;
6251 ndev->ieee80211_ptr = &vif->wdev;
6252 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6253
6254 err = wl_init_priv(cfg);
6255 if (err) {
6256 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006257 brcmf_free_vif(vif);
6258 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006259 }
6260 ifp->vif = vif;
6261
Arend van Sprielb48d8912014-07-12 08:49:41 +02006262 /* determine d11 io type before wiphy setup */
6263 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006264 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006265 brcmf_err("Failed to get D11 version (%d)\n", err);
6266 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006267 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006268 cfg->d11inf.io_type = (u8)io_type;
6269 brcmu_d11_attach(&cfg->d11inf);
6270
6271 err = brcmf_setup_wiphy(wiphy, ifp);
6272 if (err < 0)
6273 goto priv_out;
6274
6275 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006276 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006277 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6278 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6279
6280 /* firmware defaults to 40MHz disabled in 2G band. We signal
6281 * cfg80211 here that we do and have it decide we can enable
6282 * it. But first check if device does support 2G operation.
6283 */
6284 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6285 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6286 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6287 }
6288 err = wiphy_register(wiphy);
6289 if (err < 0) {
6290 brcmf_err("Could not register wiphy device (%d)\n", err);
6291 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006292 }
6293
6294 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6295 * setup 40MHz in 2GHz band and enable OBSS scanning.
6296 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006297 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6298 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006299 if (!err)
6300 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6301 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006302 else
6303 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006304 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006305
6306 err = brcmf_p2p_attach(cfg);
6307 if (err) {
6308 brcmf_err("P2P initilisation failed (%d)\n", err);
6309 goto wiphy_unreg_out;
6310 }
6311 err = brcmf_btcoex_attach(cfg);
6312 if (err) {
6313 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6314 brcmf_p2p_detach(&cfg->p2p);
6315 goto wiphy_unreg_out;
6316 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006317
6318 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6319 if (err) {
6320 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6321 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman70b7d942014-07-30 13:20:07 +02006322 } else {
6323 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6324 brcmf_notify_tdls_peer_event);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006325 }
6326
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006327 return cfg;
6328
Arend van Sprielb48d8912014-07-12 08:49:41 +02006329wiphy_unreg_out:
6330 wiphy_unregister(cfg->wiphy);
6331priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006332 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006333 brcmf_free_vif(vif);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006334wiphy_out:
6335 brcmf_free_wiphy(wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006336 return NULL;
6337}
6338
6339void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6340{
6341 if (!cfg)
6342 return;
6343
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006344 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006345 wiphy_unregister(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006346 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006347 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006348}