blob: da24bf0d43f6d2fb564cae9a3441d970decefc02 [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
Arend van Spriel95ef1232015-08-26 22:15:04 +02004750 if (vif)
4751 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01004752 free_netdev(ndev);
4753}
4754
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004755static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004756{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004757 u32 event = e->event_code;
4758 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004759
4760 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004761 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004762 return true;
4763 }
4764
4765 return false;
4766}
4767
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004768static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004769{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004770 u32 event = e->event_code;
4771 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004772
Hante Meuleman68ca3952014-02-25 20:30:26 +01004773 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
4774 (event == BRCMF_E_DISASSOC_IND) ||
4775 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004776 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004777 return true;
4778 }
4779 return false;
4780}
4781
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004782static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004783 const struct brcmf_event_msg *e)
4784{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004785 u32 event = e->event_code;
4786 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004787
4788 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004789 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4790 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004791 return true;
4792 }
4793
4794 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004795 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004796 return true;
4797 }
4798
4799 return false;
4800}
4801
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004802static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004803{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004804 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004805
4806 kfree(conn_info->req_ie);
4807 conn_info->req_ie = NULL;
4808 conn_info->req_ie_len = 0;
4809 kfree(conn_info->resp_ie);
4810 conn_info->resp_ie = NULL;
4811 conn_info->resp_ie_len = 0;
4812}
4813
Hante Meuleman89286dc2013-02-08 15:53:46 +01004814static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4815 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004816{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004817 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004818 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004819 u32 req_len;
4820 u32 resp_len;
4821 s32 err = 0;
4822
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004823 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004824
Arend van Sprielac24be62012-10-22 10:36:23 -07004825 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4826 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004827 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004828 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004829 return err;
4830 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004831 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004832 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004833 req_len = le32_to_cpu(assoc_info->req_len);
4834 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004835 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004836 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004837 cfg->extra_buf,
4838 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004839 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004840 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004841 return err;
4842 }
4843 conn_info->req_ie_len = req_len;
4844 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004845 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004846 GFP_KERNEL);
4847 } else {
4848 conn_info->req_ie_len = 0;
4849 conn_info->req_ie = NULL;
4850 }
4851 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004852 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004853 cfg->extra_buf,
4854 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004855 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004856 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004857 return err;
4858 }
4859 conn_info->resp_ie_len = resp_len;
4860 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004861 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004862 GFP_KERNEL);
4863 } else {
4864 conn_info->resp_ie_len = 0;
4865 conn_info->resp_ie = NULL;
4866 }
Arend van Spriel16886732012-12-05 15:26:04 +01004867 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4868 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004869
4870 return err;
4871}
4872
4873static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004874brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004875 struct net_device *ndev,
4876 const struct brcmf_event_msg *e)
4877{
Arend van Sprielc1179032012-10-22 13:55:33 -07004878 struct brcmf_if *ifp = netdev_priv(ndev);
4879 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004880 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4881 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004882 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004883 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004884 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004885 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004886 u32 freq;
4887 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004888 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004889
Arend van Sprield96b8012012-12-05 15:26:02 +01004890 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004891
Hante Meuleman89286dc2013-02-08 15:53:46 +01004892 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004893 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004894 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004895
Franky Lina180b832012-10-10 11:13:09 -07004896 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4897 if (buf == NULL) {
4898 err = -ENOMEM;
4899 goto done;
4900 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004901
Franky Lina180b832012-10-10 11:13:09 -07004902 /* data sent to dongle has to be little endian */
4903 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004904 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004905 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004906
4907 if (err)
4908 goto done;
4909
4910 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004911 ch.chspec = le16_to_cpu(bi->chanspec);
4912 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004913
Franky Lin83cf17a2013-04-11 13:28:50 +02004914 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004915 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4916 else
4917 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4918
Franky Lin83cf17a2013-04-11 13:28:50 +02004919 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004920 notify_channel = ieee80211_get_channel(wiphy, freq);
4921
Franky Lina180b832012-10-10 11:13:09 -07004922done:
4923 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004924 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004925 conn_info->req_ie, conn_info->req_ie_len,
4926 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004927 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004928
Arend van Sprielc1179032012-10-22 13:55:33 -07004929 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004930 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004931 return err;
4932}
4933
4934static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004935brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004936 struct net_device *ndev, const struct brcmf_event_msg *e,
4937 bool completed)
4938{
Arend van Sprielc1179032012-10-22 13:55:33 -07004939 struct brcmf_if *ifp = netdev_priv(ndev);
4940 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004941 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004942
Arend van Sprield96b8012012-12-05 15:26:02 +01004943 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004944
Arend van Sprielc1179032012-10-22 13:55:33 -07004945 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4946 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004947 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004948 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004949 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004950 brcmf_update_bss_info(cfg, ifp);
4951 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4952 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004953 }
4954 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004955 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004956 conn_info->req_ie,
4957 conn_info->req_ie_len,
4958 conn_info->resp_ie,
4959 conn_info->resp_ie_len,
4960 completed ? WLAN_STATUS_SUCCESS :
4961 WLAN_STATUS_AUTH_TIMEOUT,
4962 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004963 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4964 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004965 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004966 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004967 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004968}
4969
4970static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004971brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004972 struct net_device *ndev,
4973 const struct brcmf_event_msg *e, void *data)
4974{
Hante Meulemana44aa402014-12-03 21:05:33 +01004975 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman7ee29602013-02-06 18:40:43 +01004976 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004977 u32 event = e->event_code;
4978 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004979 struct station_info sinfo;
4980
Arend van Spriel16886732012-12-05 15:26:04 +01004981 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004982 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4983 ndev != cfg_to_ndev(cfg)) {
4984 brcmf_dbg(CONN, "AP mode link down\n");
4985 complete(&cfg->vif_disabled);
Hante Meulemana44aa402014-12-03 21:05:33 +01004986 if (ifp->vif->mbss)
Arend van Sprielee6e3a32015-08-26 22:14:55 +02004987 brcmf_remove_interface(ifp);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004988 return 0;
4989 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004990
Hante Meuleman1a873342012-09-27 14:17:54 +02004991 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004992 (reason == BRCMF_E_STATUS_SUCCESS)) {
4993 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004994 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004995 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004996 return -EINVAL;
4997 }
4998 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004999 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005000 generation++;
5001 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005002 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005003 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5004 (event == BRCMF_E_DEAUTH_IND) ||
5005 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005006 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005007 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005008 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005009}
5010
5011static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005012brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005013 const struct brcmf_event_msg *e, void *data)
5014{
Arend van Spriel19937322012-11-05 16:22:32 -08005015 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5016 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005017 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005018 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005019 s32 err = 0;
5020
Hante Meuleman8851cce2014-07-30 13:20:02 +02005021 if ((e->event_code == BRCMF_E_DEAUTH) ||
5022 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5023 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5024 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5025 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5026 }
5027
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005028 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005029 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005030 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005031 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005032 if (brcmf_is_ibssmode(ifp->vif)) {
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005033 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005034 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005035 wl_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005036 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005037 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5038 &ifp->vif->sme_state);
5039 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5040 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005041 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005042 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005043 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005044 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005045 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005046 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005047 }
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01005048 brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e));
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005049 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005050 if (ndev != cfg_to_ndev(cfg))
5051 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005052 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005053 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005054 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5055 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005056 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005057 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005058 }
5059
5060 return err;
5061}
5062
5063static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005064brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005065 const struct brcmf_event_msg *e, void *data)
5066{
Arend van Spriel19937322012-11-05 16:22:32 -08005067 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005068 u32 event = e->event_code;
5069 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005070
5071 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005072 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005073 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005074 else
Arend van Spriel19937322012-11-05 16:22:32 -08005075 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005076 }
5077
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005078 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005079}
5080
5081static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005082brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005083 const struct brcmf_event_msg *e, void *data)
5084{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005085 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005086 enum nl80211_key_type key_type;
5087
5088 if (flags & BRCMF_EVENT_MSG_GROUP)
5089 key_type = NL80211_KEYTYPE_GROUP;
5090 else
5091 key_type = NL80211_KEYTYPE_PAIRWISE;
5092
Arend van Spriel19937322012-11-05 16:22:32 -08005093 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005094 NULL, GFP_KERNEL);
5095
5096 return 0;
5097}
5098
Arend van Sprield3c0b632013-02-08 15:53:37 +01005099static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5100 const struct brcmf_event_msg *e, void *data)
5101{
5102 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5103 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5104 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5105 struct brcmf_cfg80211_vif *vif;
5106
5107 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
5108 ifevent->action, ifevent->flags, ifevent->ifidx,
5109 ifevent->bssidx);
5110
Arend van Sprield3c0b632013-02-08 15:53:37 +01005111 mutex_lock(&event->vif_event_lock);
5112 event->action = ifevent->action;
5113 vif = event->vif;
5114
5115 switch (ifevent->action) {
5116 case BRCMF_E_IF_ADD:
5117 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005118 if (!cfg->vif_event.vif) {
5119 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005120 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005121 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005122
5123 ifp->vif = vif;
5124 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005125 if (ifp->ndev) {
5126 vif->wdev.netdev = ifp->ndev;
5127 ifp->ndev->ieee80211_ptr = &vif->wdev;
5128 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5129 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005130 mutex_unlock(&event->vif_event_lock);
5131 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005132 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005133
5134 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005135 mutex_unlock(&event->vif_event_lock);
5136 /* event may not be upon user request */
5137 if (brcmf_cfg80211_vif_event_armed(cfg))
5138 wake_up(&event->vif_wq);
5139 return 0;
5140
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005141 case BRCMF_E_IF_CHANGE:
5142 mutex_unlock(&event->vif_event_lock);
5143 wake_up(&event->vif_wq);
5144 return 0;
5145
Arend van Sprield3c0b632013-02-08 15:53:37 +01005146 default:
5147 mutex_unlock(&event->vif_event_lock);
5148 break;
5149 }
5150 return -EINVAL;
5151}
5152
Arend van Spriel5b435de2011-10-05 13:19:03 +02005153static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5154{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005155 conf->frag_threshold = (u32)-1;
5156 conf->rts_threshold = (u32)-1;
5157 conf->retry_short = (u32)-1;
5158 conf->retry_long = (u32)-1;
5159 conf->tx_power = -1;
5160}
5161
Arend van Spriel5c36b992012-11-14 18:46:05 -08005162static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005163{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005164 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5165 brcmf_notify_connect_status);
5166 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5167 brcmf_notify_connect_status);
5168 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5169 brcmf_notify_connect_status);
5170 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5171 brcmf_notify_connect_status);
5172 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5173 brcmf_notify_connect_status);
5174 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5175 brcmf_notify_connect_status);
5176 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5177 brcmf_notify_roaming_status);
5178 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5179 brcmf_notify_mic_status);
5180 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5181 brcmf_notify_connect_status);
5182 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5183 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005184 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5185 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005186 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005187 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005188 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5189 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005190 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5191 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005192 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5193 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005194 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5195 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005196}
5197
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005198static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005199{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005200 kfree(cfg->conf);
5201 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005202 kfree(cfg->escan_ioctl_buf);
5203 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005204 kfree(cfg->extra_buf);
5205 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005206 kfree(cfg->pmk_list);
5207 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005208}
5209
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005210static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005211{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005212 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5213 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005214 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005215 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5216 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02005217 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005218 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5219 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005220 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005221 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
5222 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005223 goto init_priv_mem_out;
5224
5225 return 0;
5226
5227init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005228 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005229
5230 return -ENOMEM;
5231}
5232
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005233static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005234{
5235 s32 err = 0;
5236
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005237 cfg->scan_request = NULL;
5238 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005239 cfg->active_scan = true; /* we do active scan per default */
5240 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005241 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005242 if (err)
5243 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005244 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005245 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005246 brcmf_init_escan(cfg);
5247 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005248 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005249 return err;
5250}
5251
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005252static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005253{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005254 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005255 brcmf_abort_scanning(cfg);
5256 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005257}
5258
Arend van Sprield3c0b632013-02-08 15:53:37 +01005259static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5260{
5261 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005262 mutex_init(&event->vif_event_lock);
5263}
5264
Arend van Spriel5b435de2011-10-05 13:19:03 +02005265static s32
Hante Meuleman68ca3952014-02-25 20:30:26 +01005266brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005267{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005269 __le32 roamtrigger[2];
5270 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005271
5272 /*
5273 * Setup timeout if Beacons are lost and roam is
5274 * off to report link down
5275 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005276 if (brcmf_roamoff) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005277 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005278 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005279 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005280 goto dongle_rom_out;
5281 }
5282 }
5283
5284 /*
5285 * Enable/Disable built-in roaming to allow supplicant
5286 * to take care of roaming
5287 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005288 brcmf_dbg(INFO, "Internal Roaming = %s\n",
5289 brcmf_roamoff ? "Off" : "On");
5290 err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005291 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005292 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293 goto dongle_rom_out;
5294 }
5295
Arend van Sprielf588bc02011-10-12 20:51:22 +02005296 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5297 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005298 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005299 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005300 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005301 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005302 goto dongle_rom_out;
5303 }
5304
Arend van Sprielf588bc02011-10-12 20:51:22 +02005305 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5306 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005307 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005308 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005309 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005310 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005311 goto dongle_rom_out;
5312 }
5313
5314dongle_rom_out:
5315 return err;
5316}
5317
5318static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005319brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005320 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005321{
5322 s32 err = 0;
5323
Arend van Sprielac24be62012-10-22 10:36:23 -07005324 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005325 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005326 if (err) {
5327 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005328 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005329 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005330 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005331 goto dongle_scantime_out;
5332 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005333 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005334 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005335 if (err) {
5336 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005337 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005338 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005339 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005340 goto dongle_scantime_out;
5341 }
5342
Arend van Sprielac24be62012-10-22 10:36:23 -07005343 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005344 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005345 if (err) {
5346 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005347 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005349 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005350 goto dongle_scantime_out;
5351 }
5352
5353dongle_scantime_out:
5354 return err;
5355}
5356
Arend van Sprielb48d8912014-07-12 08:49:41 +02005357static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5358 struct brcmu_chan *ch)
5359{
5360 u32 ht40_flag;
5361
5362 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5363 if (ch->sb == BRCMU_CHAN_SB_U) {
5364 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5365 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5366 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5367 } else {
5368 /* It should be one of
5369 * IEEE80211_CHAN_NO_HT40 or
5370 * IEEE80211_CHAN_NO_HT40PLUS
5371 */
5372 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5373 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5374 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5375 }
5376}
5377
5378static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5379 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005380{
5381 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005382 struct ieee80211_supported_band *band;
5383 struct ieee80211_channel *channel;
5384 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005385 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005386 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005387 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005388 u8 *pbuf;
5389 u32 i, j;
5390 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005391 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005392 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005393
5394 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5395
5396 if (pbuf == NULL)
5397 return -ENOMEM;
5398
5399 list = (struct brcmf_chanspec_list *)pbuf;
5400
5401 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5402 BRCMF_DCMD_MEDLEN);
5403 if (err) {
5404 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005405 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005406 }
5407
Arend van Sprielb48d8912014-07-12 08:49:41 +02005408 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel58de92d2015-04-14 20:10:24 +02005409 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5410 if (band)
5411 for (i = 0; i < band->n_channels; i++)
5412 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5413 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5414 if (band)
5415 for (i = 0; i < band->n_channels; i++)
5416 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005417
5418 total = le32_to_cpu(list->count);
5419 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005420 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5421 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005422
Franky Lin83cf17a2013-04-11 13:28:50 +02005423 if (ch.band == BRCMU_CHAN_BAND_2G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005424 band = wiphy->bands[IEEE80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005425 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005426 band = wiphy->bands[IEEE80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005427 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005428 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005429 continue;
5430 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005431 if (!band)
5432 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005433 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005434 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005435 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005436 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005437 ch.bw == BRCMU_CHAN_BW_80)
5438 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005439
5440 channel = band->channels;
5441 index = band->n_channels;
5442 for (j = 0; j < band->n_channels; j++) {
5443 if (channel[j].hw_value == ch.chnum) {
5444 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005445 break;
5446 }
5447 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005448 channel[index].center_freq =
5449 ieee80211_channel_to_frequency(ch.chnum, band->band);
5450 channel[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005451
Arend van Sprielb48d8912014-07-12 08:49:41 +02005452 /* assuming the chanspecs order is HT20,
5453 * HT40 upper, HT40 lower, and VHT80.
5454 */
5455 if (ch.bw == BRCMU_CHAN_BW_80) {
5456 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5457 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5458 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5459 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005460 /* enable the channel and disable other bandwidths
5461 * for now as mentioned order assure they are enabled
5462 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005463 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005464 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5465 IEEE80211_CHAN_NO_80MHZ;
5466 ch.bw = BRCMU_CHAN_BW_20;
5467 cfg->d11inf.encchspec(&ch);
5468 chaninfo = ch.chspec;
5469 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5470 &chaninfo);
5471 if (!err) {
5472 if (chaninfo & WL_CHAN_RADAR)
5473 channel[index].flags |=
5474 (IEEE80211_CHAN_RADAR |
5475 IEEE80211_CHAN_NO_IR);
5476 if (chaninfo & WL_CHAN_PASSIVE)
5477 channel[index].flags |=
5478 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005479 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005480 }
5481 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005482
Arend van Sprielb48d8912014-07-12 08:49:41 +02005483fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005484 kfree(pbuf);
5485 return err;
5486}
5487
Arend van Sprielb48d8912014-07-12 08:49:41 +02005488static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005489{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005490 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5491 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005492 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005493 struct brcmf_chanspec_list *list;
5494 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005495 u32 val;
5496 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005497 struct brcmu_chan ch;
5498 u32 num_chan;
5499 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005500
5501 /* verify support for bw_cap command */
5502 val = WLC_BAND_5G;
5503 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5504
5505 if (!err) {
5506 /* only set 2G bandwidth using bw_cap command */
5507 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5508 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5509 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5510 sizeof(band_bwcap));
5511 } else {
5512 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5513 val = WLC_N_BW_40ALL;
5514 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5515 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005516
5517 if (!err) {
5518 /* update channel info in 2G band */
5519 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5520
5521 if (pbuf == NULL)
5522 return -ENOMEM;
5523
5524 ch.band = BRCMU_CHAN_BAND_2G;
5525 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005526 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005527 ch.chnum = 0;
5528 cfg->d11inf.encchspec(&ch);
5529
5530 /* pass encoded chanspec in query */
5531 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5532
5533 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5534 BRCMF_DCMD_MEDLEN);
5535 if (err) {
5536 brcmf_err("get chanspecs error (%d)\n", err);
5537 kfree(pbuf);
5538 return err;
5539 }
5540
5541 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5542 list = (struct brcmf_chanspec_list *)pbuf;
5543 num_chan = le32_to_cpu(list->count);
5544 for (i = 0; i < num_chan; i++) {
5545 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5546 cfg->d11inf.decchspec(&ch);
5547 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5548 continue;
5549 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5550 continue;
5551 for (j = 0; j < band->n_channels; j++) {
5552 if (band->channels[j].hw_value == ch.chnum)
5553 break;
5554 }
5555 if (WARN_ON(j == band->n_channels))
5556 continue;
5557
5558 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5559 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005560 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005561 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005562 return err;
5563}
5564
Arend van Spriel2375d972014-01-06 12:40:41 +01005565static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5566{
5567 u32 band, mimo_bwcap;
5568 int err;
5569
5570 band = WLC_BAND_2G;
5571 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5572 if (!err) {
5573 bw_cap[IEEE80211_BAND_2GHZ] = band;
5574 band = WLC_BAND_5G;
5575 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5576 if (!err) {
5577 bw_cap[IEEE80211_BAND_5GHZ] = band;
5578 return;
5579 }
5580 WARN_ON(1);
5581 return;
5582 }
5583 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5584 mimo_bwcap = 0;
5585 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5586 if (err)
5587 /* assume 20MHz if firmware does not give a clue */
5588 mimo_bwcap = WLC_N_BW_20ALL;
5589
5590 switch (mimo_bwcap) {
5591 case WLC_N_BW_40ALL:
5592 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5593 /* fall-thru */
5594 case WLC_N_BW_20IN2G_40IN5G:
5595 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5596 /* fall-thru */
5597 case WLC_N_BW_20ALL:
5598 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5599 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5600 break;
5601 default:
5602 brcmf_err("invalid mimo_bw_cap value\n");
5603 }
5604}
Hante Meulemand48200b2013-04-03 12:40:29 +02005605
Arend van Spriel18d6c532014-05-12 10:47:35 +02005606static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5607 u32 bw_cap[2], u32 nchain)
5608{
5609 band->ht_cap.ht_supported = true;
5610 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5611 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5612 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5613 }
5614 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5615 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5616 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5617 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5618 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5619 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5620}
5621
5622static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5623{
5624 u16 mcs_map;
5625 int i;
5626
5627 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5628 mcs_map = (mcs_map << 2) | supp;
5629
5630 return cpu_to_le16(mcs_map);
5631}
5632
5633static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
5634 u32 bw_cap[2], u32 nchain)
5635{
5636 __le16 mcs_map;
5637
5638 /* not allowed in 2.4G band */
5639 if (band->band == IEEE80211_BAND_2GHZ)
5640 return;
5641
5642 band->vht_cap.vht_supported = true;
5643 /* 80MHz is mandatory */
5644 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5645 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5646 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5647 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5648 }
5649 /* all support 256-QAM */
5650 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5651 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5652 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
5653}
5654
Arend van Sprielb48d8912014-07-12 08:49:41 +02005655static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005656{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005657 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07005658 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02005659 u32 nmode = 0;
5660 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005661 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005662 u32 rxchain;
5663 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005664 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005665 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005666 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005667
Arend van Spriel18d6c532014-05-12 10:47:35 +02005668 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02005669 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5670 if (err) {
5671 brcmf_err("nmode error (%d)\n", err);
5672 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005673 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005674 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005675 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5676 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5677 bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005678
Daniel Kim4aca7a12014-02-25 20:30:36 +01005679 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5680 if (err) {
5681 brcmf_err("rxchain error (%d)\n", err);
5682 nchain = 1;
5683 } else {
5684 for (nchain = 0; rxchain; nchain++)
5685 rxchain = rxchain & (rxchain - 1);
5686 }
5687 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5688
Arend van Sprielb48d8912014-07-12 08:49:41 +02005689 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005690 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005691 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02005692 return err;
5693 }
5694
Arend van Sprielb48d8912014-07-12 08:49:41 +02005695 wiphy = cfg_to_wiphy(cfg);
5696 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5697 band = wiphy->bands[i];
5698 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01005699 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005700
Arend van Spriel18d6c532014-05-12 10:47:35 +02005701 if (nmode)
5702 brcmf_update_ht_cap(band, bw_cap, nchain);
5703 if (vhtmode)
5704 brcmf_update_vht_cap(band, bw_cap, nchain);
Hante Meulemand48200b2013-04-03 12:40:29 +02005705 }
5706
Arend van Sprielb48d8912014-07-12 08:49:41 +02005707 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005708}
5709
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005710static const struct ieee80211_txrx_stypes
5711brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5712 [NL80211_IFTYPE_STATION] = {
5713 .tx = 0xffff,
5714 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5715 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5716 },
5717 [NL80211_IFTYPE_P2P_CLIENT] = {
5718 .tx = 0xffff,
5719 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5720 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5721 },
5722 [NL80211_IFTYPE_P2P_GO] = {
5723 .tx = 0xffff,
5724 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
5725 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
5726 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
5727 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
5728 BIT(IEEE80211_STYPE_AUTH >> 4) |
5729 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
5730 BIT(IEEE80211_STYPE_ACTION >> 4)
5731 },
5732 [NL80211_IFTYPE_P2P_DEVICE] = {
5733 .tx = 0xffff,
5734 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5735 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5736 }
5737};
5738
Arend van Spriel0882dda2015-08-20 22:06:03 +02005739/**
5740 * brcmf_setup_ifmodes() - determine interface modes and combinations.
5741 *
5742 * @wiphy: wiphy object.
5743 * @ifp: interface object needed for feat module api.
5744 *
5745 * The interface modes and combinations are determined dynamically here
5746 * based on firmware functionality.
5747 *
5748 * no p2p and no mbss:
5749 *
5750 * #STA <= 1, #AP <= 1, channels = 1, 2 total
5751 *
5752 * no p2p and mbss:
5753 *
5754 * #STA <= 1, #AP <= 1, channels = 1, 2 total
5755 * #AP <= 4, matching BI, channels = 1, 4 total
5756 *
5757 * p2p, no mchan, and mbss:
5758 *
5759 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
5760 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
5761 * #AP <= 4, matching BI, channels = 1, 4 total
5762 *
5763 * p2p, mchan, and mbss:
5764 *
5765 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
5766 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
5767 * #AP <= 4, matching BI, channels = 1, 4 total
5768 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005769static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
5770{
5771 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02005772 struct ieee80211_iface_limit *c0_limits = NULL;
5773 struct ieee80211_iface_limit *p2p_limits = NULL;
5774 struct ieee80211_iface_limit *mbss_limits = NULL;
5775 bool mbss, p2p;
5776 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005777
Arend van Spriel0882dda2015-08-20 22:06:03 +02005778 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
5779 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
5780
5781 n_combos = 1 + !!p2p + !!mbss;
5782 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005783 if (!combo)
5784 goto err;
5785
Arend van Spriel0882dda2015-08-20 22:06:03 +02005786 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
5787 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005788 goto err;
5789
Arend van Spriel0882dda2015-08-20 22:06:03 +02005790 if (p2p) {
5791 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
5792 if (!p2p_limits)
5793 goto err;
5794 }
5795
5796 if (mbss) {
5797 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
5798 if (!mbss_limits)
5799 goto err;
5800 }
5801
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005802 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
5803 BIT(NL80211_IFTYPE_ADHOC) |
5804 BIT(NL80211_IFTYPE_AP);
5805
Arend van Spriel0882dda2015-08-20 22:06:03 +02005806 c = 0;
5807 i = 0;
5808 combo[c].num_different_channels = 1;
5809 c0_limits[i].max = 1;
5810 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
5811 if (p2p) {
5812 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
5813 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005814 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
5815 BIT(NL80211_IFTYPE_P2P_GO) |
5816 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02005817 c0_limits[i].max = 1;
5818 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
5819 c0_limits[i].max = 1;
5820 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
5821 BIT(NL80211_IFTYPE_P2P_GO);
5822 } else {
5823 c0_limits[i].max = 1;
5824 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005825 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02005826 combo[c].max_interfaces = i;
5827 combo[c].n_limits = i;
5828 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005829
Arend van Spriel0882dda2015-08-20 22:06:03 +02005830 if (p2p) {
5831 c++;
5832 i = 0;
5833 combo[c].num_different_channels = 1;
5834 p2p_limits[i].max = 1;
5835 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
5836 p2p_limits[i].max = 1;
5837 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
5838 p2p_limits[i].max = 1;
5839 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
5840 p2p_limits[i].max = 1;
5841 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
5842 combo[c].max_interfaces = i;
5843 combo[c].n_limits = i;
5844 combo[c].limits = p2p_limits;
5845 }
5846
5847 if (mbss) {
5848 c++;
5849 combo[c].beacon_int_infra_match = true;
5850 combo[c].num_different_channels = 1;
5851 mbss_limits[0].max = 4;
5852 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
5853 combo[c].max_interfaces = 4;
5854 combo[c].n_limits = 1;
5855 combo[c].limits = mbss_limits;
5856 }
5857 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005858 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005859 return 0;
5860
5861err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02005862 kfree(c0_limits);
5863 kfree(p2p_limits);
5864 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005865 kfree(combo);
5866 return -ENOMEM;
5867}
5868
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005869static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
5870{
5871 /* scheduled scan settings */
5872 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
5873 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
5874 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5875 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
5876}
5877
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005878#ifdef CONFIG_PM
5879static const struct wiphy_wowlan_support brcmf_wowlan_support = {
5880 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01005881 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
5882 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
5883 .pattern_min_len = 1,
5884 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005885};
5886#endif
5887
5888static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
5889{
5890#ifdef CONFIG_PM
5891 /* wowl settings */
5892 wiphy->wowlan = &brcmf_wowlan_support;
5893#endif
5894}
5895
Arend van Sprielb48d8912014-07-12 08:49:41 +02005896static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005897{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02005898 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005899 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02005900 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005901 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02005902 __le32 bandlist[3];
5903 u32 n_bands;
5904 int err, i;
5905
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005906 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
5907 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
5908 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02005909
5910 err = brcmf_setup_ifmodes(wiphy, ifp);
5911 if (err)
5912 return err;
5913
Rafał Miłecki50f32e22015-08-20 00:16:42 +02005914 for (i = 0, combo = wiphy->iface_combinations;
5915 i < wiphy->n_iface_combinations; i++, combo++) {
5916 max_interfaces = max(max_interfaces, combo->max_interfaces);
5917 }
5918
5919 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
5920 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02005921 u8 *addr = drvr->addresses[i].addr;
5922
5923 memcpy(addr, drvr->mac, ETH_ALEN);
5924 if (i) {
5925 addr[0] |= BIT(1);
5926 addr[ETH_ALEN - 1] ^= i;
5927 }
5928 }
5929 wiphy->addresses = drvr->addresses;
5930 wiphy->n_addresses = i;
5931
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005932 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
5933 wiphy->cipher_suites = __wl_cipher_suites;
5934 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
5935 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
5936 WIPHY_FLAG_OFFCHAN_TX |
5937 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
5938 WIPHY_FLAG_SUPPORTS_TDLS;
5939 if (!brcmf_roamoff)
5940 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
5941 wiphy->mgmt_stypes = brcmf_txrx_stypes;
5942 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02005943 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
5944 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005945
5946 /* vendor commands/events support */
5947 wiphy->vendor_commands = brcmf_vendor_cmds;
5948 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
5949
Hante Meuleman4eb3af72014-09-30 10:23:18 +02005950 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
5951 brcmf_wiphy_wowl_params(wiphy);
5952
Arend van Spriel58de92d2015-04-14 20:10:24 +02005953 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
5954 sizeof(bandlist));
5955 if (err) {
5956 brcmf_err("could not obtain band info: err=%d\n", err);
5957 return err;
5958 }
5959 /* first entry in bandlist is number of bands */
5960 n_bands = le32_to_cpu(bandlist[0]);
5961 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
5962 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
5963 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
5964 GFP_KERNEL);
5965 if (!band)
5966 return -ENOMEM;
5967
5968 band->channels = kmemdup(&__wl_2ghz_channels,
5969 sizeof(__wl_2ghz_channels),
5970 GFP_KERNEL);
5971 if (!band->channels) {
5972 kfree(band);
5973 return -ENOMEM;
5974 }
5975
5976 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
5977 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
5978 }
5979 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
5980 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
5981 GFP_KERNEL);
5982 if (!band)
5983 return -ENOMEM;
5984
5985 band->channels = kmemdup(&__wl_5ghz_channels,
5986 sizeof(__wl_5ghz_channels),
5987 GFP_KERNEL);
5988 if (!band->channels) {
5989 kfree(band);
5990 return -ENOMEM;
5991 }
5992
5993 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
5994 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
5995 }
5996 }
5997 err = brcmf_setup_wiphybands(wiphy);
5998 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005999}
6000
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006001static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006002{
6003 struct net_device *ndev;
6004 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006005 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006006 s32 power_mode;
6007 s32 err = 0;
6008
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006009 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006010 return err;
6011
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006012 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006013 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006014 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006015
Hante Meuleman40a23292013-01-02 15:22:51 +01006016 /* make sure RF is ready for work */
6017 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6018
6019 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
6020 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006021
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006022 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006023 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006024 if (err)
6025 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006026 brcmf_dbg(INFO, "power save set to %s\n",
6027 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006028
Hante Meuleman68ca3952014-02-25 20:30:26 +01006029 err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006030 if (err)
6031 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006032 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6033 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006034 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006035 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006036
Hante Meulemanb3657452013-05-27 21:09:53 +02006037 brcmf_configure_arp_offload(ifp, true);
6038
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006039 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006040default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006041
6042 return err;
6043
6044}
6045
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006046static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006047{
Arend van Sprielc1179032012-10-22 13:55:33 -07006048 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006049
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006050 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006051}
6052
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006053static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006054{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006055 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006056
Arend van Spriel5b435de2011-10-05 13:19:03 +02006057 /*
6058 * While going down, if associated with AP disassociate
6059 * from AP to save power
6060 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006061 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006062 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006063
6064 /* Make sure WPA_Supplicant receives all the event
6065 generated due to DISASSOC call to the fw to keep
6066 the state fw and WPA_Supplicant state consistent
6067 */
6068 brcmf_delay(500);
6069 }
6070
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006071 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006072 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006073
Arend van Spriel5b435de2011-10-05 13:19:03 +02006074 return 0;
6075}
6076
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006077s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006078{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006079 struct brcmf_if *ifp = netdev_priv(ndev);
6080 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006081 s32 err = 0;
6082
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006083 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006084 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006085 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006086
6087 return err;
6088}
6089
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006090s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006091{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006092 struct brcmf_if *ifp = netdev_priv(ndev);
6093 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006094 s32 err = 0;
6095
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006096 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006097 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006098 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006099
6100 return err;
6101}
6102
Arend van Spriela7965fb2013-04-11 17:08:37 +02006103enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6104{
6105 struct wireless_dev *wdev = &ifp->vif->wdev;
6106
6107 return wdev->iftype;
6108}
6109
Hante Meulemanbfe81972014-10-28 14:56:16 +01006110bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6111 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006112{
6113 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006114
6115 list_for_each_entry(vif, &cfg->vif_list, list) {
6116 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006117 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006118 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006119 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006120}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006121
6122static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6123 u8 action)
6124{
6125 u8 evt_action;
6126
6127 mutex_lock(&event->vif_event_lock);
6128 evt_action = event->action;
6129 mutex_unlock(&event->vif_event_lock);
6130 return evt_action == action;
6131}
6132
6133void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6134 struct brcmf_cfg80211_vif *vif)
6135{
6136 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6137
6138 mutex_lock(&event->vif_event_lock);
6139 event->vif = vif;
6140 event->action = 0;
6141 mutex_unlock(&event->vif_event_lock);
6142}
6143
6144bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6145{
6146 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6147 bool armed;
6148
6149 mutex_lock(&event->vif_event_lock);
6150 armed = event->vif != NULL;
6151 mutex_unlock(&event->vif_event_lock);
6152
6153 return armed;
6154}
6155int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
6156 u8 action, ulong timeout)
6157{
6158 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6159
6160 return wait_event_timeout(event->vif_wq,
6161 vif_event_equals(event, action), timeout);
6162}
6163
Arend van Spriel63db1a42014-12-21 12:43:51 +01006164static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6165 struct regulatory_request *req)
6166{
6167 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6168 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6169 struct brcmf_fil_country_le ccreq;
6170 int i;
6171
6172 brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
6173 req->alpha2[0], req->alpha2[1]);
6174
6175 /* ignore non-ISO3166 country codes */
6176 for (i = 0; i < sizeof(req->alpha2); i++)
6177 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
6178 brcmf_err("not a ISO3166 code\n");
6179 return;
6180 }
6181 memset(&ccreq, 0, sizeof(ccreq));
6182 ccreq.rev = cpu_to_le32(-1);
6183 memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006184 if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
6185 brcmf_err("firmware rejected country setting\n");
6186 return;
6187 }
6188 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006189}
6190
Arend van Sprielb48d8912014-07-12 08:49:41 +02006191static void brcmf_free_wiphy(struct wiphy *wiphy)
6192{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006193 int i;
6194
Arend van Spriel58de92d2015-04-14 20:10:24 +02006195 if (!wiphy)
6196 return;
6197
Arend van Spriel0882dda2015-08-20 22:06:03 +02006198 if (wiphy->iface_combinations) {
6199 for (i = 0; i < wiphy->n_iface_combinations; i++)
6200 kfree(wiphy->iface_combinations[i].limits);
6201 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006202 kfree(wiphy->iface_combinations);
6203 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6204 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6205 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6206 }
6207 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6208 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6209 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6210 }
6211 wiphy_free(wiphy);
6212}
6213
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006214struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
6215 struct device *busdev)
6216{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006217 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006218 struct brcmf_cfg80211_info *cfg;
6219 struct wiphy *wiphy;
6220 struct brcmf_cfg80211_vif *vif;
6221 struct brcmf_if *ifp;
6222 s32 err = 0;
6223 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006224 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006225
6226 if (!ndev) {
6227 brcmf_err("ndev is invalid\n");
6228 return NULL;
6229 }
6230
6231 ifp = netdev_priv(ndev);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006232 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
6233 if (!wiphy) {
6234 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006235 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006236 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006237 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006238 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006239
6240 cfg = wiphy_priv(wiphy);
6241 cfg->wiphy = wiphy;
6242 cfg->pub = drvr;
6243 init_vif_event(&cfg->vif_event);
6244 INIT_LIST_HEAD(&cfg->vif_list);
6245
6246 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006247 if (IS_ERR(vif))
6248 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006249
6250 vif->ifp = ifp;
6251 vif->wdev.netdev = ndev;
6252 ndev->ieee80211_ptr = &vif->wdev;
6253 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6254
6255 err = wl_init_priv(cfg);
6256 if (err) {
6257 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006258 brcmf_free_vif(vif);
6259 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006260 }
6261 ifp->vif = vif;
6262
Arend van Sprielb48d8912014-07-12 08:49:41 +02006263 /* determine d11 io type before wiphy setup */
6264 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006265 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006266 brcmf_err("Failed to get D11 version (%d)\n", err);
6267 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006268 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006269 cfg->d11inf.io_type = (u8)io_type;
6270 brcmu_d11_attach(&cfg->d11inf);
6271
6272 err = brcmf_setup_wiphy(wiphy, ifp);
6273 if (err < 0)
6274 goto priv_out;
6275
6276 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006277 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006278 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6279 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6280
6281 /* firmware defaults to 40MHz disabled in 2G band. We signal
6282 * cfg80211 here that we do and have it decide we can enable
6283 * it. But first check if device does support 2G operation.
6284 */
6285 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6286 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6287 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6288 }
6289 err = wiphy_register(wiphy);
6290 if (err < 0) {
6291 brcmf_err("Could not register wiphy device (%d)\n", err);
6292 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006293 }
6294
6295 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6296 * setup 40MHz in 2GHz band and enable OBSS scanning.
6297 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006298 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6299 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006300 if (!err)
6301 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6302 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006303 else
6304 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006305 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006306
6307 err = brcmf_p2p_attach(cfg);
6308 if (err) {
6309 brcmf_err("P2P initilisation failed (%d)\n", err);
6310 goto wiphy_unreg_out;
6311 }
6312 err = brcmf_btcoex_attach(cfg);
6313 if (err) {
6314 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6315 brcmf_p2p_detach(&cfg->p2p);
6316 goto wiphy_unreg_out;
6317 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006318
6319 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6320 if (err) {
6321 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6322 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman70b7d942014-07-30 13:20:07 +02006323 } else {
6324 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6325 brcmf_notify_tdls_peer_event);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006326 }
6327
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006328 return cfg;
6329
Arend van Sprielb48d8912014-07-12 08:49:41 +02006330wiphy_unreg_out:
6331 wiphy_unregister(cfg->wiphy);
6332priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006333 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006334 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006335 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006336wiphy_out:
6337 brcmf_free_wiphy(wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006338 return NULL;
6339}
6340
6341void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6342{
6343 if (!cfg)
6344 return;
6345
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006346 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006347 wiphy_unregister(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006348 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006349 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006350}