blob: 13ca3eb2462b18f7d85e6a6534cd9382928fc1f1 [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"
Arend Van Sprielac551362016-11-23 10:25:22 +000035#include "pno.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010036#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020037#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070038#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020039#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020040#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010041#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010042#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020043
Arend van Spriele5806072012-09-19 22:21:08 +020044#define BRCMF_SCAN_IE_LEN_MAX 2048
Arend van Spriele5806072012-09-19 22:21:08 +020045
Hante Meuleman1a873342012-09-27 14:17:54 +020046#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
47#define WPA_OUI_TYPE 1
48#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
49#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010050#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020051
52#define VS_IE_FIXED_HDR_LEN 6
53#define WPA_IE_VERSION_LEN 2
54#define WPA_IE_MIN_OUI_LEN 4
55#define WPA_IE_SUITE_COUNT_LEN 2
56
57#define WPA_CIPHER_NONE 0 /* None */
58#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
59#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
60#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
61#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
62
63#define RSN_AKM_NONE 0 /* None (IBSS) */
64#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
65#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010066#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
67#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020068#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010069#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
70#define RSN_CAP_MFPR_MASK BIT(6)
71#define RSN_CAP_MFPC_MASK BIT(7)
72#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020073
74#define VNDR_IE_CMD_LEN 4 /* length of the set command
75 * string :"add", "del" (+ NUL)
76 */
77#define VNDR_IE_COUNT_OFFSET 4
78#define VNDR_IE_PKTFLAG_OFFSET 8
79#define VNDR_IE_VSIE_OFFSET 12
80#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010081#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
84#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020085
Hante Meuleman89286dc2013-02-08 15:53:46 +010086#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
87#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
88#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
89
Hante Meuleman1678ba82015-12-10 13:43:00 +010090#define BRCMF_SCAN_CHANNEL_TIME 40
91#define BRCMF_SCAN_UNASSOC_TIME 40
92#define BRCMF_SCAN_PASSIVE_TIME 120
93
Hante Meuleman3021ad92016-01-05 11:05:45 +010094#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
95
Arend van Spriel5b435de2011-10-05 13:19:03 +020096#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
97 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
98
Arend van Sprielce81e312012-10-22 13:55:37 -070099static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200100{
Arend van Sprielc1179032012-10-22 13:55:33 -0700101 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100102 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
103 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200104 return false;
105 }
106 return true;
107}
108
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
110#define RATETAB_ENT(_rateid, _flags) \
111 { \
112 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
113 .hw_value = (_rateid), \
114 .flags = (_flags), \
115 }
116
117static struct ieee80211_rate __wl_rates[] = {
118 RATETAB_ENT(BRCM_RATE_1M, 0),
119 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
120 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
121 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
122 RATETAB_ENT(BRCM_RATE_6M, 0),
123 RATETAB_ENT(BRCM_RATE_9M, 0),
124 RATETAB_ENT(BRCM_RATE_12M, 0),
125 RATETAB_ENT(BRCM_RATE_18M, 0),
126 RATETAB_ENT(BRCM_RATE_24M, 0),
127 RATETAB_ENT(BRCM_RATE_36M, 0),
128 RATETAB_ENT(BRCM_RATE_48M, 0),
129 RATETAB_ENT(BRCM_RATE_54M, 0),
130};
131
Arend van Spriel5b435de2011-10-05 13:19:03 +0200132#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200133#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
134#define wl_a_rates (__wl_rates + 4)
135#define wl_a_rates_size (wl_g_rates_size - 4)
136
137#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200138 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200139 .center_freq = (_freq), \
140 .hw_value = (_channel), \
141 .flags = IEEE80211_CHAN_DISABLED, \
142 .max_antenna_gain = 0, \
143 .max_power = 30, \
144}
145
146#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200147 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200148 .center_freq = 5000 + (5 * (_channel)), \
149 .hw_value = (_channel), \
150 .flags = IEEE80211_CHAN_DISABLED, \
151 .max_antenna_gain = 0, \
152 .max_power = 30, \
153}
154
155static struct ieee80211_channel __wl_2ghz_channels[] = {
156 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
157 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
158 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
159 CHAN2G(13, 2472), CHAN2G(14, 2484)
160};
161
162static struct ieee80211_channel __wl_5ghz_channels[] = {
163 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
164 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
165 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
166 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
167 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
168 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
169};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200170
Arend van Sprielb48d8912014-07-12 08:49:41 +0200171/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200172 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200173 */
174static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200175 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200176 .bitrates = wl_g_rates,
177 .n_bitrates = wl_g_rates_size,
178};
179
Arend van Spriel58de92d2015-04-14 20:10:24 +0200180static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200181 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200182 .bitrates = wl_a_rates,
183 .n_bitrates = wl_a_rates_size,
184};
185
Hante Meulemand48200b2013-04-03 12:40:29 +0200186/* This is to override regulatory domains defined in cfg80211 module (reg.c)
187 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200188 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
189 * With respect to these flags, wpa_supplicant doesn't * start p2p
190 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200191 * domain are to be done here.
192 */
193static const struct ieee80211_regdomain brcmf_regdom = {
194 .n_reg_rules = 4,
195 .alpha2 = "99",
196 .reg_rules = {
197 /* IEEE 802.11b/g, channels 1..11 */
198 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
199 /* If any */
200 /* IEEE 802.11 channel 14 - Only JP enables
201 * this and for 802.11b only
202 */
203 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
204 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200205 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200206 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200207 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200208};
209
Hante Meuleman240d61a2016-02-17 11:27:10 +0100210/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
211 * are supported. A pointer to this array and the number of entries is passed
212 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
213 * So the cipher suite AES_CMAC has to be the last one in the array, and when
214 * device does not support MFP then the number of suites will be decreased by 1
215 */
216static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200217 WLAN_CIPHER_SUITE_WEP40,
218 WLAN_CIPHER_SUITE_WEP104,
219 WLAN_CIPHER_SUITE_TKIP,
220 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100221 /* Keep as last entry: */
222 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200223};
224
Hante Meuleman1a873342012-09-27 14:17:54 +0200225/* Vendor specific ie. id = 221, oui and type defines exact ie */
226struct brcmf_vs_tlv {
227 u8 id;
228 u8 len;
229 u8 oui[3];
230 u8 oui_type;
231};
232
233struct parsed_vndr_ie_info {
234 u8 *ie_ptr;
235 u32 ie_len; /* total length including id & length field */
236 struct brcmf_vs_tlv vndrie;
237};
238
239struct parsed_vndr_ies {
240 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100241 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200242};
243
Arend van Spriel7705ba62016-04-17 16:44:58 +0200244static u8 nl80211_band_to_fwil(enum nl80211_band band)
245{
246 switch (band) {
247 case NL80211_BAND_2GHZ:
248 return WLC_BAND_2G;
249 case NL80211_BAND_5GHZ:
250 return WLC_BAND_5G;
251 default:
252 WARN_ON(1);
253 break;
254 }
255 return 0;
256}
257
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200258static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
259 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200260{
261 struct brcmu_chan ch_inf;
262 s32 primary_offset;
263
264 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
265 ch->chan->center_freq, ch->center_freq1, ch->width);
266 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100267 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200268 switch (ch->width) {
269 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100270 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200271 ch_inf.bw = BRCMU_CHAN_BW_20;
272 WARN_ON(primary_offset != 0);
273 break;
274 case NL80211_CHAN_WIDTH_40:
275 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100276 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200277 ch_inf.sb = BRCMU_CHAN_SB_U;
278 else
279 ch_inf.sb = BRCMU_CHAN_SB_L;
280 break;
281 case NL80211_CHAN_WIDTH_80:
282 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100283 if (primary_offset == -30)
284 ch_inf.sb = BRCMU_CHAN_SB_LL;
285 else if (primary_offset == -10)
286 ch_inf.sb = BRCMU_CHAN_SB_LU;
287 else if (primary_offset == 10)
288 ch_inf.sb = BRCMU_CHAN_SB_UL;
289 else
290 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200291 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100292 case NL80211_CHAN_WIDTH_80P80:
293 case NL80211_CHAN_WIDTH_160:
294 case NL80211_CHAN_WIDTH_5:
295 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200296 default:
297 WARN_ON_ONCE(1);
298 }
299 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200300 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200301 ch_inf.band = BRCMU_CHAN_BAND_2G;
302 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200303 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200304 ch_inf.band = BRCMU_CHAN_BAND_5G;
305 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200306 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200307 default:
308 WARN_ON_ONCE(1);
309 }
310 d11inf->encchspec(&ch_inf);
311
312 return ch_inf.chspec;
313}
314
Franky Lin83cf17a2013-04-11 13:28:50 +0200315u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
316 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700317{
Franky Lin83cf17a2013-04-11 13:28:50 +0200318 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700319
Franky Lin83cf17a2013-04-11 13:28:50 +0200320 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
321 ch_inf.bw = BRCMU_CHAN_BW_20;
322 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700323
Franky Lin83cf17a2013-04-11 13:28:50 +0200324 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700325}
326
Hante Meuleman89286dc2013-02-08 15:53:46 +0100327/* Traverse a string of 1-byte tag/1-byte length/variable-length value
328 * triples, returning a pointer to the substring whose first element
329 * matches tag
330 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100331const struct brcmf_tlv *
332brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100333{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100334 const struct brcmf_tlv *elt = buf;
335 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100336
337 /* find tagged parameter */
338 while (totlen >= TLV_HDR_LEN) {
339 int len = elt->len;
340
341 /* validate remaining totlen */
342 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
343 return elt;
344
345 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
346 totlen -= (len + TLV_HDR_LEN);
347 }
348
349 return NULL;
350}
351
352/* Is any of the tlvs the expected entry? If
353 * not update the tlvs buffer pointer/length.
354 */
355static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100356brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
357 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100358{
359 /* If the contents match the OUI and the type */
360 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
361 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
362 type == ie[TLV_BODY_OFF + oui_len]) {
363 return true;
364 }
365
366 if (tlvs == NULL)
367 return false;
368 /* point to the next ie */
369 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
370 /* calculate the length of the rest of the buffer */
371 *tlvs_len -= (int)(ie - *tlvs);
372 /* update the pointer to the start of the buffer */
373 *tlvs = ie;
374
375 return false;
376}
377
378static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100379brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100380{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100381 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100382
383 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100384 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100385 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
386 return (struct brcmf_vs_tlv *)ie;
387 }
388 return NULL;
389}
390
391static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100392brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100393{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100394 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100395
396 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
397 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
398 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
399 return (struct brcmf_vs_tlv *)ie;
400 }
401 return NULL;
402}
403
Arend van Spriel39504a22015-08-20 22:06:05 +0200404static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
405 struct brcmf_cfg80211_vif *vif,
406 enum nl80211_iftype new_type)
407{
Arend van Spriel39504a22015-08-20 22:06:05 +0200408 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100409 bool check_combos = false;
410 int ret = 0;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530411 struct iface_combination_params params = {
412 .num_different_channels = 1,
413 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200414
Arend van Spriel39504a22015-08-20 22:06:05 +0200415 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100416 if (pos == vif) {
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530417 params.iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100418 } else {
419 /* concurrent interfaces so need check combinations */
420 check_combos = true;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530421 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100422 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200423
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424 if (check_combos)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530425 ret = cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel353c46a2015-12-10 13:43:06 +0100426
427 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200428}
429
430static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
431 enum nl80211_iftype new_type)
432{
Arend van Spriel39504a22015-08-20 22:06:05 +0200433 struct brcmf_cfg80211_vif *pos;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530434 struct iface_combination_params params = {
435 .num_different_channels = 1,
436 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200437
Arend van Spriel39504a22015-08-20 22:06:05 +0200438 list_for_each_entry(pos, &cfg->vif_list, list)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530439 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel39504a22015-08-20 22:06:05 +0200440
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530441 params.iftype_num[new_type]++;
442 return cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel39504a22015-08-20 22:06:05 +0200443}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100444
Arend van Spriel5b435de2011-10-05 13:19:03 +0200445static void convert_key_from_CPU(struct brcmf_wsec_key *key,
446 struct brcmf_wsec_key_le *key_le)
447{
448 key_le->index = cpu_to_le32(key->index);
449 key_le->len = cpu_to_le32(key->len);
450 key_le->algo = cpu_to_le32(key->algo);
451 key_le->flags = cpu_to_le32(key->flags);
452 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
453 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
454 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
455 memcpy(key_le->data, key->data, sizeof(key->data));
456 memcpy(key_le->ea, key->ea, sizeof(key->ea));
457}
458
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200459static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100460send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200461{
462 int err;
463 struct brcmf_wsec_key_le key_le;
464
465 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200466
Hante Meuleman118eb302014-12-21 12:43:49 +0100467 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700468
Hante Meuleman118eb302014-12-21 12:43:49 +0100469 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700470 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200471
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100473 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200474 return err;
475}
476
Hante Meulemanb3657452013-05-27 21:09:53 +0200477static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100478brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200479{
480 s32 err;
481 u32 mode;
482
483 if (enable)
484 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
485 else
486 mode = 0;
487
488 /* Try to set and enable ARP offload feature, this may fail, then it */
489 /* is simply not supported and err 0 will be returned */
490 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
491 if (err) {
492 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
493 mode, err);
494 err = 0;
495 } else {
496 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
497 if (err) {
498 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
499 enable, err);
500 err = 0;
501 } else
502 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
503 enable, mode);
504 }
505
Franky Lin52f22fb2016-02-17 11:26:55 +0100506 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
507 if (err) {
508 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
509 enable, err);
510 err = 0;
511 } else
512 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
513 enable, mode);
514
Hante Meulemanb3657452013-05-27 21:09:53 +0200515 return err;
516}
517
Hante Meuleman8851cce2014-07-30 13:20:02 +0200518static void
519brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
520{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200521 struct brcmf_cfg80211_vif *vif;
522 struct brcmf_if *ifp;
523
524 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
525 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200526
527 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
528 (wdev->iftype == NL80211_IFTYPE_AP) ||
529 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
530 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
531 ADDR_DIRECT);
532 else
533 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
534 ADDR_INDIRECT);
535}
536
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200537static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
538{
539 int bsscfgidx;
540
541 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
542 /* bsscfgidx 1 is reserved for legacy P2P */
543 if (bsscfgidx == 1)
544 continue;
545 if (!drvr->iflist[bsscfgidx])
546 return bsscfgidx;
547 }
548
549 return -ENOMEM;
550}
551
Hante Meulemana44aa402014-12-03 21:05:33 +0100552static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
553{
554 struct brcmf_mbss_ssid_le mbss_ssid_le;
555 int bsscfgidx;
556 int err;
557
558 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200559 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100560 if (bsscfgidx < 0)
561 return bsscfgidx;
562
563 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
564 mbss_ssid_le.SSID_len = cpu_to_le32(5);
565 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
566
567 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
568 sizeof(mbss_ssid_le));
569 if (err < 0)
570 brcmf_err("setting ssid failed %d\n", err);
571
572 return err;
573}
574
575/**
576 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
577 *
578 * @wiphy: wiphy device of new interface.
579 * @name: name of the new interface.
580 * @flags: not used.
581 * @params: contains mac address for AP device.
582 */
583static
584struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
585 u32 *flags, struct vif_params *params)
586{
587 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
588 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
589 struct brcmf_cfg80211_vif *vif;
590 int err;
591
592 if (brcmf_cfg80211_vif_event_armed(cfg))
593 return ERR_PTR(-EBUSY);
594
595 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
596
Rafał Miłecki26072332016-06-06 23:03:55 +0200597 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100598 if (IS_ERR(vif))
599 return (struct wireless_dev *)vif;
600
601 brcmf_cfg80211_arm_vif_event(cfg, vif);
602
603 err = brcmf_cfg80211_request_ap_if(ifp);
604 if (err) {
605 brcmf_cfg80211_arm_vif_event(cfg, NULL);
606 goto fail;
607 }
608
609 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100610 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
611 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100612 brcmf_cfg80211_arm_vif_event(cfg, NULL);
613 if (!err) {
614 brcmf_err("timeout occurred\n");
615 err = -EIO;
616 goto fail;
617 }
618
619 /* interface created in firmware */
620 ifp = vif->ifp;
621 if (!ifp) {
622 brcmf_err("no if pointer provided\n");
623 err = -ENOENT;
624 goto fail;
625 }
626
627 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
628 err = brcmf_net_attach(ifp, true);
629 if (err) {
630 brcmf_err("Registering netdevice failed\n");
631 goto fail;
632 }
633
634 return &ifp->vif->wdev;
635
636fail:
637 brcmf_free_vif(vif);
638 return ERR_PTR(err);
639}
640
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100641static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
642{
643 enum nl80211_iftype iftype;
644
645 iftype = vif->wdev.iftype;
646 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
647}
648
649static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
650{
651 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
652}
653
Arend van Spriel9f440b72013-02-08 15:53:36 +0100654static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
655 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100656 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100657 enum nl80211_iftype type,
658 u32 *flags,
659 struct vif_params *params)
660{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200661 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200662 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200663
Arend van Spriel9f440b72013-02-08 15:53:36 +0100664 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200665 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
666 if (err) {
667 brcmf_err("iface validation failed: err=%d\n", err);
668 return ERR_PTR(err);
669 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100670 switch (type) {
671 case NL80211_IFTYPE_ADHOC:
672 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100673 case NL80211_IFTYPE_AP_VLAN:
674 case NL80211_IFTYPE_WDS:
675 case NL80211_IFTYPE_MONITOR:
676 case NL80211_IFTYPE_MESH_POINT:
677 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100678 case NL80211_IFTYPE_AP:
679 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200680 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100681 case NL80211_IFTYPE_P2P_CLIENT:
682 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200683 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100684 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200685 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100686 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100687 default:
688 return ERR_PTR(-EINVAL);
689 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200690
691 if (IS_ERR(wdev))
692 brcmf_err("add iface %s type %d failed: err=%d\n",
693 name, type, (int)PTR_ERR(wdev));
694 else
695 brcmf_cfg80211_update_proto_addr_mode(wdev);
696
697 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100698}
699
Daniel Kim5e787f72014-06-21 12:11:18 +0200700static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
701{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200702 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200703 brcmf_set_mpc(ifp, mpc);
704}
705
Arend van Sprielf96aa072013-04-05 10:57:48 +0200706void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100707{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100708 s32 err = 0;
709
710 if (check_vif_up(ifp->vif)) {
711 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
712 if (err) {
713 brcmf_err("fail to set mpc\n");
714 return;
715 }
716 brcmf_dbg(INFO, "MPC : %d\n", mpc);
717 }
718}
719
Arend van Spriela0f472a2013-04-05 10:57:49 +0200720s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
721 struct brcmf_if *ifp, bool aborted,
722 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100723{
724 struct brcmf_scan_params_le params_le;
725 struct cfg80211_scan_request *scan_request;
726 s32 err = 0;
727
728 brcmf_dbg(SCAN, "Enter\n");
729
730 /* clear scan request, because the FW abort can cause a second call */
731 /* to this functon and might cause a double cfg80211_scan_done */
732 scan_request = cfg->scan_request;
733 cfg->scan_request = NULL;
734
735 if (timer_pending(&cfg->escan_timeout))
736 del_timer_sync(&cfg->escan_timeout);
737
738 if (fw_abort) {
739 /* Do a scan abort to stop the driver's scan engine */
740 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
741 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800742 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100743 params_le.bss_type = DOT11_BSSTYPE_ANY;
744 params_le.scan_type = 0;
745 params_le.channel_num = cpu_to_le32(1);
746 params_le.nprobes = cpu_to_le32(1);
747 params_le.active_time = cpu_to_le32(-1);
748 params_le.passive_time = cpu_to_le32(-1);
749 params_le.home_time = cpu_to_le32(-1);
750 /* Scan is aborted by setting channel_list[0] to -1 */
751 params_le.channel_list[0] = cpu_to_le16(-1);
752 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200753 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100754 &params_le, sizeof(params_le));
755 if (err)
756 brcmf_err("Scan abort failed\n");
757 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200758
Daniel Kim5e787f72014-06-21 12:11:18 +0200759 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200760
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100761 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000762 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100763 * which takes precedence.
764 */
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000765 if (cfg->internal_escan) {
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100766 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000767 cfg->internal_escan = false;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100768 if (!aborted)
769 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100770 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300771 struct cfg80211_scan_info info = {
772 .aborted = aborted,
773 };
774
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100775 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
776 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300777 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100778 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100779 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
780 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100781
782 return err;
783}
784
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200785static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
786 struct wireless_dev *wdev)
787{
788 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
789 struct net_device *ndev = wdev->netdev;
790 struct brcmf_if *ifp = netdev_priv(ndev);
791 int ret;
792 int err;
793
794 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
795
796 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
797 if (err) {
798 brcmf_err("interface_remove failed %d\n", err);
799 goto err_unarm;
800 }
801
802 /* wait for firmware event */
803 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
804 BRCMF_VIF_EVENT_TIMEOUT);
805 if (!ret) {
806 brcmf_err("timeout occurred\n");
807 err = -EIO;
808 goto err_unarm;
809 }
810
811 brcmf_remove_interface(ifp, true);
812
813err_unarm:
814 brcmf_cfg80211_arm_vif_event(cfg, NULL);
815 return err;
816}
817
Arend van Spriel9f440b72013-02-08 15:53:36 +0100818static
819int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
820{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100821 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
822 struct net_device *ndev = wdev->netdev;
823
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200824 if (ndev && ndev == cfg_to_ndev(cfg))
825 return -ENOTSUPP;
826
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100827 /* vif event pending in firmware */
828 if (brcmf_cfg80211_vif_event_armed(cfg))
829 return -EBUSY;
830
831 if (ndev) {
832 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200833 cfg->escan_info.ifp == netdev_priv(ndev))
834 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
835 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100836
837 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
838 }
839
Arend van Spriel9f440b72013-02-08 15:53:36 +0100840 switch (wdev->iftype) {
841 case NL80211_IFTYPE_ADHOC:
842 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100843 case NL80211_IFTYPE_AP_VLAN:
844 case NL80211_IFTYPE_WDS:
845 case NL80211_IFTYPE_MONITOR:
846 case NL80211_IFTYPE_MESH_POINT:
847 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200848 case NL80211_IFTYPE_AP:
849 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100850 case NL80211_IFTYPE_P2P_CLIENT:
851 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200852 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100853 return brcmf_p2p_del_vif(wiphy, wdev);
854 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100855 default:
856 return -EINVAL;
857 }
858 return -EOPNOTSUPP;
859}
860
Arend van Spriel5b435de2011-10-05 13:19:03 +0200861static s32
862brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
863 enum nl80211_iftype type, u32 *flags,
864 struct vif_params *params)
865{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100866 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700867 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100868 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200869 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200870 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200871 s32 err = 0;
872
Hante Meuleman37a869e2015-10-29 20:33:17 +0100873 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
874 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200875
876 /* WAR: There are a number of p2p interface related problems which
877 * need to be handled initially (before doing the validate).
878 * wpa_supplicant tends to do iface changes on p2p device/client/go
879 * which are not always possible/allowed. However we need to return
880 * OK otherwise the wpa_supplicant wont start. The situation differs
881 * on configuration and setup (p2pon=1 module param). The first check
882 * is to see if the request is a change to station for p2p iface.
883 */
884 if ((type == NL80211_IFTYPE_STATION) &&
885 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
886 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
887 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
888 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
889 /* Now depending on whether module param p2pon=1 was used the
890 * response needs to be either 0 or EOPNOTSUPP. The reason is
891 * that if p2pon=1 is used, but a newer supplicant is used then
892 * we should return an error, as this combination wont work.
893 * In other situations 0 is returned and supplicant will start
894 * normally. It will give a trace in cfg80211, but it is the
895 * only way to get it working. Unfortunately this will result
896 * in situation where we wont support new supplicant in
897 * combination with module param p2pon=1, but that is the way
898 * it is. If the user tries this then unloading of driver might
899 * fail/lock.
900 */
901 if (cfg->p2p.p2pdev_dynamically)
902 return -EOPNOTSUPP;
903 else
904 return 0;
905 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200906 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
907 if (err) {
908 brcmf_err("iface validation failed: err=%d\n", err);
909 return err;
910 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200911 switch (type) {
912 case NL80211_IFTYPE_MONITOR:
913 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100914 brcmf_err("type (%d) : currently we do not support this type\n",
915 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200916 return -EOPNOTSUPP;
917 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200918 infra = 0;
919 break;
920 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200921 infra = 1;
922 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200923 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100924 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200925 ap = 1;
926 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200927 default:
928 err = -EINVAL;
929 goto done;
930 }
931
Hante Meuleman1a873342012-09-27 14:17:54 +0200932 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100933 if (type == NL80211_IFTYPE_P2P_GO) {
934 brcmf_dbg(INFO, "IF Type = P2P GO\n");
935 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
936 }
937 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100938 brcmf_dbg(INFO, "IF Type = AP\n");
939 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200940 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100941 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200942 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100943 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200944 err = -EAGAIN;
945 goto done;
946 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100947 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100948 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200949 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200950 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200951
Hante Meuleman8851cce2014-07-30 13:20:02 +0200952 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
953
Arend van Spriel5b435de2011-10-05 13:19:03 +0200954done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100955 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200956
957 return err;
958}
959
Franky Lin83cf17a2013-04-11 13:28:50 +0200960static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
961 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200962 struct cfg80211_scan_request *request)
963{
964 u32 n_ssids;
965 u32 n_channels;
966 s32 i;
967 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200968 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200969 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200970 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200971
Joe Perches93803b32015-03-02 19:54:49 -0800972 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200973 params_le->bss_type = DOT11_BSSTYPE_ANY;
974 params_le->scan_type = 0;
975 params_le->channel_num = 0;
976 params_le->nprobes = cpu_to_le32(-1);
977 params_le->active_time = cpu_to_le32(-1);
978 params_le->passive_time = cpu_to_le32(-1);
979 params_le->home_time = cpu_to_le32(-1);
980 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
981
982 /* if request is null exit so it will be all channel broadcast scan */
983 if (!request)
984 return;
985
986 n_ssids = request->n_ssids;
987 n_channels = request->n_channels;
988 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100989 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
990 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200991 if (n_channels > 0) {
992 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200993 chanspec = channel_to_chanspec(&cfg->d11inf,
994 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100995 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
996 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200997 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200998 }
999 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001000 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001001 }
1002 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001003 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001004 if (n_ssids > 0) {
1005 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1006 n_channels * sizeof(u16);
1007 offset = roundup(offset, sizeof(u32));
1008 ptr = (char *)params_le + offset;
1009 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001010 memset(&ssid_le, 0, sizeof(ssid_le));
1011 ssid_le.SSID_len =
1012 cpu_to_le32(request->ssids[i].ssid_len);
1013 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1014 request->ssids[i].ssid_len);
1015 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001016 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001017 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001018 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
1019 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001020 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1021 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001022 }
1023 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001024 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001025 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001026 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1027 params_le->ssid_le.SSID,
1028 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001029 params_le->ssid_le.SSID_len =
1030 cpu_to_le32(request->ssids->ssid_len);
1031 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1032 request->ssids->ssid_len);
1033 }
1034 }
1035 /* Adding mask to channel numbers */
1036 params_le->channel_num =
1037 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1038 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1039}
1040
1041static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001042brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001043 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001044{
1045 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1046 offsetof(struct brcmf_escan_params_le, params_le);
1047 struct brcmf_escan_params_le *params;
1048 s32 err = 0;
1049
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001050 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001051
1052 if (request != NULL) {
1053 /* Allocate space for populating ssids in struct */
1054 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1055
1056 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001057 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001058 }
1059
1060 params = kzalloc(params_size, GFP_KERNEL);
1061 if (!params) {
1062 err = -ENOMEM;
1063 goto exit;
1064 }
1065 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001066 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001067 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001068 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001069 params->sync_id = cpu_to_le16(0x1234);
1070
Arend van Spriela0f472a2013-04-05 10:57:49 +02001071 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001072 if (err) {
1073 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001074 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001075 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001076 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001077 }
1078
1079 kfree(params);
1080exit:
1081 return err;
1082}
1083
1084static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001085brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001086{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001087 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001088 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001089 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001090 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001091 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001092
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001093 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001094 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001095 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001096 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001097 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001098 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001099 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001100 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001101 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001102 return err;
1103 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001104 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001105 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001106 results->version = 0;
1107 results->count = 0;
1108 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1109
Hante Meulemanc4958102015-11-25 11:32:41 +01001110 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001111 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001112 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001113 return err;
1114}
1115
1116static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001117brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001118 struct cfg80211_scan_request *request,
1119 struct cfg80211_ssid *this_ssid)
1120{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001121 struct brcmf_if *ifp = vif->ifp;
1122 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001123 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001124 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001125 bool escan_req;
1126 bool spec_scan;
1127 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001128 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001129 u32 SSID_len;
1130
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001131 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001132
Arend van Sprielc1179032012-10-22 13:55:33 -07001133 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001134 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001135 return -EAGAIN;
1136 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001137 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001138 brcmf_err("Scanning being aborted: status (%lu)\n",
1139 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001140 return -EAGAIN;
1141 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001142 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1143 brcmf_err("Scanning suppressed: status (%lu)\n",
1144 cfg->scan_status);
1145 return -EAGAIN;
1146 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001147 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001148 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001149 return -EAGAIN;
1150 }
1151
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001152 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001153 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1154 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001155
Hante Meulemane756af52012-09-11 21:18:52 +02001156 escan_req = false;
1157 if (request) {
1158 /* scan bss */
1159 ssids = request->ssids;
1160 escan_req = true;
1161 } else {
1162 /* scan in ibss */
1163 /* we don't do escan in ibss */
1164 ssids = this_ssid;
1165 }
1166
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001167 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001168 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001169 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001170 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001171 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001172 if (err)
1173 goto scan_out;
1174
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001175 err = brcmf_do_escan(vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001176 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001177 goto scan_out;
1178 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001179 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1180 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001181 memset(&ssid_le, 0, sizeof(ssid_le));
1182 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1183 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001184 spec_scan = false;
1185 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001186 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1187 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001188 spec_scan = true;
1189 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001190 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001191
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001192 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001193 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001194 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001195 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001196 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001197 goto scan_out;
1198 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001199 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001200 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1201 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001202 if (err) {
1203 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001204 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001205 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001206 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001207 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001208
Daniel Kim5e787f72014-06-21 12:11:18 +02001209 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001210 goto scan_out;
1211 }
1212 }
1213
Hante Meuleman661fa952015-02-06 18:36:47 +01001214 /* Arm scan timeout timer */
1215 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001216 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001217
Hante Meulemane756af52012-09-11 21:18:52 +02001218 return 0;
1219
1220scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001221 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001222 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001223 return err;
1224}
1225
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001227brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001228{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001229 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001230 s32 err = 0;
1231
Arend van Sprield96b8012012-12-05 15:26:02 +01001232 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001233 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1234 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 return -EIO;
1236
Arend van Spriela0f472a2013-04-05 10:57:49 +02001237 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001238
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001240 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001241
Arend van Sprield96b8012012-12-05 15:26:02 +01001242 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001243 return err;
1244}
1245
1246static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1247{
1248 s32 err = 0;
1249
Arend van Sprielac24be62012-10-22 10:36:23 -07001250 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1251 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001252 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001253 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001254
1255 return err;
1256}
1257
1258static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1259{
1260 s32 err = 0;
1261
Arend van Sprielac24be62012-10-22 10:36:23 -07001262 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1263 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001264 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001265 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001266
1267 return err;
1268}
1269
1270static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1271{
1272 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001273 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001274
Arend van Sprielac24be62012-10-22 10:36:23 -07001275 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001276 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001277 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001278 return err;
1279 }
1280 return err;
1281}
1282
1283static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1284{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001285 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1286 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001287 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288 s32 err = 0;
1289
Arend van Sprield96b8012012-12-05 15:26:02 +01001290 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001291 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001292 return -EIO;
1293
1294 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001295 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1296 cfg->conf->rts_threshold = wiphy->rts_threshold;
1297 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001298 if (!err)
1299 goto done;
1300 }
1301 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001302 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1303 cfg->conf->frag_threshold = wiphy->frag_threshold;
1304 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 if (!err)
1306 goto done;
1307 }
1308 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001309 && (cfg->conf->retry_long != wiphy->retry_long)) {
1310 cfg->conf->retry_long = wiphy->retry_long;
1311 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001312 if (!err)
1313 goto done;
1314 }
1315 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001316 && (cfg->conf->retry_short != wiphy->retry_short)) {
1317 cfg->conf->retry_short = wiphy->retry_short;
1318 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001319 if (!err)
1320 goto done;
1321 }
1322
1323done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001324 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001325 return err;
1326}
1327
Arend van Spriel5b435de2011-10-05 13:19:03 +02001328static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1329{
1330 memset(prof, 0, sizeof(*prof));
1331}
1332
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001333static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1334{
1335 u16 reason;
1336
1337 switch (e->event_code) {
1338 case BRCMF_E_DEAUTH:
1339 case BRCMF_E_DEAUTH_IND:
1340 case BRCMF_E_DISASSOC_IND:
1341 reason = e->reason;
1342 break;
1343 case BRCMF_E_LINK:
1344 default:
1345 reason = 0;
1346 break;
1347 }
1348 return reason;
1349}
1350
1351static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001352{
Piotr Haber61730d42013-04-23 12:53:12 +02001353 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001354 s32 err = 0;
1355
Arend van Sprield96b8012012-12-05 15:26:02 +01001356 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001357
Hante Meulemanb0a79082015-12-10 13:43:07 +01001358 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001359 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001360 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001361 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001362 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001363 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001364 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001365 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1366 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1367 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1368 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001369 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001370 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001371 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1372 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001373 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001374}
1375
1376static s32
1377brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1378 struct cfg80211_ibss_params *params)
1379{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001380 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001381 struct brcmf_if *ifp = netdev_priv(ndev);
1382 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001383 struct brcmf_join_params join_params;
1384 size_t join_params_size = 0;
1385 s32 err = 0;
1386 s32 wsec = 0;
1387 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001388 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001389 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001390
Arend van Sprield96b8012012-12-05 15:26:02 +01001391 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001392 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001393 return -EIO;
1394
1395 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001396 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001397 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001398 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399 return -EOPNOTSUPP;
1400 }
1401
Arend van Sprielc1179032012-10-22 13:55:33 -07001402 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001403
1404 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001405 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001406 else
Arend van Spriel16886732012-12-05 15:26:04 +01001407 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408
Johannes Berg683b6d32012-11-08 21:25:48 +01001409 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001410 brcmf_dbg(CONN, "channel: %d\n",
1411 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001412 else
Arend van Spriel16886732012-12-05 15:26:04 +01001413 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001414
1415 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001416 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 else
Arend van Spriel16886732012-12-05 15:26:04 +01001418 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001419
1420 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001421 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001422 else
Arend van Spriel16886732012-12-05 15:26:04 +01001423 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424
1425 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001426 brcmf_dbg(CONN, "beacon interval: %d\n",
1427 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001428 else
Arend van Spriel16886732012-12-05 15:26:04 +01001429 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430
1431 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001432 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 else
Arend van Spriel16886732012-12-05 15:26:04 +01001434 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001435
1436 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001437 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001438 else
Arend van Spriel16886732012-12-05 15:26:04 +01001439 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440
1441 /* Configure Privacy for starter */
1442 if (params->privacy)
1443 wsec |= WEP_ENABLED;
1444
Arend van Sprielc1179032012-10-22 13:55:33 -07001445 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001447 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001448 goto done;
1449 }
1450
1451 /* Configure Beacon Interval for starter */
1452 if (params->beacon_interval)
1453 bcnprd = params->beacon_interval;
1454 else
1455 bcnprd = 100;
1456
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001457 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001459 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001460 goto done;
1461 }
1462
1463 /* Configure required join parameter */
1464 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1465
1466 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001467 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1468 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1469 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001470 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471
1472 /* BSSID */
1473 if (params->bssid) {
1474 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001475 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001476 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001477 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001478 eth_broadcast_addr(join_params.params_le.bssid);
1479 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 }
1481
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001483 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001484 u32 target_channel;
1485
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001486 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001488 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001489 if (params->channel_fixed) {
1490 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001491 chanspec = chandef_to_chanspec(&cfg->d11inf,
1492 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001493 join_params.params_le.chanspec_list[0] =
1494 cpu_to_le16(chanspec);
1495 join_params.params_le.chanspec_num = cpu_to_le32(1);
1496 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001497 }
1498
1499 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001500 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001501 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001502 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001503 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001504 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505 goto done;
1506 }
1507 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001508 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001509
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001510 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511
1512
Arend van Sprielc1179032012-10-22 13:55:33 -07001513 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001514 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001515 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001516 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001517 goto done;
1518 }
1519
1520done:
1521 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001522 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001523 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524 return err;
1525}
1526
1527static s32
1528brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1529{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001530 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531
Arend van Sprield96b8012012-12-05 15:26:02 +01001532 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001533 if (!check_vif_up(ifp->vif)) {
1534 /* When driver is being unloaded, it can end up here. If an
1535 * error is returned then later on a debug trace in the wireless
1536 * core module will be printed. To avoid this 0 is returned.
1537 */
1538 return 0;
1539 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001541 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001542 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543
Arend van Sprield96b8012012-12-05 15:26:02 +01001544 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001545
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001546 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001547}
1548
1549static s32 brcmf_set_wpa_version(struct net_device *ndev,
1550 struct cfg80211_connect_params *sme)
1551{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001552 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001553 struct brcmf_cfg80211_security *sec;
1554 s32 val = 0;
1555 s32 err = 0;
1556
1557 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1558 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1559 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1560 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1561 else
1562 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001563 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001564 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001566 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001567 return err;
1568 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001569 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001570 sec->wpa_versions = sme->crypto.wpa_versions;
1571 return err;
1572}
1573
1574static s32 brcmf_set_auth_type(struct net_device *ndev,
1575 struct cfg80211_connect_params *sme)
1576{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001577 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001578 struct brcmf_cfg80211_security *sec;
1579 s32 val = 0;
1580 s32 err = 0;
1581
1582 switch (sme->auth_type) {
1583 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1584 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001585 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586 break;
1587 case NL80211_AUTHTYPE_SHARED_KEY:
1588 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001589 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001590 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001591 default:
1592 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001593 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001594 break;
1595 }
1596
Hante Meuleman89286dc2013-02-08 15:53:46 +01001597 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001598 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001599 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001600 return err;
1601 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001602 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001603 sec->auth_type = sme->auth_type;
1604 return err;
1605}
1606
1607static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001608brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001609 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001610{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001611 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612 struct brcmf_cfg80211_security *sec;
1613 s32 pval = 0;
1614 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001615 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001616 s32 err = 0;
1617
1618 if (sme->crypto.n_ciphers_pairwise) {
1619 switch (sme->crypto.ciphers_pairwise[0]) {
1620 case WLAN_CIPHER_SUITE_WEP40:
1621 case WLAN_CIPHER_SUITE_WEP104:
1622 pval = WEP_ENABLED;
1623 break;
1624 case WLAN_CIPHER_SUITE_TKIP:
1625 pval = TKIP_ENABLED;
1626 break;
1627 case WLAN_CIPHER_SUITE_CCMP:
1628 pval = AES_ENABLED;
1629 break;
1630 case WLAN_CIPHER_SUITE_AES_CMAC:
1631 pval = AES_ENABLED;
1632 break;
1633 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001634 brcmf_err("invalid cipher pairwise (%d)\n",
1635 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001636 return -EINVAL;
1637 }
1638 }
1639 if (sme->crypto.cipher_group) {
1640 switch (sme->crypto.cipher_group) {
1641 case WLAN_CIPHER_SUITE_WEP40:
1642 case WLAN_CIPHER_SUITE_WEP104:
1643 gval = WEP_ENABLED;
1644 break;
1645 case WLAN_CIPHER_SUITE_TKIP:
1646 gval = TKIP_ENABLED;
1647 break;
1648 case WLAN_CIPHER_SUITE_CCMP:
1649 gval = AES_ENABLED;
1650 break;
1651 case WLAN_CIPHER_SUITE_AES_CMAC:
1652 gval = AES_ENABLED;
1653 break;
1654 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001655 brcmf_err("invalid cipher group (%d)\n",
1656 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001657 return -EINVAL;
1658 }
1659 }
1660
Arend van Spriel16886732012-12-05 15:26:04 +01001661 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001662 /* In case of privacy, but no security and WPS then simulate */
1663 /* setting AES. WPS-2.0 allows no security */
1664 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1665 sme->privacy)
1666 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001667
Hante Meuleman240d61a2016-02-17 11:27:10 +01001668 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001669 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001670 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001671 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672 return err;
1673 }
1674
Arend van Spriel06bb1232012-09-27 14:17:56 +02001675 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001676 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1677 sec->cipher_group = sme->crypto.cipher_group;
1678
1679 return err;
1680}
1681
1682static s32
1683brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1684{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001685 struct brcmf_if *ifp = netdev_priv(ndev);
1686 s32 val;
1687 s32 err;
1688 const struct brcmf_tlv *rsn_ie;
1689 const u8 *ie;
1690 u32 ie_len;
1691 u32 offset;
1692 u16 rsn_cap;
1693 u32 mfp;
1694 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001695
Hante Meuleman240d61a2016-02-17 11:27:10 +01001696 if (!sme->crypto.n_akm_suites)
1697 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001698
Hante Meuleman240d61a2016-02-17 11:27:10 +01001699 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1700 if (err) {
1701 brcmf_err("could not get wpa_auth (%d)\n", err);
1702 return err;
1703 }
1704 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1705 switch (sme->crypto.akm_suites[0]) {
1706 case WLAN_AKM_SUITE_8021X:
1707 val = WPA_AUTH_UNSPECIFIED;
1708 break;
1709 case WLAN_AKM_SUITE_PSK:
1710 val = WPA_AUTH_PSK;
1711 break;
1712 default:
1713 brcmf_err("invalid cipher group (%d)\n",
1714 sme->crypto.cipher_group);
1715 return -EINVAL;
1716 }
1717 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1718 switch (sme->crypto.akm_suites[0]) {
1719 case WLAN_AKM_SUITE_8021X:
1720 val = WPA2_AUTH_UNSPECIFIED;
1721 break;
1722 case WLAN_AKM_SUITE_8021X_SHA256:
1723 val = WPA2_AUTH_1X_SHA256;
1724 break;
1725 case WLAN_AKM_SUITE_PSK_SHA256:
1726 val = WPA2_AUTH_PSK_SHA256;
1727 break;
1728 case WLAN_AKM_SUITE_PSK:
1729 val = WPA2_AUTH_PSK;
1730 break;
1731 default:
1732 brcmf_err("invalid cipher group (%d)\n",
1733 sme->crypto.cipher_group);
1734 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735 }
1736 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001737
1738 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1739 goto skip_mfp_config;
1740 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1741 * IE will not be verified, just a quick search for MFP config
1742 */
1743 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1744 WLAN_EID_RSN);
1745 if (!rsn_ie)
1746 goto skip_mfp_config;
1747 ie = (const u8 *)rsn_ie;
1748 ie_len = rsn_ie->len + TLV_HDR_LEN;
1749 /* Skip unicast suite */
1750 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1751 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1752 goto skip_mfp_config;
1753 /* Skip multicast suite */
1754 count = ie[offset] + (ie[offset + 1] << 8);
1755 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1756 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1757 goto skip_mfp_config;
1758 /* Skip auth key management suite(s) */
1759 count = ie[offset] + (ie[offset + 1] << 8);
1760 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1761 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1762 goto skip_mfp_config;
1763 /* Ready to read capabilities */
1764 mfp = BRCMF_MFP_NONE;
1765 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1766 if (rsn_cap & RSN_CAP_MFPR_MASK)
1767 mfp = BRCMF_MFP_REQUIRED;
1768 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1769 mfp = BRCMF_MFP_CAPABLE;
1770 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1771
1772skip_mfp_config:
1773 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1774 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1775 if (err) {
1776 brcmf_err("could not set wpa_auth (%d)\n", err);
1777 return err;
1778 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001779
1780 return err;
1781}
1782
1783static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001784brcmf_set_sharedkey(struct net_device *ndev,
1785 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001786{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001787 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001788 struct brcmf_cfg80211_security *sec;
1789 struct brcmf_wsec_key key;
1790 s32 val;
1791 s32 err = 0;
1792
Arend van Spriel16886732012-12-05 15:26:04 +01001793 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001794
Roland Vossena718e2f2011-10-12 20:51:24 +02001795 if (sme->key_len == 0)
1796 return 0;
1797
Arend van Spriel06bb1232012-09-27 14:17:56 +02001798 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001799 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1800 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001801
1802 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1803 return 0;
1804
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001805 if (!(sec->cipher_pairwise &
1806 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1807 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001808
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001809 memset(&key, 0, sizeof(key));
1810 key.len = (u32) sme->key_len;
1811 key.index = (u32) sme->key_idx;
1812 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001813 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001814 return -EINVAL;
1815 }
1816 memcpy(key.data, sme->key, key.len);
1817 key.flags = BRCMF_PRIMARY_KEY;
1818 switch (sec->cipher_pairwise) {
1819 case WLAN_CIPHER_SUITE_WEP40:
1820 key.algo = CRYPTO_ALGO_WEP1;
1821 break;
1822 case WLAN_CIPHER_SUITE_WEP104:
1823 key.algo = CRYPTO_ALGO_WEP128;
1824 break;
1825 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001826 brcmf_err("Invalid algorithm (%d)\n",
1827 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001828 return -EINVAL;
1829 }
1830 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001831 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1832 key.len, key.index, key.algo);
1833 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001834 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001835 if (err)
1836 return err;
1837
1838 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001839 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001840 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001841 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001842 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001843 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844 }
1845 return err;
1846}
1847
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001848static
1849enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1850 enum nl80211_auth_type type)
1851{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001852 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1853 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1854 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1855 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001856 }
1857 return type;
1858}
1859
Arend van Spriel7705ba62016-04-17 16:44:58 +02001860static void brcmf_set_join_pref(struct brcmf_if *ifp,
1861 struct cfg80211_bss_selection *bss_select)
1862{
1863 struct brcmf_join_pref_params join_pref_params[2];
1864 enum nl80211_band band;
1865 int err, i = 0;
1866
1867 join_pref_params[i].len = 2;
1868 join_pref_params[i].rssi_gain = 0;
1869
1870 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1871 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1872
1873 switch (bss_select->behaviour) {
1874 case __NL80211_BSS_SELECT_ATTR_INVALID:
1875 brcmf_c_set_joinpref_default(ifp);
1876 return;
1877 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1878 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1879 band = bss_select->param.band_pref;
1880 join_pref_params[i].band = nl80211_band_to_fwil(band);
1881 i++;
1882 break;
1883 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1884 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1885 band = bss_select->param.adjust.band;
1886 join_pref_params[i].band = nl80211_band_to_fwil(band);
1887 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1888 i++;
1889 break;
1890 case NL80211_BSS_SELECT_ATTR_RSSI:
1891 default:
1892 break;
1893 }
1894 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1895 join_pref_params[i].len = 2;
1896 join_pref_params[i].rssi_gain = 0;
1897 join_pref_params[i].band = 0;
1898 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1899 sizeof(join_pref_params));
1900 if (err)
1901 brcmf_err("Set join_pref error (%d)\n", err);
1902}
1903
Arend van Spriel5b435de2011-10-05 13:19:03 +02001904static s32
1905brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001906 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001907{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001908 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001909 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 struct ieee80211_channel *chan = sme->channel;
1911 struct brcmf_join_params join_params;
1912 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001913 const struct brcmf_tlv *rsn_ie;
1914 const struct brcmf_vs_tlv *wpa_ie;
1915 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001916 u32 ie_len;
1917 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001918 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001919 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001920 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001921
Arend van Sprield96b8012012-12-05 15:26:02 +01001922 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001923 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001924 return -EIO;
1925
1926 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001927 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001928 return -EOPNOTSUPP;
1929 }
1930
Hante Meuleman89286dc2013-02-08 15:53:46 +01001931 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1932 /* A normal (non P2P) connection request setup. */
1933 ie = NULL;
1934 ie_len = 0;
1935 /* find the WPA_IE */
1936 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1937 if (wpa_ie) {
1938 ie = wpa_ie;
1939 ie_len = wpa_ie->len + TLV_HDR_LEN;
1940 } else {
1941 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001942 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1943 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001944 WLAN_EID_RSN);
1945 if (rsn_ie) {
1946 ie = rsn_ie;
1947 ie_len = rsn_ie->len + TLV_HDR_LEN;
1948 }
1949 }
1950 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1951 }
1952
1953 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1954 sme->ie, sme->ie_len);
1955 if (err)
1956 brcmf_err("Set Assoc REQ IE Failed\n");
1957 else
1958 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1959
Arend van Sprielc1179032012-10-22 13:55:33 -07001960 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001961
1962 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001963 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001964 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001965 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001966 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1967 cfg->channel, chan->center_freq, chanspec);
1968 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001969 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001970 chanspec = 0;
1971 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001972
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001973 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001974
1975 err = brcmf_set_wpa_version(ndev, sme);
1976 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001977 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001978 goto done;
1979 }
1980
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001981 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001982 err = brcmf_set_auth_type(ndev, sme);
1983 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001984 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 goto done;
1986 }
1987
Hante Meuleman240d61a2016-02-17 11:27:10 +01001988 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001989 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001990 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001991 goto done;
1992 }
1993
1994 err = brcmf_set_key_mgmt(ndev, sme);
1995 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001996 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001997 goto done;
1998 }
1999
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002000 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002001 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002002 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002003 goto done;
2004 }
2005
Hante Meuleman89286dc2013-02-08 15:53:46 +01002006 /* Join with specific BSSID and cached SSID
2007 * If SSID is zero join based on BSSID only
2008 */
2009 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2010 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2011 if (cfg->channel)
2012 join_params_size += sizeof(u16);
2013 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2014 if (ext_join_params == NULL) {
2015 err = -ENOMEM;
2016 goto done;
2017 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002018 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2019 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2020 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2021 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2022 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2023 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002024
Hante Meuleman89286dc2013-02-08 15:53:46 +01002025 /* Set up join scan parameters */
2026 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002027 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2028
2029 if (sme->bssid)
2030 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2031 else
Joe Perches93803b32015-03-02 19:54:49 -08002032 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002033
2034 if (cfg->channel) {
2035 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2036
2037 ext_join_params->assoc_le.chanspec_list[0] =
2038 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002039 /* Increase dwell time to receive probe response or detect
2040 * beacon from target AP at a noisy air only during connect
2041 * command.
2042 */
2043 ext_join_params->scan_le.active_time =
2044 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2045 ext_join_params->scan_le.passive_time =
2046 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2047 /* To sync with presence period of VSDB GO send probe request
2048 * more frequently. Probe request will be stopped when it gets
2049 * probe response from target AP/GO.
2050 */
2051 ext_join_params->scan_le.nprobes =
2052 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2053 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2054 } else {
2055 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2056 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2057 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002058 }
2059
Arend van Spriel7705ba62016-04-17 16:44:58 +02002060 brcmf_set_join_pref(ifp, &sme->bss_select);
2061
Hante Meuleman89286dc2013-02-08 15:53:46 +01002062 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2063 join_params_size);
2064 kfree(ext_join_params);
2065 if (!err)
2066 /* This is it. join command worked, we are done */
2067 goto done;
2068
2069 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002070 memset(&join_params, 0, sizeof(join_params));
2071 join_params_size = sizeof(join_params.ssid_le);
2072
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002073 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2074 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002075
Hante Meuleman89286dc2013-02-08 15:53:46 +01002076 if (sme->bssid)
2077 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2078 else
Joe Perches93803b32015-03-02 19:54:49 -08002079 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080
Hante Meuleman17012612013-02-06 18:40:44 +01002081 if (cfg->channel) {
2082 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2083 join_params.params_le.chanspec_num = cpu_to_le32(1);
2084 join_params_size += sizeof(join_params.params_le);
2085 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002086 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002087 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002089 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002090
2091done:
2092 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002093 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002094 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 return err;
2096}
2097
2098static s32
2099brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2100 u16 reason_code)
2101{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002102 struct brcmf_if *ifp = netdev_priv(ndev);
2103 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002104 struct brcmf_scb_val_le scbval;
2105 s32 err = 0;
2106
Arend van Sprield96b8012012-12-05 15:26:02 +01002107 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002108 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002109 return -EIO;
2110
Arend van Sprielc1179032012-10-22 13:55:33 -07002111 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002112 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002113 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114
Arend van Spriel06bb1232012-09-27 14:17:56 +02002115 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002116 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002117 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002118 &scbval, sizeof(scbval));
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
Arend van Sprield96b8012012-12-05 15:26:02 +01002122 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 return err;
2124}
2125
2126static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002127brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002128 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002130 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002131 struct net_device *ndev = cfg_to_ndev(cfg);
2132 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002133 s32 err;
2134 s32 disable;
2135 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002137 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002138 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 return -EIO;
2140
2141 switch (type) {
2142 case NL80211_TX_POWER_AUTOMATIC:
2143 break;
2144 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002145 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002146 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002147 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002148 err = -EINVAL;
2149 goto done;
2150 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002151 qdbm = MBM_TO_DBM(4 * mbm);
2152 if (qdbm > 127)
2153 qdbm = 127;
2154 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002156 default:
2157 brcmf_err("Unsupported type %d\n", type);
2158 err = -EINVAL;
2159 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 }
2161 /* Make sure radio is off or on as far as software is concerned */
2162 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002163 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002165 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002167 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002168 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002169 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170
2171done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002172 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173 return err;
2174}
2175
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002176static s32
2177brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2178 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002179{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002180 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002181 struct net_device *ndev = cfg_to_ndev(cfg);
2182 struct brcmf_if *ifp = netdev_priv(ndev);
2183 s32 qdbm = 0;
2184 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002185
Arend van Sprield96b8012012-12-05 15:26:02 +01002186 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002187 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002188 return -EIO;
2189
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002190 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002191 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002192 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002193 goto done;
2194 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002195 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002196
2197done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002198 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002199 return err;
2200}
2201
2202static s32
2203brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002204 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002205{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002206 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002207 u32 index;
2208 u32 wsec;
2209 s32 err = 0;
2210
Arend van Sprield96b8012012-12-05 15:26:02 +01002211 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002212 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002213 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002214 return -EIO;
2215
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002216 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002218 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002219 goto done;
2220 }
2221
2222 if (wsec & WEP_ENABLED) {
2223 /* Just select a new current key */
2224 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002225 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002226 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002227 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002228 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229 }
2230done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002231 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 return err;
2233}
2234
2235static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002236brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2237 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238{
Hante Meuleman992f6062013-04-02 21:06:17 +02002239 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002240 struct brcmf_wsec_key *key;
2241 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002242
2243 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002244 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2245
Hante Meuleman219e0f72016-02-17 11:27:09 +01002246 if (!check_vif_up(ifp->vif))
2247 return -EIO;
2248
2249 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2250 /* we ignore this key index in this case */
2251 return -EINVAL;
2252 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002253
Hante Meuleman240d61a2016-02-17 11:27:10 +01002254 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002255
Hante Meuleman240d61a2016-02-17 11:27:10 +01002256 if (key->algo == CRYPTO_ALGO_OFF) {
2257 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2258 return -EINVAL;
2259 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Hante Meuleman240d61a2016-02-17 11:27:10 +01002261 memset(key, 0, sizeof(*key));
2262 key->index = (u32)key_idx;
2263 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002264
Hante Meuleman240d61a2016-02-17 11:27:10 +01002265 /* Clear the key/index */
2266 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267
Hante Meuleman219e0f72016-02-17 11:27:09 +01002268 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002269 return err;
2270}
2271
2272static s32
2273brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002274 u8 key_idx, bool pairwise, const u8 *mac_addr,
2275 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002276{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002277 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002278 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002279 s32 val;
2280 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002281 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002282 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002283 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284
Arend van Sprield96b8012012-12-05 15:26:02 +01002285 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002286 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002287 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002288 return -EIO;
2289
Hante Meuleman118eb302014-12-21 12:43:49 +01002290 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2291 /* we ignore this key index in this case */
2292 brcmf_err("invalid key index (%d)\n", key_idx);
2293 return -EINVAL;
2294 }
2295
Hante Meuleman219e0f72016-02-17 11:27:09 +01002296 if (params->key_len == 0)
2297 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2298 mac_addr);
2299
2300 if (params->key_len > sizeof(key->data)) {
2301 brcmf_err("Too long key length (%u)\n", params->key_len);
2302 return -EINVAL;
2303 }
2304
2305 ext_key = false;
2306 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2307 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2308 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2309 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002311
Hante Meuleman118eb302014-12-21 12:43:49 +01002312 key = &ifp->vif->profile.key[key_idx];
2313 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002314 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2315 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002316 key->len = params->key_len;
2317 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002318 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002319 if (!ext_key)
2320 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002321
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322 switch (params->cipher) {
2323 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002324 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002325 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002326 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002327 break;
2328 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002329 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002330 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002331 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332 break;
2333 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002334 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002335 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002336 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2337 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2338 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002339 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002340 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002341 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002342 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002343 break;
2344 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002345 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002346 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002347 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348 break;
2349 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002350 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002351 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002352 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002353 break;
2354 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002355 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356 err = -EINVAL;
2357 goto done;
2358 }
2359
Hante Meuleman118eb302014-12-21 12:43:49 +01002360 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002361 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002362 goto done;
2363
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002364 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002366 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002367 goto done;
2368 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002370 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002372 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373 goto done;
2374 }
2375
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002377 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 return err;
2379}
2380
2381static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002382brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2383 bool pairwise, const u8 *mac_addr, void *cookie,
2384 void (*callback)(void *cookie,
2385 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386{
2387 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002388 struct brcmf_if *ifp = netdev_priv(ndev);
2389 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002390 struct brcmf_cfg80211_security *sec;
2391 s32 wsec;
2392 s32 err = 0;
2393
Arend van Sprield96b8012012-12-05 15:26:02 +01002394 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002395 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002396 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002397 return -EIO;
2398
2399 memset(&params, 0, sizeof(params));
2400
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002401 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002402 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002403 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404 /* Ignore this error, may happen during DISASSOC */
2405 err = -EAGAIN;
2406 goto done;
2407 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002408 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002409 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002410 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2411 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002412 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002413 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2414 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002415 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002416 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002417 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002418 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002419 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002420 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002421 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002422 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002423 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002424 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425 err = -EINVAL;
2426 goto done;
2427 }
2428 callback(cookie, &params);
2429
2430done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002431 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002432 return err;
2433}
2434
2435static s32
2436brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002437 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002438{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002439 struct brcmf_if *ifp = netdev_priv(ndev);
2440
2441 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2442
2443 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2444 return 0;
2445
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002446 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002447
2448 return -EOPNOTSUPP;
2449}
2450
Hante Meuleman118eb302014-12-21 12:43:49 +01002451static void
2452brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2453{
2454 s32 err;
2455 u8 key_idx;
2456 struct brcmf_wsec_key *key;
2457 s32 wsec;
2458
2459 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2460 key = &ifp->vif->profile.key[key_idx];
2461 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2462 (key->algo == CRYPTO_ALGO_WEP128))
2463 break;
2464 }
2465 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2466 return;
2467
2468 err = send_key_to_dongle(ifp, key);
2469 if (err) {
2470 brcmf_err("Setting WEP key failed (%d)\n", err);
2471 return;
2472 }
2473 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2474 if (err) {
2475 brcmf_err("get wsec error (%d)\n", err);
2476 return;
2477 }
2478 wsec |= WEP_ENABLED;
2479 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2480 if (err)
2481 brcmf_err("set wsec error (%d)\n", err);
2482}
2483
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002484static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2485{
2486 struct nl80211_sta_flag_update *sfu;
2487
2488 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2489 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2490 sfu = &si->sta_flags;
2491 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2492 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2493 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2494 BIT(NL80211_STA_FLAG_AUTHORIZED);
2495 if (fw_sta_flags & BRCMF_STA_WME)
2496 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2497 if (fw_sta_flags & BRCMF_STA_AUTHE)
2498 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2499 if (fw_sta_flags & BRCMF_STA_ASSOC)
2500 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2501 if (fw_sta_flags & BRCMF_STA_AUTHO)
2502 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2503}
2504
2505static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2506{
2507 struct {
2508 __le32 len;
2509 struct brcmf_bss_info_le bss_le;
2510 } *buf;
2511 u16 capability;
2512 int err;
2513
2514 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2515 if (!buf)
2516 return;
2517
2518 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2519 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2520 WL_BSS_INFO_MAX);
2521 if (err) {
2522 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002523 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002524 }
2525 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2526 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2527 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2528 capability = le16_to_cpu(buf->bss_le.capability);
2529 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2530 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2531 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2532 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2533 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2534 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002535
2536out_kfree:
2537 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002538}
2539
Arend van Spriel5b435de2011-10-05 13:19:03 +02002540static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002541brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2542 struct station_info *sinfo)
2543{
2544 struct brcmf_scb_val_le scbval;
2545 struct brcmf_pktcnt_le pktcnt;
2546 s32 err;
2547 u32 rate;
2548 u32 rssi;
2549
2550 /* Get the current tx rate */
2551 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2552 if (err < 0) {
2553 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2554 return err;
2555 }
2556 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2557 sinfo->txrate.legacy = rate * 5;
2558
2559 memset(&scbval, 0, sizeof(scbval));
2560 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2561 sizeof(scbval));
2562 if (err) {
2563 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2564 return err;
2565 }
2566 rssi = le32_to_cpu(scbval.val);
2567 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2568 sinfo->signal = rssi;
2569
2570 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2571 sizeof(pktcnt));
2572 if (err) {
2573 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2574 return err;
2575 }
2576 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2577 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2578 BIT(NL80211_STA_INFO_TX_PACKETS) |
2579 BIT(NL80211_STA_INFO_TX_FAILED);
2580 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2581 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2582 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2583 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2584
2585 return 0;
2586}
2587
2588static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002589brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002590 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002591{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002592 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002593 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002594 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002595 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002596 u32 sta_flags;
2597 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002598 s32 total_rssi;
2599 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002600 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002601 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002602
Arend van Sprield96b8012012-12-05 15:26:02 +01002603 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002604 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002605 return -EIO;
2606
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002607 if (brcmf_is_ibssmode(ifp->vif))
2608 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2609
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002610 memset(&sta_info_le, 0, sizeof(sta_info_le));
2611 memcpy(&sta_info_le, mac, ETH_ALEN);
2612 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2613 &sta_info_le,
2614 sizeof(sta_info_le));
2615 is_tdls_peer = !err;
2616 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002617 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002618 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002619 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002620 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002621 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002622 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002623 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002624 }
2625 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2626 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2627 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2628 sta_flags = le32_to_cpu(sta_info_le.flags);
2629 brcmf_convert_sta_flags(sta_flags, sinfo);
2630 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2631 if (is_tdls_peer)
2632 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2633 else
2634 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2635 if (sta_flags & BRCMF_STA_ASSOC) {
2636 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2637 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2638 brcmf_fill_bss_param(ifp, sinfo);
2639 }
2640 if (sta_flags & BRCMF_STA_SCBSTATS) {
2641 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2642 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2643 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2644 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2645 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2646 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2647 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2648 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2649 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002650 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002651 sinfo->txrate.legacy =
2652 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002653 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002654 if (sinfo->rx_packets) {
2655 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002656 sinfo->rxrate.legacy =
2657 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002658 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002659 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2660 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2661 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2662 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2663 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2664 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002665 total_rssi = 0;
2666 count_rssi = 0;
2667 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2668 if (sta_info_le.rssi[i]) {
2669 sinfo->chain_signal_avg[count_rssi] =
2670 sta_info_le.rssi[i];
2671 sinfo->chain_signal[count_rssi] =
2672 sta_info_le.rssi[i];
2673 total_rssi += sta_info_le.rssi[i];
2674 count_rssi++;
2675 }
2676 }
2677 if (count_rssi) {
2678 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2679 sinfo->chains = count_rssi;
2680
2681 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2682 total_rssi /= count_rssi;
2683 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002684 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2685 &ifp->vif->sme_state)) {
2686 memset(&scb_val, 0, sizeof(scb_val));
2687 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2688 &scb_val, sizeof(scb_val));
2689 if (err) {
2690 brcmf_err("Could not get rssi (%d)\n", err);
2691 goto done;
2692 } else {
2693 rssi = le32_to_cpu(scb_val.val);
2694 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2695 sinfo->signal = rssi;
2696 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2697 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002698 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002699 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002701 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002702 return err;
2703}
2704
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002705static int
2706brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2707 int idx, u8 *mac, struct station_info *sinfo)
2708{
2709 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2710 struct brcmf_if *ifp = netdev_priv(ndev);
2711 s32 err;
2712
2713 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2714
2715 if (idx == 0) {
2716 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2717 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2718 &cfg->assoclist,
2719 sizeof(cfg->assoclist));
2720 if (err) {
2721 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2722 err);
2723 cfg->assoclist.count = 0;
2724 return -EOPNOTSUPP;
2725 }
2726 }
2727 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2728 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2729 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2730 }
2731 return -ENOENT;
2732}
2733
Arend van Spriel5b435de2011-10-05 13:19:03 +02002734static s32
2735brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2736 bool enabled, s32 timeout)
2737{
2738 s32 pm;
2739 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002740 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002741 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002742
Arend van Sprield96b8012012-12-05 15:26:02 +01002743 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002744
2745 /*
2746 * Powersave enable/disable request is coming from the
2747 * cfg80211 even before the interface is up. In that
2748 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002749 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002750 * FW later while initializing the dongle
2751 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002752 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002753 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002754
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002755 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756 goto done;
2757 }
2758
2759 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002760 /* Do not enable the power save after assoc if it is a p2p interface */
2761 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2762 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2763 pm = PM_OFF;
2764 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002765 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766
Arend van Sprielc1179032012-10-22 13:55:33 -07002767 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002768 if (err) {
2769 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002770 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002771 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002772 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002773 }
2774done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002775 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002776 return err;
2777}
2778
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002779static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002780 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002781{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002782 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002783 struct ieee80211_channel *notify_channel;
2784 struct cfg80211_bss *bss;
2785 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002786 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002787 u16 channel;
2788 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002789 u16 notify_capability;
2790 u16 notify_interval;
2791 u8 *notify_ie;
2792 size_t notify_ielen;
2793 s32 notify_signal;
2794
2795 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002796 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 return 0;
2798 }
2799
Franky Lin83cf17a2013-04-11 13:28:50 +02002800 if (!bi->ctl_ch) {
2801 ch.chspec = le16_to_cpu(bi->chanspec);
2802 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002803 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002804 }
2805 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806
2807 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002808 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002809 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002810 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811
2812 freq = ieee80211_channel_to_frequency(channel, band->band);
2813 notify_channel = ieee80211_get_channel(wiphy, freq);
2814
Arend van Spriel5b435de2011-10-05 13:19:03 +02002815 notify_capability = le16_to_cpu(bi->capability);
2816 notify_interval = le16_to_cpu(bi->beacon_period);
2817 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2818 notify_ielen = le32_to_cpu(bi->ie_length);
2819 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2820
Arend van Spriel16886732012-12-05 15:26:04 +01002821 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2822 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2823 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2824 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2825 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002826
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002827 bss = cfg80211_inform_bss(wiphy, notify_channel,
2828 CFG80211_BSS_FTYPE_UNKNOWN,
2829 (const u8 *)bi->BSSID,
2830 0, notify_capability,
2831 notify_interval, notify_ie,
2832 notify_ielen, notify_signal,
2833 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002834
Franky Line78946e2011-11-10 20:30:34 +01002835 if (!bss)
2836 return -ENOMEM;
2837
Johannes Berg5b112d32013-02-01 01:49:58 +01002838 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002839
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002840 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002841}
2842
Roland Vossen6f09be02011-10-18 14:03:02 +02002843static struct brcmf_bss_info_le *
2844next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2845{
2846 if (bss == NULL)
2847 return list->bss_info_le;
2848 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2849 le32_to_cpu(bss->length));
2850}
2851
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002852static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002853{
2854 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002855 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856 s32 err = 0;
2857 int i;
2858
Hante Meulemanef8596e2014-09-30 10:23:13 +02002859 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002860 if (bss_list->count != 0 &&
2861 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002862 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2863 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002864 return -EOPNOTSUPP;
2865 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002866 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002867 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002868 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002869 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002870 if (err)
2871 break;
2872 }
2873 return err;
2874}
2875
Hante Meulemanb0a79082015-12-10 13:43:07 +01002876static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2877 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002879 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002880 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002881 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002882 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002883 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002884 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885 u8 *buf = NULL;
2886 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002887 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002888 u16 notify_capability;
2889 u16 notify_interval;
2890 u8 *notify_ie;
2891 size_t notify_ielen;
2892 s32 notify_signal;
2893
Arend van Sprield96b8012012-12-05 15:26:02 +01002894 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002895
2896 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2897 if (buf == NULL) {
2898 err = -ENOMEM;
2899 goto CleanUp;
2900 }
2901
2902 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2903
Arend van Sprielac24be62012-10-22 10:36:23 -07002904 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2905 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002906 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002907 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002908 goto CleanUp;
2909 }
2910
Roland Vossend34bf642011-10-18 14:03:01 +02002911 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002912
Franky Lin83cf17a2013-04-11 13:28:50 +02002913 ch.chspec = le16_to_cpu(bi->chanspec);
2914 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002915
Franky Lin83cf17a2013-04-11 13:28:50 +02002916 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002917 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002918 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002919 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002920
Rafał Miłecki4712d882016-05-20 13:38:57 +02002921 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002922 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002923 notify_channel = ieee80211_get_channel(wiphy, freq);
2924
Arend van Spriel5b435de2011-10-05 13:19:03 +02002925 notify_capability = le16_to_cpu(bi->capability);
2926 notify_interval = le16_to_cpu(bi->beacon_period);
2927 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2928 notify_ielen = le32_to_cpu(bi->ie_length);
2929 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2930
Rafał Miłecki4712d882016-05-20 13:38:57 +02002931 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002932 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2933 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2934 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002935
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002936 bss = cfg80211_inform_bss(wiphy, notify_channel,
2937 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2938 notify_capability, notify_interval,
2939 notify_ie, notify_ielen, notify_signal,
2940 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002941
Franky Line78946e2011-11-10 20:30:34 +01002942 if (!bss) {
2943 err = -ENOMEM;
2944 goto CleanUp;
2945 }
2946
Johannes Berg5b112d32013-02-01 01:49:58 +01002947 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002948
Arend van Spriel5b435de2011-10-05 13:19:03 +02002949CleanUp:
2950
2951 kfree(buf);
2952
Arend van Sprield96b8012012-12-05 15:26:02 +01002953 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002954
2955 return err;
2956}
2957
Hante Meuleman89286dc2013-02-08 15:53:46 +01002958static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2959 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002960{
Roland Vossend34bf642011-10-18 14:03:01 +02002961 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002962 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002963 u16 beacon_interval;
2964 u8 dtim_period;
2965 size_t ie_len;
2966 u8 *ie;
2967 s32 err = 0;
2968
Arend van Sprield96b8012012-12-05 15:26:02 +01002969 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002970 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002971 return err;
2972
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002973 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002974 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002975 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002976 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002977 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002978 goto update_bss_info_out;
2979 }
2980
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002981 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2982 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002983 if (err)
2984 goto update_bss_info_out;
2985
2986 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2987 ie_len = le32_to_cpu(bi->ie_length);
2988 beacon_interval = le16_to_cpu(bi->beacon_period);
2989
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002990 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002991 if (tim)
2992 dtim_period = tim->data[1];
2993 else {
2994 /*
2995 * active scan was done so we could not get dtim
2996 * information out of probe response.
2997 * so we speficially query dtim information to dongle.
2998 */
2999 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07003000 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003001 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003002 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003003 goto update_bss_info_out;
3004 }
3005 dtim_period = (u8)var;
3006 }
3007
Arend van Spriel5b435de2011-10-05 13:19:03 +02003008update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003009 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003010 return err;
3011}
3012
Hante Meuleman18e2f612013-02-08 15:53:49 +01003013void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003014{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003015 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003016
Arend van Sprielc1179032012-10-22 13:55:33 -07003017 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003018 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003019 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003020 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003021 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003022 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3023 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003024}
3025
Hante Meulemane756af52012-09-11 21:18:52 +02003026static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3027{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003028 struct brcmf_cfg80211_info *cfg =
3029 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003030 escan_timeout_work);
3031
Hante Meulemanef8596e2014-09-30 10:23:13 +02003032 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003033 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003034}
3035
3036static void brcmf_escan_timeout(unsigned long data)
3037{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003038 struct brcmf_cfg80211_info *cfg =
3039 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003040
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003041 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003042 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003043 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003044 }
3045}
3046
3047static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003048brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3049 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003050 struct brcmf_bss_info_le *bss_info_le)
3051{
Franky Lin83cf17a2013-04-11 13:28:50 +02003052 struct brcmu_chan ch_bss, ch_bss_info_le;
3053
3054 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3055 cfg->d11inf.decchspec(&ch_bss);
3056 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3057 cfg->d11inf.decchspec(&ch_bss_info_le);
3058
Hante Meulemane756af52012-09-11 21:18:52 +02003059 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003060 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003061 bss_info_le->SSID_len == bss->SSID_len &&
3062 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003063 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3064 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003065 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3066 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3067
Hante Meulemane756af52012-09-11 21:18:52 +02003068 /* preserve max RSSI if the measurements are
3069 * both on-channel or both off-channel
3070 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003071 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003072 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003073 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3074 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003075 /* preserve the on-channel rssi measurement
3076 * if the new measurement is off channel
3077 */
3078 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003079 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003080 }
3081 return 1;
3082 }
3083 return 0;
3084}
3085
3086static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003087brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003088 const struct brcmf_event_msg *e, void *data)
3089{
Arend van Spriel19937322012-11-05 16:22:32 -08003090 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003091 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003092 struct brcmf_escan_result_le *escan_result_le;
3093 struct brcmf_bss_info_le *bss_info_le;
3094 struct brcmf_bss_info_le *bss = NULL;
3095 u32 bi_length;
3096 struct brcmf_scan_results *list;
3097 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003098 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003099
Arend van Spriel5c36b992012-11-14 18:46:05 -08003100 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003101
Arend van Spriela0f472a2013-04-05 10:57:49 +02003102 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003103 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003104 return -EPERM;
3105 }
3106
3107 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003108 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003109 escan_result_le = (struct brcmf_escan_result_le *) data;
3110 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003111 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003112 goto exit;
3113 }
Hante Meulemane756af52012-09-11 21:18:52 +02003114 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003115 brcmf_err("Invalid bss_count %d: ignoring\n",
3116 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003117 goto exit;
3118 }
3119 bss_info_le = &escan_result_le->bss_info_le;
3120
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003121 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3122 goto exit;
3123
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003124 if (!cfg->internal_escan && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003125 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3126 goto exit;
3127 }
3128
Hante Meulemane756af52012-09-11 21:18:52 +02003129 bi_length = le32_to_cpu(bss_info_le->length);
3130 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3131 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003132 brcmf_err("Invalid bss_info length %d: ignoring\n",
3133 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003134 goto exit;
3135 }
3136
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003137 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003138 BIT(NL80211_IFTYPE_ADHOC))) {
3139 if (le16_to_cpu(bss_info_le->capability) &
3140 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003141 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003142 goto exit;
3143 }
3144 }
3145
3146 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003147 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003148 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003149 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003150 goto exit;
3151 }
3152
3153 for (i = 0; i < list->count; i++) {
3154 bss = bss ? (struct brcmf_bss_info_le *)
3155 ((unsigned char *)bss +
3156 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003157 if (brcmf_compare_update_same_bss(cfg, bss,
3158 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003159 goto exit;
3160 }
Hante Meulemand5367332016-02-17 11:26:51 +01003161 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3162 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003163 list->version = le32_to_cpu(bss_info_le->version);
3164 list->buflen += bi_length;
3165 list->count++;
3166 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003167 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003168 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3169 goto exit;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003170 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003171 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003172 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003173 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003174 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003175 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3176 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003177 }
3178exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003179 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003180}
3181
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003182static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003183{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003184 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3185 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003186 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3187 /* Init scan_timeout timer */
3188 init_timer(&cfg->escan_timeout);
3189 cfg->escan_timeout.data = (unsigned long) cfg;
3190 cfg->escan_timeout.function = brcmf_escan_timeout;
3191 INIT_WORK(&cfg->escan_timeout_work,
3192 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003193}
3194
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003195static struct cfg80211_scan_request *
3196brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3197 struct cfg80211_scan_request *req;
3198 size_t req_size;
3199
3200 req_size = sizeof(*req) +
3201 n_netinfo * sizeof(req->channels[0]) +
3202 n_netinfo * sizeof(*req->ssids);
3203
3204 req = kzalloc(req_size, GFP_KERNEL);
3205 if (req) {
3206 req->wiphy = wiphy;
3207 req->ssids = (void *)(&req->channels[0]) +
3208 n_netinfo * sizeof(req->channels[0]);
3209 }
3210 return req;
3211}
3212
3213static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3214 u8 *ssid, u8 ssid_len, u8 channel)
3215{
3216 struct ieee80211_channel *chan;
3217 enum nl80211_band band;
3218 int freq;
3219
3220 if (channel <= CH_MAX_2G_CHANNEL)
3221 band = NL80211_BAND_2GHZ;
3222 else
3223 band = NL80211_BAND_5GHZ;
3224
3225 freq = ieee80211_channel_to_frequency(channel, band);
3226 if (!freq)
3227 return -EINVAL;
3228
3229 chan = ieee80211_get_channel(req->wiphy, freq);
3230 if (!chan)
3231 return -EINVAL;
3232
3233 req->channels[req->n_channels++] = chan;
3234 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3235 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3236
3237 return 0;
3238}
3239
3240static int brcmf_start_internal_escan(struct brcmf_if *ifp,
3241 struct cfg80211_scan_request *request)
3242{
3243 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3244 int err;
3245
3246 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3247 /* Abort any on-going scan */
3248 brcmf_abort_scanning(cfg);
3249 }
3250
3251 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3252 cfg->escan_info.run = brcmf_run_escan;
3253 err = brcmf_do_escan(ifp, request);
3254 if (err) {
3255 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3256 return err;
3257 }
3258 cfg->internal_escan = true;
3259 return 0;
3260}
3261
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003262static struct brcmf_pno_net_info_le *
3263brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3264{
3265 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3266 struct brcmf_pno_net_info_le *netinfo;
3267
3268 switch (pfn_v1->version) {
3269 default:
3270 WARN_ON(1);
3271 /* fall-thru */
3272 case cpu_to_le32(1):
3273 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3274 break;
3275 case cpu_to_le32(2):
3276 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3277 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3278 break;
3279 }
3280
3281 return netinfo;
3282}
3283
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003284/* PFN result doesn't have all the info which are required by the supplicant
3285 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3286 * via wl_inform_single_bss in the required format. Escan does require the
3287 * scan request in the form of cfg80211_scan_request. For timebeing, create
3288 * cfg80211_scan_request one out of the received PNO event.
3289 */
3290static s32
3291brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3292 const struct brcmf_event_msg *e, void *data)
3293{
3294 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3295 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3296 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003297 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003298 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003299 struct brcmf_pno_scanresults_le *pfn_result;
3300 u32 result_count;
3301 u32 status;
3302
3303 brcmf_dbg(SCAN, "Enter\n");
3304
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003305 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3306 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3307 return 0;
3308 }
3309
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003310 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3311 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3312 return 0;
3313 }
3314
3315 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3316 result_count = le32_to_cpu(pfn_result->count);
3317 status = le32_to_cpu(pfn_result->status);
3318
3319 /* PFN event is limited to fit 512 bytes so we may get
3320 * multiple NET_FOUND events. For now place a warning here.
3321 */
3322 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3323 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003324 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003325 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3326 goto out_err;
3327 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003328 request = brcmf_alloc_internal_escan_request(wiphy,
3329 result_count);
3330 if (!request) {
3331 err = -ENOMEM;
3332 goto out_err;
3333 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003334
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003335 data += sizeof(struct brcmf_pno_scanresults_le);
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003336 netinfo_start = brcmf_get_netinfo_array(pfn_result);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003337
3338 for (i = 0; i < result_count; i++) {
3339 netinfo = &netinfo_start[i];
3340 if (!netinfo) {
3341 brcmf_err("Invalid netinfo ptr. index: %d\n",
3342 i);
3343 err = -EINVAL;
3344 goto out_err;
3345 }
3346
3347 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3348 netinfo->SSID, netinfo->channel);
3349 err = brcmf_internal_escan_add_info(request,
3350 netinfo->SSID,
3351 netinfo->SSID_len,
3352 netinfo->channel);
3353 if (err)
3354 goto out_err;
3355 }
3356
3357 err = brcmf_start_internal_escan(ifp, request);
3358 if (!err)
3359 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003360
3361out_err:
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003362 cfg80211_sched_scan_stopped(wiphy);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003363free_req:
3364 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003365 return err;
3366}
3367
3368static int
3369brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3370 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003371 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003372{
3373 struct brcmf_if *ifp = netdev_priv(ndev);
3374 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003375
3376 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003377 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003378
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003379 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3380 brcmf_err("Scanning suppressed: status (%lu)\n",
3381 cfg->scan_status);
3382 return -EAGAIN;
3383 }
3384
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003385 if (req->n_match_sets <= 0) {
3386 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3387 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003388 return -EINVAL;
3389 }
3390
Arend Van Spriel3e486112016-11-23 10:25:27 +00003391 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003392}
3393
3394static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3395 struct net_device *ndev)
3396{
3397 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003398 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003399
3400 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielac551362016-11-23 10:25:22 +00003401 brcmf_pno_clean(ifp);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003402 if (cfg->internal_escan)
Arend Van Sprielac551362016-11-23 10:25:22 +00003403 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003404 return 0;
3405}
3406
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003407static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003408{
3409 if (ms < 1000 / HZ) {
3410 cond_resched();
3411 mdelay(ms);
3412 } else {
3413 msleep(ms);
3414 }
3415}
3416
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003417static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3418 u8 *pattern, u32 patternsize, u8 *mask,
3419 u32 packet_offset)
3420{
3421 struct brcmf_fil_wowl_pattern_le *filter;
3422 u32 masksize;
3423 u32 patternoffset;
3424 u8 *buf;
3425 u32 bufsize;
3426 s32 ret;
3427
3428 masksize = (patternsize + 7) / 8;
3429 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3430
3431 bufsize = sizeof(*filter) + patternsize + masksize;
3432 buf = kzalloc(bufsize, GFP_KERNEL);
3433 if (!buf)
3434 return -ENOMEM;
3435 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3436
3437 memcpy(filter->cmd, cmd, 4);
3438 filter->masksize = cpu_to_le32(masksize);
3439 filter->offset = cpu_to_le32(packet_offset);
3440 filter->patternoffset = cpu_to_le32(patternoffset);
3441 filter->patternsize = cpu_to_le32(patternsize);
3442 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3443
3444 if ((mask) && (masksize))
3445 memcpy(buf + sizeof(*filter), mask, masksize);
3446 if ((pattern) && (patternsize))
3447 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3448
3449 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3450
3451 kfree(buf);
3452 return ret;
3453}
3454
Hante Meuleman3021ad92016-01-05 11:05:45 +01003455static s32
3456brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3457 void *data)
3458{
3459 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3460 struct brcmf_pno_scanresults_le *pfn_result;
3461 struct brcmf_pno_net_info_le *netinfo;
3462
3463 brcmf_dbg(SCAN, "Enter\n");
3464
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003465 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3466 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3467 return 0;
3468 }
3469
Hante Meuleman3021ad92016-01-05 11:05:45 +01003470 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3471
3472 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3473 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3474 return 0;
3475 }
3476
3477 if (le32_to_cpu(pfn_result->count) < 1) {
3478 brcmf_err("Invalid result count, expected 1 (%d)\n",
3479 le32_to_cpu(pfn_result->count));
3480 return -EINVAL;
3481 }
3482
3483 data += sizeof(struct brcmf_pno_scanresults_le);
3484 netinfo = (struct brcmf_pno_net_info_le *)data;
3485 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3486 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3487 cfg->wowl.nd->n_channels = 1;
3488 cfg->wowl.nd->channels[0] =
3489 ieee80211_channel_to_frequency(netinfo->channel,
3490 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3491 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3492 cfg->wowl.nd_info->n_matches = 1;
3493 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3494
3495 /* Inform (the resume task) that the net detect information was recvd */
3496 cfg->wowl.nd_data_completed = true;
3497 wake_up(&cfg->wowl.nd_data_wait);
3498
3499 return 0;
3500}
3501
Hante Meulemanaeb64222015-10-29 20:33:19 +01003502#ifdef CONFIG_PM
3503
3504static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3505{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003506 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003507 struct brcmf_wowl_wakeind_le wake_ind_le;
3508 struct cfg80211_wowlan_wakeup wakeup_data;
3509 struct cfg80211_wowlan_wakeup *wakeup;
3510 u32 wakeind;
3511 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003512 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003513
3514 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3515 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003516 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003517 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3518 return;
3519 }
3520
3521 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3522 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003523 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3524 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003525 wakeup = &wakeup_data;
3526 memset(&wakeup_data, 0, sizeof(wakeup_data));
3527 wakeup_data.pattern_idx = -1;
3528
3529 if (wakeind & BRCMF_WOWL_MAGIC) {
3530 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3531 wakeup_data.magic_pkt = true;
3532 }
3533 if (wakeind & BRCMF_WOWL_DIS) {
3534 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3535 wakeup_data.disconnect = true;
3536 }
3537 if (wakeind & BRCMF_WOWL_BCN) {
3538 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3539 wakeup_data.disconnect = true;
3540 }
3541 if (wakeind & BRCMF_WOWL_RETR) {
3542 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3543 wakeup_data.disconnect = true;
3544 }
3545 if (wakeind & BRCMF_WOWL_NET) {
3546 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3547 /* For now always map to pattern 0, no API to get
3548 * correct information available at the moment.
3549 */
3550 wakeup_data.pattern_idx = 0;
3551 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003552 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3553 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3554 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3555 cfg->wowl.nd_data_completed,
3556 BRCMF_ND_INFO_TIMEOUT);
3557 if (!timeout)
3558 brcmf_err("No result for wowl net detect\n");
3559 else
3560 wakeup_data.net_detect = cfg->wowl.nd_info;
3561 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003562 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3563 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3564 wakeup_data.gtk_rekey_failure = true;
3565 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003566 } else {
3567 wakeup = NULL;
3568 }
3569 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3570}
3571
3572#else
3573
3574static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3575{
3576}
3577
3578#endif /* CONFIG_PM */
3579
Arend van Spriel5b435de2011-10-05 13:19:03 +02003580static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3581{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003582 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3583 struct net_device *ndev = cfg_to_ndev(cfg);
3584 struct brcmf_if *ifp = netdev_priv(ndev);
3585
Arend van Sprield96b8012012-12-05 15:26:02 +01003586 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003587
Hante Meuleman3021ad92016-01-05 11:05:45 +01003588 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003589 brcmf_report_wowl_wakeind(wiphy, ifp);
3590 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3591 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003592 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3593 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003594 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003595 cfg->wowl.pre_pmmode);
3596 cfg->wowl.active = false;
3597 if (cfg->wowl.nd_enabled) {
3598 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3599 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3600 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3601 brcmf_notify_sched_scan_results);
3602 cfg->wowl.nd_enabled = false;
3603 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003604 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003605 return 0;
3606}
3607
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003608static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3609 struct brcmf_if *ifp,
3610 struct cfg80211_wowlan *wowl)
3611{
3612 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003613 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003614 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003615
3616 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3617
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003618 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3619 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003620 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003621 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3622
3623 wowl_config = 0;
3624 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003625 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003626 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003627 wowl_config |= BRCMF_WOWL_MAGIC;
3628 if ((wowl->patterns) && (wowl->n_patterns)) {
3629 wowl_config |= BRCMF_WOWL_NET;
3630 for (i = 0; i < wowl->n_patterns; i++) {
3631 brcmf_config_wowl_pattern(ifp, "add",
3632 (u8 *)wowl->patterns[i].pattern,
3633 wowl->patterns[i].pattern_len,
3634 (u8 *)wowl->patterns[i].mask,
3635 wowl->patterns[i].pkt_offset);
3636 }
3637 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003638 if (wowl->nd_config) {
3639 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3640 wowl->nd_config);
3641 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3642
3643 cfg->wowl.nd_data_completed = false;
3644 cfg->wowl.nd_enabled = true;
3645 /* Now reroute the event for PFN to the wowl function. */
3646 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3647 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3648 brcmf_wowl_nd_results);
3649 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003650 if (wowl->gtk_rekey_failure)
3651 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003652 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3653 wowl_config |= BRCMF_WOWL_UNASSOC;
3654
Hante Meulemana7ed7822016-09-19 12:09:58 +01003655 memcpy(&wowl_wakeind, "clear", 6);
3656 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3657 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003658 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3659 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3660 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003661 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003662}
3663
Arend van Spriel5b435de2011-10-05 13:19:03 +02003664static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003665 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003666{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003667 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3668 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003669 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003670 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003671
Arend van Sprield96b8012012-12-05 15:26:02 +01003672 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003673
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003674 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003675 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003676 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003677 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003678 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003679
Hante Meuleman3021ad92016-01-05 11:05:45 +01003680 /* Stop scheduled scan */
3681 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3682 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3683
Arend van Spriel7d641072012-10-22 13:55:39 -07003684 /* end any scanning */
3685 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003686 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003687
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003688 if (wowl == NULL) {
3689 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3690 list_for_each_entry(vif, &cfg->vif_list, list) {
3691 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3692 continue;
3693 /* While going to suspend if associated with AP
3694 * disassociate from AP to save power while system is
3695 * in suspended state
3696 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003697 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003698 /* Make sure WPA_Supplicant receives all the event
3699 * generated due to DISASSOC call to the fw to keep
3700 * the state fw and WPA_Supplicant state consistent
3701 */
3702 brcmf_delay(500);
3703 }
3704 /* Configure MPC */
3705 brcmf_set_mpc(ifp, 1);
3706
3707 } else {
3708 /* Configure WOWL paramaters */
3709 brcmf_configure_wowl(cfg, ifp, wowl);
3710 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003711
Arend van Spriel7d641072012-10-22 13:55:39 -07003712exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003713 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003714 /* clear any scanning activity */
3715 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003716 return 0;
3717}
3718
3719static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003720brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003721{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003722 struct brcmf_pmk_list_le *pmk_list;
3723 int i;
3724 u32 npmk;
3725 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003726
Hante Meuleman6c404f32015-12-10 13:43:03 +01003727 pmk_list = &cfg->pmk_list;
3728 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003729
Hante Meuleman6c404f32015-12-10 13:43:03 +01003730 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3731 for (i = 0; i < npmk; i++)
3732 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003733
Hante Meuleman6c404f32015-12-10 13:43:03 +01003734 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3735 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003736
3737 return err;
3738}
3739
3740static s32
3741brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3742 struct cfg80211_pmksa *pmksa)
3743{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003744 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003745 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003746 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3747 s32 err;
3748 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003749
Arend van Sprield96b8012012-12-05 15:26:02 +01003750 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003751 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003752 return -EIO;
3753
Hante Meuleman6c404f32015-12-10 13:43:03 +01003754 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3755 for (i = 0; i < npmk; i++)
3756 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003757 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003758 if (i < BRCMF_MAXPMKID) {
3759 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3760 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3761 if (i == npmk) {
3762 npmk++;
3763 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003764 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003765 } else {
3766 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3767 return -EINVAL;
3768 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769
Hante Meuleman6c404f32015-12-10 13:43:03 +01003770 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3771 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3772 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3773 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3774 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003775
Hante Meuleman6c404f32015-12-10 13:43:03 +01003776 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777
Arend van Sprield96b8012012-12-05 15:26:02 +01003778 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003779 return err;
3780}
3781
3782static s32
3783brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003784 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003785{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003786 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003787 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003788 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3789 s32 err;
3790 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003791
Arend van Sprield96b8012012-12-05 15:26:02 +01003792 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003793 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003794 return -EIO;
3795
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003796 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003797
Hante Meuleman6c404f32015-12-10 13:43:03 +01003798 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3799 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003800 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003801 break;
3802
Hante Meuleman6c404f32015-12-10 13:43:03 +01003803 if ((npmk > 0) && (i < npmk)) {
3804 for (; i < (npmk - 1); i++) {
3805 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3806 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003807 WLAN_PMKID_LEN);
3808 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003809 memset(&pmk[i], 0, sizeof(*pmk));
3810 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3811 } else {
3812 brcmf_err("Cache entry not found\n");
3813 return -EINVAL;
3814 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003815
Hante Meuleman6c404f32015-12-10 13:43:03 +01003816 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003817
Arend van Sprield96b8012012-12-05 15:26:02 +01003818 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003819 return err;
3820
3821}
3822
3823static s32
3824brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3825{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003826 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003827 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003828 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829
Arend van Sprield96b8012012-12-05 15:26:02 +01003830 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003831 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003832 return -EIO;
3833
Hante Meuleman6c404f32015-12-10 13:43:03 +01003834 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3835 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003836
Arend van Sprield96b8012012-12-05 15:26:02 +01003837 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003838 return err;
3839
3840}
3841
Hante Meuleman1f170112013-02-06 18:40:38 +01003842static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003843{
3844 s32 err;
3845
3846 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003847 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003848 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003849 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003850 return err;
3851 }
3852 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003853 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003854 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003855 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003856 return err;
3857 }
3858 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003859 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003860 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003861 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003862 return err;
3863 }
3864
3865 return 0;
3866}
3867
3868static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3869{
3870 if (is_rsn_ie)
3871 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3872
3873 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3874}
3875
3876static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003877brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003878 const struct brcmf_vs_tlv *wpa_ie,
3879 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003880{
3881 u32 auth = 0; /* d11 open authentication */
3882 u16 count;
3883 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003884 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003885 u32 i;
3886 u32 wsec;
3887 u32 pval = 0;
3888 u32 gval = 0;
3889 u32 wpa_auth = 0;
3890 u32 offset;
3891 u8 *data;
3892 u16 rsn_cap;
3893 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003894 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003895
Arend van Sprield96b8012012-12-05 15:26:02 +01003896 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003897 if (wpa_ie == NULL)
3898 goto exit;
3899
3900 len = wpa_ie->len + TLV_HDR_LEN;
3901 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003902 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003903 if (!is_rsn_ie)
3904 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003905 else
3906 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003907
3908 /* check for multicast cipher suite */
3909 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3910 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003911 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003912 goto exit;
3913 }
3914
3915 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3916 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003917 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003918 goto exit;
3919 }
3920 offset += TLV_OUI_LEN;
3921
3922 /* pick up multicast cipher */
3923 switch (data[offset]) {
3924 case WPA_CIPHER_NONE:
3925 gval = 0;
3926 break;
3927 case WPA_CIPHER_WEP_40:
3928 case WPA_CIPHER_WEP_104:
3929 gval = WEP_ENABLED;
3930 break;
3931 case WPA_CIPHER_TKIP:
3932 gval = TKIP_ENABLED;
3933 break;
3934 case WPA_CIPHER_AES_CCM:
3935 gval = AES_ENABLED;
3936 break;
3937 default:
3938 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003939 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003940 goto exit;
3941 }
3942
3943 offset++;
3944 /* walk thru unicast cipher list and pick up what we recognize */
3945 count = data[offset] + (data[offset + 1] << 8);
3946 offset += WPA_IE_SUITE_COUNT_LEN;
3947 /* Check for unicast suite(s) */
3948 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3949 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003950 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003951 goto exit;
3952 }
3953 for (i = 0; i < count; i++) {
3954 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3955 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003956 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003957 goto exit;
3958 }
3959 offset += TLV_OUI_LEN;
3960 switch (data[offset]) {
3961 case WPA_CIPHER_NONE:
3962 break;
3963 case WPA_CIPHER_WEP_40:
3964 case WPA_CIPHER_WEP_104:
3965 pval |= WEP_ENABLED;
3966 break;
3967 case WPA_CIPHER_TKIP:
3968 pval |= TKIP_ENABLED;
3969 break;
3970 case WPA_CIPHER_AES_CCM:
3971 pval |= AES_ENABLED;
3972 break;
3973 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00003974 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003975 }
3976 offset++;
3977 }
3978 /* walk thru auth management suite list and pick up what we recognize */
3979 count = data[offset] + (data[offset + 1] << 8);
3980 offset += WPA_IE_SUITE_COUNT_LEN;
3981 /* Check for auth key management suite(s) */
3982 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3983 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003984 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003985 goto exit;
3986 }
3987 for (i = 0; i < count; i++) {
3988 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3989 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003990 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003991 goto exit;
3992 }
3993 offset += TLV_OUI_LEN;
3994 switch (data[offset]) {
3995 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003996 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003997 wpa_auth |= WPA_AUTH_NONE;
3998 break;
3999 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004000 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004001 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4002 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4003 break;
4004 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004005 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4007 (wpa_auth |= WPA_AUTH_PSK);
4008 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004009 case RSN_AKM_SHA256_PSK:
4010 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4011 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4012 break;
4013 case RSN_AKM_SHA256_1X:
4014 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4015 wpa_auth |= WPA2_AUTH_1X_SHA256;
4016 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004017 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004018 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004019 }
4020 offset++;
4021 }
4022
Hante Meuleman240d61a2016-02-17 11:27:10 +01004023 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004024 if (is_rsn_ie) {
4025 wme_bss_disable = 1;
4026 if ((offset + RSN_CAP_LEN) <= len) {
4027 rsn_cap = data[offset] + (data[offset + 1] << 8);
4028 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4029 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004030 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4031 brcmf_dbg(TRACE, "MFP Required\n");
4032 mfp = BRCMF_MFP_REQUIRED;
4033 /* Firmware only supports mfp required in
4034 * combination with WPA2_AUTH_PSK_SHA256 or
4035 * WPA2_AUTH_1X_SHA256.
4036 */
4037 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4038 WPA2_AUTH_1X_SHA256))) {
4039 err = -EINVAL;
4040 goto exit;
4041 }
4042 /* Firmware has requirement that WPA2_AUTH_PSK/
4043 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4044 * is to be included in the rsn ie.
4045 */
4046 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4047 wpa_auth |= WPA2_AUTH_PSK;
4048 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4049 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4050 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4051 brcmf_dbg(TRACE, "MFP Capable\n");
4052 mfp = BRCMF_MFP_CAPABLE;
4053 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004054 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004055 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004056 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004057 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004058 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004059 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004060 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004061 goto exit;
4062 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004063
4064 /* Skip PMKID cnt as it is know to be 0 for AP. */
4065 offset += RSN_PMKID_COUNT_LEN;
4066
4067 /* See if there is BIP wpa suite left for MFP */
4068 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4069 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4070 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4071 &data[offset],
4072 WPA_IE_MIN_OUI_LEN);
4073 if (err < 0) {
4074 brcmf_err("bip error %d\n", err);
4075 goto exit;
4076 }
4077 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004078 }
4079 /* FOR WPS , set SES_OW_ENABLED */
4080 wsec = (pval | gval | SES_OW_ENABLED);
4081
4082 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004083 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004084 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004085 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004086 goto exit;
4087 }
4088 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004089 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004090 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004091 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004092 goto exit;
4093 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004094 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4095 * will overwrite the values set by MFP
4096 */
4097 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4098 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4099 if (err < 0) {
4100 brcmf_err("mfp error %d\n", err);
4101 goto exit;
4102 }
4103 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004104 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004105 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004106 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004107 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004108 goto exit;
4109 }
4110
4111exit:
4112 return err;
4113}
4114
4115static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004116brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004117 struct parsed_vndr_ies *vndr_ies)
4118{
Hante Meuleman1a873342012-09-27 14:17:54 +02004119 struct brcmf_vs_tlv *vndrie;
4120 struct brcmf_tlv *ie;
4121 struct parsed_vndr_ie_info *parsed_info;
4122 s32 remaining_len;
4123
4124 remaining_len = (s32)vndr_ie_len;
4125 memset(vndr_ies, 0, sizeof(*vndr_ies));
4126
4127 ie = (struct brcmf_tlv *)vndr_ie_buf;
4128 while (ie) {
4129 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4130 goto next;
4131 vndrie = (struct brcmf_vs_tlv *)ie;
4132 /* len should be bigger than OUI length + one */
4133 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004134 brcmf_err("invalid vndr ie. length is too small %d\n",
4135 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004136 goto next;
4137 }
4138 /* if wpa or wme ie, do not add ie */
4139 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4140 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4141 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004142 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004143 goto next;
4144 }
4145
4146 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4147
4148 /* save vndr ie information */
4149 parsed_info->ie_ptr = (char *)vndrie;
4150 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4151 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4152
4153 vndr_ies->count++;
4154
Arend van Sprield96b8012012-12-05 15:26:02 +01004155 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4156 parsed_info->vndrie.oui[0],
4157 parsed_info->vndrie.oui[1],
4158 parsed_info->vndrie.oui[2],
4159 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004160
Arend van Spriel9f440b72013-02-08 15:53:36 +01004161 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004162 break;
4163next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004164 remaining_len -= (ie->len + TLV_HDR_LEN);
4165 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004166 ie = NULL;
4167 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004168 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4169 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004170 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004171 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004172}
4173
4174static u32
4175brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4176{
4177
Hante Meuleman1a873342012-09-27 14:17:54 +02004178 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4179 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4180
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304181 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004182
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304183 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004184
4185 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4186
4187 return ie_len + VNDR_IE_HDR_SIZE;
4188}
4189
Arend van Spriel1332e262012-11-05 16:22:18 -08004190s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4191 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004192{
Arend van Spriel1332e262012-11-05 16:22:18 -08004193 struct brcmf_if *ifp;
4194 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004195 s32 err = 0;
4196 u8 *iovar_ie_buf;
4197 u8 *curr_ie_buf;
4198 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004199 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004200 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004201 u32 del_add_ie_buf_len = 0;
4202 u32 total_ie_buf_len = 0;
4203 u32 parsed_ie_buf_len = 0;
4204 struct parsed_vndr_ies old_vndr_ies;
4205 struct parsed_vndr_ies new_vndr_ies;
4206 struct parsed_vndr_ie_info *vndrie_info;
4207 s32 i;
4208 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004209 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004210
Arend van Spriel1332e262012-11-05 16:22:18 -08004211 if (!vif)
4212 return -ENODEV;
4213 ifp = vif->ifp;
4214 saved_ie = &vif->saved_ie;
4215
Hante Meuleman37a869e2015-10-29 20:33:17 +01004216 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4217 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004218 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4219 if (!iovar_ie_buf)
4220 return -ENOMEM;
4221 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004222 switch (pktflag) {
4223 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4224 mgmt_ie_buf = saved_ie->probe_req_ie;
4225 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4226 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4227 break;
4228 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4229 mgmt_ie_buf = saved_ie->probe_res_ie;
4230 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4231 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4232 break;
4233 case BRCMF_VNDR_IE_BEACON_FLAG:
4234 mgmt_ie_buf = saved_ie->beacon_ie;
4235 mgmt_ie_len = &saved_ie->beacon_ie_len;
4236 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4237 break;
4238 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4239 mgmt_ie_buf = saved_ie->assoc_req_ie;
4240 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4241 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4242 break;
4243 default:
4244 err = -EPERM;
4245 brcmf_err("not suitable type\n");
4246 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004247 }
4248
4249 if (vndr_ie_len > mgmt_ie_buf_len) {
4250 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004251 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004252 goto exit;
4253 }
4254
4255 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4256 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4257 ptr = curr_ie_buf;
4258 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4259 for (i = 0; i < new_vndr_ies.count; i++) {
4260 vndrie_info = &new_vndr_ies.ie_info[i];
4261 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4262 vndrie_info->ie_len);
4263 parsed_ie_buf_len += vndrie_info->ie_len;
4264 }
4265 }
4266
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004267 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004268 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4269 (memcmp(mgmt_ie_buf, curr_ie_buf,
4270 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004271 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004272 goto exit;
4273 }
4274
4275 /* parse old vndr_ie */
4276 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4277
4278 /* make a command to delete old ie */
4279 for (i = 0; i < old_vndr_ies.count; i++) {
4280 vndrie_info = &old_vndr_ies.ie_info[i];
4281
Arend van Sprield96b8012012-12-05 15:26:02 +01004282 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4283 vndrie_info->vndrie.id,
4284 vndrie_info->vndrie.len,
4285 vndrie_info->vndrie.oui[0],
4286 vndrie_info->vndrie.oui[1],
4287 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004288
4289 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4290 vndrie_info->ie_ptr,
4291 vndrie_info->ie_len,
4292 "del");
4293 curr_ie_buf += del_add_ie_buf_len;
4294 total_ie_buf_len += del_add_ie_buf_len;
4295 }
4296 }
4297
4298 *mgmt_ie_len = 0;
4299 /* Add if there is any extra IE */
4300 if (mgmt_ie_buf && parsed_ie_buf_len) {
4301 ptr = mgmt_ie_buf;
4302
4303 remained_buf_len = mgmt_ie_buf_len;
4304
4305 /* make a command to add new ie */
4306 for (i = 0; i < new_vndr_ies.count; i++) {
4307 vndrie_info = &new_vndr_ies.ie_info[i];
4308
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004309 /* verify remained buf size before copy data */
4310 if (remained_buf_len < (vndrie_info->vndrie.len +
4311 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004312 brcmf_err("no space in mgmt_ie_buf: len left %d",
4313 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004314 break;
4315 }
4316 remained_buf_len -= (vndrie_info->ie_len +
4317 VNDR_IE_VSIE_OFFSET);
4318
Arend van Sprield96b8012012-12-05 15:26:02 +01004319 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4320 vndrie_info->vndrie.id,
4321 vndrie_info->vndrie.len,
4322 vndrie_info->vndrie.oui[0],
4323 vndrie_info->vndrie.oui[1],
4324 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004325
4326 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4327 vndrie_info->ie_ptr,
4328 vndrie_info->ie_len,
4329 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004330
4331 /* save the parsed IE in wl struct */
4332 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4333 vndrie_info->ie_len);
4334 *mgmt_ie_len += vndrie_info->ie_len;
4335
4336 curr_ie_buf += del_add_ie_buf_len;
4337 total_ie_buf_len += del_add_ie_buf_len;
4338 }
4339 }
4340 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004341 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004342 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004343 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004344 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004345 }
4346
4347exit:
4348 kfree(iovar_ie_buf);
4349 return err;
4350}
4351
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004352s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4353{
4354 s32 pktflags[] = {
4355 BRCMF_VNDR_IE_PRBREQ_FLAG,
4356 BRCMF_VNDR_IE_PRBRSP_FLAG,
4357 BRCMF_VNDR_IE_BEACON_FLAG
4358 };
4359 int i;
4360
4361 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4362 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4363
4364 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4365 return 0;
4366}
4367
Hante Meuleman1a873342012-09-27 14:17:54 +02004368static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004369brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4370 struct cfg80211_beacon_data *beacon)
4371{
4372 s32 err;
4373
4374 /* Set Beacon IEs to FW */
4375 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4376 beacon->tail, beacon->tail_len);
4377 if (err) {
4378 brcmf_err("Set Beacon IE Failed\n");
4379 return err;
4380 }
4381 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4382
4383 /* Set Probe Response IEs to FW */
4384 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4385 beacon->proberesp_ies,
4386 beacon->proberesp_ies_len);
4387 if (err)
4388 brcmf_err("Set Probe Resp IE Failed\n");
4389 else
4390 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4391
4392 return err;
4393}
4394
4395static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004396brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4397 struct cfg80211_ap_settings *settings)
4398{
4399 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004400 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004401 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004402 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004403 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004404 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004405 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004406 const struct brcmf_tlv *rsn_ie;
4407 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004408 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004409 enum nl80211_iftype dev_role;
4410 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004411 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004412 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004413 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004414 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004415
Arend van Spriel06c01582014-05-12 10:47:37 +02004416 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4417 settings->chandef.chan->hw_value,
4418 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004419 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004420 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4421 settings->ssid, settings->ssid_len, settings->auth_type,
4422 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004423 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004424 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004425
Arend van Spriel98027762014-12-21 12:43:53 +01004426 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004427 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4428 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004429 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004430 } else {
4431 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4432 settings->beacon.tail_len,
4433 WLAN_EID_COUNTRY);
4434 is_11d = country_ie ? 1 : 0;
4435 supports_11d = true;
4436 }
Arend van Spriel98027762014-12-21 12:43:53 +01004437
Hante Meuleman1a873342012-09-27 14:17:54 +02004438 memset(&ssid_le, 0, sizeof(ssid_le));
4439 if (settings->ssid == NULL || settings->ssid_len == 0) {
4440 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4441 ssid_ie = brcmf_parse_tlvs(
4442 (u8 *)&settings->beacon.head[ie_offset],
4443 settings->beacon.head_len - ie_offset,
4444 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004445 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004446 return -EINVAL;
4447
4448 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4449 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004450 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004451 } else {
4452 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4453 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4454 }
4455
Hante Meulemana44aa402014-12-03 21:05:33 +01004456 if (!mbss) {
4457 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004458 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004459 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004460
4461 /* find the RSN_IE */
4462 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4463 settings->beacon.tail_len, WLAN_EID_RSN);
4464
4465 /* find the WPA_IE */
4466 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4467 settings->beacon.tail_len);
4468
Hante Meuleman1a873342012-09-27 14:17:54 +02004469 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004470 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004471 if (wpa_ie != NULL) {
4472 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004473 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004474 if (err < 0)
4475 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004476 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004477 struct brcmf_vs_tlv *tmp_ie;
4478
4479 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4480
Hante Meuleman1a873342012-09-27 14:17:54 +02004481 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004482 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004483 if (err < 0)
4484 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004485 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004486 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004487 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004488 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004489 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004490
Rafał Miłecki8707e082016-05-27 21:07:19 +02004491 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004492 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004493 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004494 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4495 is_11d);
4496 if (err < 0) {
4497 brcmf_err("Regulatory Set Error, %d\n", err);
4498 goto exit;
4499 }
4500 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004501 if (settings->beacon_interval) {
4502 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4503 settings->beacon_interval);
4504 if (err < 0) {
4505 brcmf_err("Beacon Interval Set Error, %d\n",
4506 err);
4507 goto exit;
4508 }
4509 }
4510 if (settings->dtim_period) {
4511 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4512 settings->dtim_period);
4513 if (err < 0) {
4514 brcmf_err("DTIM Interval Set Error, %d\n", err);
4515 goto exit;
4516 }
4517 }
4518
Hante Meuleman8abffd82015-10-29 20:33:16 +01004519 if ((dev_role == NL80211_IFTYPE_AP) &&
4520 ((ifp->ifidx == 0) ||
4521 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004522 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4523 if (err < 0) {
4524 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4525 goto exit;
4526 }
4527 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4528 }
4529
4530 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004531 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004532 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004533 goto exit;
4534 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004535 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004536 /* Multiple-BSS should use same 11d configuration */
4537 err = -EINVAL;
4538 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004539 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004540
4541 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004542 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004543 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4544 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4545
Hante Meulemana0f07952013-02-08 15:53:47 +01004546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4547 if (err < 0) {
4548 brcmf_err("setting AP mode failed %d\n", err);
4549 goto exit;
4550 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004551 if (!mbss) {
4552 /* Firmware 10.x requires setting channel after enabling
4553 * AP and before bringing interface up.
4554 */
4555 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4556 if (err < 0) {
4557 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4558 chanspec, err);
4559 goto exit;
4560 }
4561 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004562 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4563 if (err < 0) {
4564 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4565 goto exit;
4566 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004567 /* On DOWN the firmware removes the WEP keys, reconfigure
4568 * them if they were set.
4569 */
4570 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004571
4572 memset(&join_params, 0, sizeof(join_params));
4573 /* join parameters starts with ssid */
4574 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4575 /* create softap */
4576 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4577 &join_params, sizeof(join_params));
4578 if (err < 0) {
4579 brcmf_err("SET SSID error (%d)\n", err);
4580 goto exit;
4581 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004582
4583 if (settings->hidden_ssid) {
4584 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4585 if (err) {
4586 brcmf_err("closednet error (%d)\n", err);
4587 goto exit;
4588 }
4589 }
4590
Hante Meulemana0f07952013-02-08 15:53:47 +01004591 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004592 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4593 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4594 if (err < 0) {
4595 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4596 chanspec, err);
4597 goto exit;
4598 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004599 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4600 sizeof(ssid_le));
4601 if (err < 0) {
4602 brcmf_err("setting ssid failed %d\n", err);
4603 goto exit;
4604 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004605 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004606 bss_enable.enable = cpu_to_le32(1);
4607 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4608 sizeof(bss_enable));
4609 if (err < 0) {
4610 brcmf_err("bss_enable config failed %d\n", err);
4611 goto exit;
4612 }
4613
4614 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004615 } else {
4616 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004617 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004618
Wright Fengf25ba692016-11-18 09:59:52 +08004619 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004620 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004621 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004622
4623exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004624 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004625 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004626 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004627 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004628 return err;
4629}
4630
4631static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4632{
Arend van Sprielc1179032012-10-22 13:55:33 -07004633 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004634 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004635 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004636 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004637
Arend van Sprield96b8012012-12-05 15:26:02 +01004638 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004639
Hante Meuleman426d0a52013-02-08 15:53:53 +01004640 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004641 /* Due to most likely deauths outstanding we sleep */
4642 /* first to make sure they get processed by fw. */
4643 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004644
Hante Meulemana44aa402014-12-03 21:05:33 +01004645 if (ifp->vif->mbss) {
4646 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4647 return err;
4648 }
4649
Rafał Miłeckic940de12016-07-06 12:22:54 +02004650 /* First BSS doesn't get a full reset */
4651 if (ifp->bsscfgidx == 0)
4652 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4653
Hante Meuleman5c33a942013-04-02 21:06:18 +02004654 memset(&join_params, 0, sizeof(join_params));
4655 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4656 &join_params, sizeof(join_params));
4657 if (err < 0)
4658 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004659 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004660 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004661 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004662 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4663 if (err < 0)
4664 brcmf_err("setting AP mode failed %d\n", err);
4665 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4666 if (err < 0)
4667 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004668 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4669 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004670 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4671 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004672 /* Bring device back up so it can be used again */
4673 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4674 if (err < 0)
4675 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004676
4677 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004678 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004679 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004680 bss_enable.enable = cpu_to_le32(0);
4681 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4682 sizeof(bss_enable));
4683 if (err < 0)
4684 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004685 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004686 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004687 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004688 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004689 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004690
Hante Meuleman1a873342012-09-27 14:17:54 +02004691 return err;
4692}
4693
Hante Meulemana0f07952013-02-08 15:53:47 +01004694static s32
4695brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4696 struct cfg80211_beacon_data *info)
4697{
Hante Meulemana0f07952013-02-08 15:53:47 +01004698 struct brcmf_if *ifp = netdev_priv(ndev);
4699 s32 err;
4700
4701 brcmf_dbg(TRACE, "Enter\n");
4702
Hante Meulemana0f07952013-02-08 15:53:47 +01004703 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4704
4705 return err;
4706}
4707
Hante Meuleman1a873342012-09-27 14:17:54 +02004708static int
4709brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004710 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004711{
Hante Meulemana0f07952013-02-08 15:53:47 +01004712 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004713 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004714 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004715 s32 err;
4716
Jouni Malinen89c771e2014-10-10 20:52:40 +03004717 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004718 return -EFAULT;
4719
Jouni Malinen89c771e2014-10-10 20:52:40 +03004720 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004721
Hante Meulemana0f07952013-02-08 15:53:47 +01004722 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4723 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004724 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004725 return -EIO;
4726
Jouni Malinen89c771e2014-10-10 20:52:40 +03004727 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004728 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004729 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004730 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004731 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004732 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004733
Arend van Sprield96b8012012-12-05 15:26:02 +01004734 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004735 return err;
4736}
4737
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004738static int
4739brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4740 const u8 *mac, struct station_parameters *params)
4741{
4742 struct brcmf_if *ifp = netdev_priv(ndev);
4743 s32 err;
4744
4745 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4746 params->sta_flags_mask, params->sta_flags_set);
4747
4748 /* Ignore all 00 MAC */
4749 if (is_zero_ether_addr(mac))
4750 return 0;
4751
4752 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4753 return 0;
4754
4755 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4756 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4757 (void *)mac, ETH_ALEN);
4758 else
4759 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4760 (void *)mac, ETH_ALEN);
4761 if (err < 0)
4762 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4763
4764 return err;
4765}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004766
4767static void
4768brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4769 struct wireless_dev *wdev,
4770 u16 frame_type, bool reg)
4771{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004772 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004773 u16 mgmt_type;
4774
4775 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4776
4777 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004778 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004779 if (reg)
4780 vif->mgmt_rx_reg |= BIT(mgmt_type);
4781 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004782 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004783}
4784
4785
4786static int
4787brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004788 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004789{
4790 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004791 struct ieee80211_channel *chan = params->chan;
4792 const u8 *buf = params->buf;
4793 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004794 const struct ieee80211_mgmt *mgmt;
4795 struct brcmf_cfg80211_vif *vif;
4796 s32 err = 0;
4797 s32 ie_offset;
4798 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004799 struct brcmf_fil_action_frame_le *action_frame;
4800 struct brcmf_fil_af_params_le *af_params;
4801 bool ack;
4802 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004803 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004804
4805 brcmf_dbg(TRACE, "Enter\n");
4806
4807 *cookie = 0;
4808
4809 mgmt = (const struct ieee80211_mgmt *)buf;
4810
Hante Meulemana0f07952013-02-08 15:53:47 +01004811 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4812 brcmf_err("Driver only allows MGMT packet type\n");
4813 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004814 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004815
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004816 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4817
Hante Meulemana0f07952013-02-08 15:53:47 +01004818 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4819 /* Right now the only reason to get a probe response */
4820 /* is for p2p listen response or for p2p GO from */
4821 /* wpa_supplicant. Unfortunately the probe is send */
4822 /* on primary ndev, while dongle wants it on the p2p */
4823 /* vif. Since this is only reason for a probe */
4824 /* response to be sent, the vif is taken from cfg. */
4825 /* If ever desired to send proberesp for non p2p */
4826 /* response then data should be checked for */
4827 /* "DIRECT-". Note in future supplicant will take */
4828 /* dedicated p2p wdev to do this and then this 'hack'*/
4829 /* is not needed anymore. */
4830 ie_offset = DOT11_MGMT_HDR_LEN +
4831 DOT11_BCN_PRB_FIXED_LEN;
4832 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004833 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4834 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4835 err = brcmf_vif_set_mgmt_ie(vif,
4836 BRCMF_VNDR_IE_PRBRSP_FLAG,
4837 &buf[ie_offset],
4838 ie_len);
4839 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4840 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004841 } else if (ieee80211_is_action(mgmt->frame_control)) {
4842 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4843 if (af_params == NULL) {
4844 brcmf_err("unable to allocate frame\n");
4845 err = -ENOMEM;
4846 goto exit;
4847 }
4848 action_frame = &af_params->action_frame;
4849 /* Add the packet Id */
4850 action_frame->packet_id = cpu_to_le32(*cookie);
4851 /* Add BSSID */
4852 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4853 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4854 /* Add the length exepted for 802.11 header */
4855 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004856 /* Add the channel. Use the one specified as parameter if any or
4857 * the current one (got from the firmware) otherwise
4858 */
4859 if (chan)
4860 freq = chan->center_freq;
4861 else
4862 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4863 &freq);
4864 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004865 af_params->channel = cpu_to_le32(chan_nr);
4866
4867 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4868 le16_to_cpu(action_frame->len));
4869
4870 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004871 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004872
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004873 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004874 af_params);
4875
4876 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4877 GFP_KERNEL);
4878 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004879 } else {
4880 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4881 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4882 }
4883
Hante Meuleman18e2f612013-02-08 15:53:49 +01004884exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004885 return err;
4886}
4887
4888
4889static int
4890brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4891 struct wireless_dev *wdev,
4892 u64 cookie)
4893{
4894 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4895 struct brcmf_cfg80211_vif *vif;
4896 int err = 0;
4897
4898 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4899
4900 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4901 if (vif == NULL) {
4902 brcmf_err("No p2p device available for probe response\n");
4903 err = -ENODEV;
4904 goto exit;
4905 }
4906 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4907exit:
4908 return err;
4909}
4910
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004911static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4912 struct wireless_dev *wdev,
4913 struct cfg80211_chan_def *chandef)
4914{
4915 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4916 struct net_device *ndev = wdev->netdev;
4917 struct brcmf_if *ifp;
4918 struct brcmu_chan ch;
4919 enum nl80211_band band = 0;
4920 enum nl80211_chan_width width = 0;
4921 u32 chanspec;
4922 int freq, err;
4923
4924 if (!ndev)
4925 return -ENODEV;
4926 ifp = netdev_priv(ndev);
4927
4928 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4929 if (err) {
4930 brcmf_err("chanspec failed (%d)\n", err);
4931 return err;
4932 }
4933
4934 ch.chspec = chanspec;
4935 cfg->d11inf.decchspec(&ch);
4936
4937 switch (ch.band) {
4938 case BRCMU_CHAN_BAND_2G:
4939 band = NL80211_BAND_2GHZ;
4940 break;
4941 case BRCMU_CHAN_BAND_5G:
4942 band = NL80211_BAND_5GHZ;
4943 break;
4944 }
4945
4946 switch (ch.bw) {
4947 case BRCMU_CHAN_BW_80:
4948 width = NL80211_CHAN_WIDTH_80;
4949 break;
4950 case BRCMU_CHAN_BW_40:
4951 width = NL80211_CHAN_WIDTH_40;
4952 break;
4953 case BRCMU_CHAN_BW_20:
4954 width = NL80211_CHAN_WIDTH_20;
4955 break;
4956 case BRCMU_CHAN_BW_80P80:
4957 width = NL80211_CHAN_WIDTH_80P80;
4958 break;
4959 case BRCMU_CHAN_BW_160:
4960 width = NL80211_CHAN_WIDTH_160;
4961 break;
4962 }
4963
4964 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
4965 chandef->chan = ieee80211_get_channel(wiphy, freq);
4966 chandef->width = width;
4967 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
4968 chandef->center_freq2 = 0;
4969
4970 return 0;
4971}
4972
Piotr Haber61730d42013-04-23 12:53:12 +02004973static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4974 struct wireless_dev *wdev,
4975 enum nl80211_crit_proto_id proto,
4976 u16 duration)
4977{
4978 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4979 struct brcmf_cfg80211_vif *vif;
4980
4981 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4982
4983 /* only DHCP support for now */
4984 if (proto != NL80211_CRIT_PROTO_DHCP)
4985 return -EINVAL;
4986
4987 /* suppress and abort scanning */
4988 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4989 brcmf_abort_scanning(cfg);
4990
4991 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4992}
4993
4994static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4995 struct wireless_dev *wdev)
4996{
4997 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4998 struct brcmf_cfg80211_vif *vif;
4999
5000 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5001
5002 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5003 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5004}
5005
Hante Meuleman70b7d942014-07-30 13:20:07 +02005006static s32
5007brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5008 const struct brcmf_event_msg *e, void *data)
5009{
5010 switch (e->reason) {
5011 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5012 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5013 break;
5014 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5015 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5016 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5017 break;
5018 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5019 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5020 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5021 break;
5022 }
5023
5024 return 0;
5025}
5026
Arend van Spriel89c2f382013-08-10 12:27:25 +02005027static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5028{
5029 int ret;
5030
5031 switch (oper) {
5032 case NL80211_TDLS_DISCOVERY_REQ:
5033 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5034 break;
5035 case NL80211_TDLS_SETUP:
5036 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5037 break;
5038 case NL80211_TDLS_TEARDOWN:
5039 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5040 break;
5041 default:
5042 brcmf_err("unsupported operation: %d\n", oper);
5043 ret = -EOPNOTSUPP;
5044 }
5045 return ret;
5046}
5047
5048static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005049 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005050 enum nl80211_tdls_operation oper)
5051{
5052 struct brcmf_if *ifp;
5053 struct brcmf_tdls_iovar_le info;
5054 int ret = 0;
5055
5056 ret = brcmf_convert_nl80211_tdls_oper(oper);
5057 if (ret < 0)
5058 return ret;
5059
5060 ifp = netdev_priv(ndev);
5061 memset(&info, 0, sizeof(info));
5062 info.mode = (u8)ret;
5063 if (peer)
5064 memcpy(info.ea, peer, ETH_ALEN);
5065
5066 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5067 &info, sizeof(info));
5068 if (ret < 0)
5069 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5070
5071 return ret;
5072}
5073
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005074#ifdef CONFIG_PM
5075static int
5076brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5077 struct cfg80211_gtk_rekey_data *gtk)
5078{
5079 struct brcmf_if *ifp = netdev_priv(ndev);
5080 struct brcmf_gtk_keyinfo_le gtk_le;
5081 int ret;
5082
5083 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5084
5085 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5086 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5087 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5088 sizeof(gtk_le.replay_counter));
5089
5090 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5091 sizeof(gtk_le));
5092 if (ret < 0)
5093 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5094
5095 return ret;
5096}
5097#endif
5098
5099static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005100 .add_virtual_intf = brcmf_cfg80211_add_iface,
5101 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005102 .change_virtual_intf = brcmf_cfg80211_change_iface,
5103 .scan = brcmf_cfg80211_scan,
5104 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5105 .join_ibss = brcmf_cfg80211_join_ibss,
5106 .leave_ibss = brcmf_cfg80211_leave_ibss,
5107 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005108 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005109 .set_tx_power = brcmf_cfg80211_set_tx_power,
5110 .get_tx_power = brcmf_cfg80211_get_tx_power,
5111 .add_key = brcmf_cfg80211_add_key,
5112 .del_key = brcmf_cfg80211_del_key,
5113 .get_key = brcmf_cfg80211_get_key,
5114 .set_default_key = brcmf_cfg80211_config_default_key,
5115 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5116 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005117 .connect = brcmf_cfg80211_connect,
5118 .disconnect = brcmf_cfg80211_disconnect,
5119 .suspend = brcmf_cfg80211_suspend,
5120 .resume = brcmf_cfg80211_resume,
5121 .set_pmksa = brcmf_cfg80211_set_pmksa,
5122 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005123 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005124 .start_ap = brcmf_cfg80211_start_ap,
5125 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005126 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005127 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005128 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005129 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5130 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005131 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5132 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5133 .remain_on_channel = brcmf_p2p_remain_on_channel,
5134 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005135 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005136 .start_p2p_device = brcmf_p2p_start_device,
5137 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005138 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5139 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005140 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005141};
5142
Arend van Spriel3eacf862012-10-22 13:55:30 -07005143struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005144 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005145{
Hante Meulemana44aa402014-12-03 21:05:33 +01005146 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005147 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005148 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005149
Arend van Spriel33a6b152013-02-08 15:53:39 +01005150 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005151 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005152 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5153 if (!vif)
5154 return ERR_PTR(-ENOMEM);
5155
5156 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005157 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005158
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005159 brcmf_init_prof(&vif->profile);
5160
Hante Meulemana44aa402014-12-03 21:05:33 +01005161 if (type == NL80211_IFTYPE_AP) {
5162 mbss = false;
5163 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5164 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5165 mbss = true;
5166 break;
5167 }
5168 }
5169 vif->mbss = mbss;
5170 }
5171
Arend van Spriel3eacf862012-10-22 13:55:30 -07005172 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005173 return vif;
5174}
5175
Arend van Spriel427dec52014-01-06 12:40:47 +01005176void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005177{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005178 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005179 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005180}
5181
Arend van Spriel9df4d542014-01-06 12:40:49 +01005182void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5183{
5184 struct brcmf_cfg80211_vif *vif;
5185 struct brcmf_if *ifp;
5186
5187 ifp = netdev_priv(ndev);
5188 vif = ifp->vif;
5189
Arend van Spriel95ef1232015-08-26 22:15:04 +02005190 if (vif)
5191 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005192 free_netdev(ndev);
5193}
5194
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005195static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005196{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005197 u32 event = e->event_code;
5198 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005199
5200 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005201 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005202 return true;
5203 }
5204
5205 return false;
5206}
5207
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005208static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005209{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005210 u32 event = e->event_code;
5211 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005212
Hante Meuleman68ca3952014-02-25 20:30:26 +01005213 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5214 (event == BRCMF_E_DISASSOC_IND) ||
5215 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005216 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005217 return true;
5218 }
5219 return false;
5220}
5221
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005222static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005223 const struct brcmf_event_msg *e)
5224{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005225 u32 event = e->event_code;
5226 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005227
5228 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005229 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5230 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005231 return true;
5232 }
5233
5234 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005235 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005236 return true;
5237 }
5238
5239 return false;
5240}
5241
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005242static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005243{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005244 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005245
5246 kfree(conn_info->req_ie);
5247 conn_info->req_ie = NULL;
5248 conn_info->req_ie_len = 0;
5249 kfree(conn_info->resp_ie);
5250 conn_info->resp_ie = NULL;
5251 conn_info->resp_ie_len = 0;
5252}
5253
Hante Meuleman89286dc2013-02-08 15:53:46 +01005254static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5255 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005256{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005257 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005258 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005259 u32 req_len;
5260 u32 resp_len;
5261 s32 err = 0;
5262
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005263 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005264
Arend van Sprielac24be62012-10-22 10:36:23 -07005265 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5266 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005267 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005268 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005269 return err;
5270 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005271 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005272 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005273 req_len = le32_to_cpu(assoc_info->req_len);
5274 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005275 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005276 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005277 cfg->extra_buf,
5278 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005279 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005280 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005281 return err;
5282 }
5283 conn_info->req_ie_len = req_len;
5284 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005285 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005286 GFP_KERNEL);
5287 } else {
5288 conn_info->req_ie_len = 0;
5289 conn_info->req_ie = NULL;
5290 }
5291 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005292 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005293 cfg->extra_buf,
5294 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005295 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005296 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005297 return err;
5298 }
5299 conn_info->resp_ie_len = resp_len;
5300 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005301 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005302 GFP_KERNEL);
5303 } else {
5304 conn_info->resp_ie_len = 0;
5305 conn_info->resp_ie = NULL;
5306 }
Arend van Spriel16886732012-12-05 15:26:04 +01005307 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5308 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005309
5310 return err;
5311}
5312
5313static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005314brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005315 struct net_device *ndev,
5316 const struct brcmf_event_msg *e)
5317{
Arend van Sprielc1179032012-10-22 13:55:33 -07005318 struct brcmf_if *ifp = netdev_priv(ndev);
5319 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005320 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5321 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005322 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005323 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005324 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005325 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005326 u32 freq;
5327 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005328 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005329
Arend van Sprield96b8012012-12-05 15:26:02 +01005330 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005331
Hante Meuleman89286dc2013-02-08 15:53:46 +01005332 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005333 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005334 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005335
Franky Lina180b832012-10-10 11:13:09 -07005336 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5337 if (buf == NULL) {
5338 err = -ENOMEM;
5339 goto done;
5340 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005341
Franky Lina180b832012-10-10 11:13:09 -07005342 /* data sent to dongle has to be little endian */
5343 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005344 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005345 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005346
5347 if (err)
5348 goto done;
5349
5350 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005351 ch.chspec = le16_to_cpu(bi->chanspec);
5352 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005353
Franky Lin83cf17a2013-04-11 13:28:50 +02005354 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005355 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005356 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005357 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005358
Rafał Miłecki4712d882016-05-20 13:38:57 +02005359 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005360 notify_channel = ieee80211_get_channel(wiphy, freq);
5361
Franky Lina180b832012-10-10 11:13:09 -07005362done:
5363 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005364 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005365 conn_info->req_ie, conn_info->req_ie_len,
5366 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005367 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368
Arend van Sprielc1179032012-10-22 13:55:33 -07005369 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005370 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005371 return err;
5372}
5373
5374static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005375brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005376 struct net_device *ndev, const struct brcmf_event_msg *e,
5377 bool completed)
5378{
Arend van Sprielc1179032012-10-22 13:55:33 -07005379 struct brcmf_if *ifp = netdev_priv(ndev);
5380 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005381 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005382
Arend van Sprield96b8012012-12-05 15:26:02 +01005383 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005384
Arend van Sprielc1179032012-10-22 13:55:33 -07005385 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5386 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005387 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005388 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005389 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005390 brcmf_update_bss_info(cfg, ifp);
5391 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5392 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005393 }
5394 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005395 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005396 conn_info->req_ie,
5397 conn_info->req_ie_len,
5398 conn_info->resp_ie,
5399 conn_info->resp_ie_len,
5400 completed ? WLAN_STATUS_SUCCESS :
5401 WLAN_STATUS_AUTH_TIMEOUT,
5402 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005403 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5404 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005405 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005406 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005407 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005408}
5409
5410static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005411brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005412 struct net_device *ndev,
5413 const struct brcmf_event_msg *e, void *data)
5414{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005415 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005416 u32 event = e->event_code;
5417 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005418 struct station_info sinfo;
5419
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005420 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5421 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005422 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5423 ndev != cfg_to_ndev(cfg)) {
5424 brcmf_dbg(CONN, "AP mode link down\n");
5425 complete(&cfg->vif_disabled);
5426 return 0;
5427 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005428
Hante Meuleman1a873342012-09-27 14:17:54 +02005429 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005430 (reason == BRCMF_E_STATUS_SUCCESS)) {
5431 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005432 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005433 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005434 return -EINVAL;
5435 }
5436 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005437 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005438 generation++;
5439 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005440 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005441 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5442 (event == BRCMF_E_DEAUTH_IND) ||
5443 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005444 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005445 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005446 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005447}
5448
5449static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005450brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451 const struct brcmf_event_msg *e, void *data)
5452{
Arend van Spriel19937322012-11-05 16:22:32 -08005453 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5454 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005455 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005456 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005457 s32 err = 0;
5458
Hante Meuleman8851cce2014-07-30 13:20:02 +02005459 if ((e->event_code == BRCMF_E_DEAUTH) ||
5460 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5461 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5462 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5463 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5464 }
5465
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005466 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005467 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005468 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005469 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005470 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005471 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005472 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005473 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005474 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005475 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5476 &ifp->vif->sme_state);
5477 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5478 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005479 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005480 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005481 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005482 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005483 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005484 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005485 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005486 brcmf_link_down(ifp->vif,
5487 brcmf_map_fw_linkdown_reason(e));
5488 brcmf_init_prof(ndev_to_prof(ndev));
5489 if (ndev != cfg_to_ndev(cfg))
5490 complete(&cfg->vif_disabled);
5491 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005492 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005493 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005494 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005495 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5496 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005497 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005498 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005499 }
5500
5501 return err;
5502}
5503
5504static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005505brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005506 const struct brcmf_event_msg *e, void *data)
5507{
Arend van Spriel19937322012-11-05 16:22:32 -08005508 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005509 u32 event = e->event_code;
5510 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005511
5512 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005513 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005514 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005515 else
Arend van Spriel19937322012-11-05 16:22:32 -08005516 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005517 }
5518
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005519 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005520}
5521
5522static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005523brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005524 const struct brcmf_event_msg *e, void *data)
5525{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005526 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005527 enum nl80211_key_type key_type;
5528
5529 if (flags & BRCMF_EVENT_MSG_GROUP)
5530 key_type = NL80211_KEYTYPE_GROUP;
5531 else
5532 key_type = NL80211_KEYTYPE_PAIRWISE;
5533
Arend van Spriel19937322012-11-05 16:22:32 -08005534 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005535 NULL, GFP_KERNEL);
5536
5537 return 0;
5538}
5539
Arend van Sprield3c0b632013-02-08 15:53:37 +01005540static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5541 const struct brcmf_event_msg *e, void *data)
5542{
5543 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5544 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5545 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5546 struct brcmf_cfg80211_vif *vif;
5547
Hante Meuleman37a869e2015-10-29 20:33:17 +01005548 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005549 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005550 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005551
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005552 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005553 event->action = ifevent->action;
5554 vif = event->vif;
5555
5556 switch (ifevent->action) {
5557 case BRCMF_E_IF_ADD:
5558 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005559 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005560 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005561 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005562 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005563
5564 ifp->vif = vif;
5565 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005566 if (ifp->ndev) {
5567 vif->wdev.netdev = ifp->ndev;
5568 ifp->ndev->ieee80211_ptr = &vif->wdev;
5569 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5570 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005571 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005572 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005573 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005574
5575 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005576 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005577 /* event may not be upon user request */
5578 if (brcmf_cfg80211_vif_event_armed(cfg))
5579 wake_up(&event->vif_wq);
5580 return 0;
5581
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005582 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005583 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005584 wake_up(&event->vif_wq);
5585 return 0;
5586
Arend van Sprield3c0b632013-02-08 15:53:37 +01005587 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005588 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005589 break;
5590 }
5591 return -EINVAL;
5592}
5593
Arend van Spriel5b435de2011-10-05 13:19:03 +02005594static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5595{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005596 conf->frag_threshold = (u32)-1;
5597 conf->rts_threshold = (u32)-1;
5598 conf->retry_short = (u32)-1;
5599 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005600}
5601
Arend van Spriel5c36b992012-11-14 18:46:05 -08005602static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005603{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005604 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5605 brcmf_notify_connect_status);
5606 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5607 brcmf_notify_connect_status);
5608 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5609 brcmf_notify_connect_status);
5610 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5611 brcmf_notify_connect_status);
5612 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5613 brcmf_notify_connect_status);
5614 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5615 brcmf_notify_connect_status);
5616 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5617 brcmf_notify_roaming_status);
5618 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5619 brcmf_notify_mic_status);
5620 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5621 brcmf_notify_connect_status);
5622 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5623 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005624 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5625 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005626 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005627 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005628 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5629 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005630 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5631 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005632 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5633 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005634 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5635 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005636}
5637
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005638static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005639{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005640 kfree(cfg->conf);
5641 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005642 kfree(cfg->extra_buf);
5643 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005644 kfree(cfg->wowl.nd);
5645 cfg->wowl.nd = NULL;
5646 kfree(cfg->wowl.nd_info);
5647 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005648 kfree(cfg->escan_info.escan_buf);
5649 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005650}
5651
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005652static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005653{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005654 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5655 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005656 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005657 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5658 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005659 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005660 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5661 if (!cfg->wowl.nd)
5662 goto init_priv_mem_out;
5663 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5664 sizeof(struct cfg80211_wowlan_nd_match *),
5665 GFP_KERNEL);
5666 if (!cfg->wowl.nd_info)
5667 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005668 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5669 if (!cfg->escan_info.escan_buf)
5670 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005671
5672 return 0;
5673
5674init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005675 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005676
5677 return -ENOMEM;
5678}
5679
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005680static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005681{
5682 s32 err = 0;
5683
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005684 cfg->scan_request = NULL;
5685 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005686 cfg->active_scan = true; /* we do active scan per default */
5687 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005688 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005689 if (err)
5690 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005691 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005692 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005693 brcmf_init_escan(cfg);
5694 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005695 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005696 return err;
5697}
5698
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005699static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005700{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005701 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005702 brcmf_abort_scanning(cfg);
5703 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005704}
5705
Arend van Sprield3c0b632013-02-08 15:53:37 +01005706static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5707{
5708 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005709 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005710}
5711
Hante Meuleman1119e232015-11-25 11:32:42 +01005712static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005713{
Hante Meuleman1119e232015-11-25 11:32:42 +01005714 s32 err;
5715 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005716 __le32 roamtrigger[2];
5717 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005718
Hante Meuleman1119e232015-11-25 11:32:42 +01005719 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005720 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005721 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5722 else
5723 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5724 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5725 if (err) {
5726 brcmf_err("bcn_timeout error (%d)\n", err);
5727 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005728 }
5729
Hante Meuleman1119e232015-11-25 11:32:42 +01005730 /* Enable/Disable built-in roaming to allow supplicant to take care of
5731 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005732 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005733 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005734 ifp->drvr->settings->roamoff ? "Off" : "On");
5735 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5736 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005737 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005738 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005739 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005740 }
5741
Arend van Sprielf588bc02011-10-12 20:51:22 +02005742 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5743 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005744 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005745 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005746 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005747 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005748 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005749 }
5750
Arend van Sprielf588bc02011-10-12 20:51:22 +02005751 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5752 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005753 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005754 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005755 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005756 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005757 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005758 }
5759
Hante Meuleman1119e232015-11-25 11:32:42 +01005760roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005761 return err;
5762}
5763
5764static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005765brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005766{
5767 s32 err = 0;
5768
Arend van Sprielac24be62012-10-22 10:36:23 -07005769 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005770 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005771 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005772 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005773 goto dongle_scantime_out;
5774 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005775 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005776 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005777 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005778 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005779 goto dongle_scantime_out;
5780 }
5781
Arend van Sprielac24be62012-10-22 10:36:23 -07005782 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005783 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005784 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005785 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005786 goto dongle_scantime_out;
5787 }
5788
5789dongle_scantime_out:
5790 return err;
5791}
5792
Arend van Sprielb48d8912014-07-12 08:49:41 +02005793static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5794 struct brcmu_chan *ch)
5795{
5796 u32 ht40_flag;
5797
5798 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5799 if (ch->sb == BRCMU_CHAN_SB_U) {
5800 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5801 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5802 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5803 } else {
5804 /* It should be one of
5805 * IEEE80211_CHAN_NO_HT40 or
5806 * IEEE80211_CHAN_NO_HT40PLUS
5807 */
5808 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5809 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5810 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5811 }
5812}
5813
5814static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5815 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005816{
5817 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005818 struct ieee80211_supported_band *band;
5819 struct ieee80211_channel *channel;
5820 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005821 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005822 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005823 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005824 u8 *pbuf;
5825 u32 i, j;
5826 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005827 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005828 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005829
5830 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5831
5832 if (pbuf == NULL)
5833 return -ENOMEM;
5834
5835 list = (struct brcmf_chanspec_list *)pbuf;
5836
5837 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5838 BRCMF_DCMD_MEDLEN);
5839 if (err) {
5840 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005841 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005842 }
5843
Arend van Sprielb48d8912014-07-12 08:49:41 +02005844 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005845 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005846 if (band)
5847 for (i = 0; i < band->n_channels; i++)
5848 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005849 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005850 if (band)
5851 for (i = 0; i < band->n_channels; i++)
5852 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005853
5854 total = le32_to_cpu(list->count);
5855 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005856 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5857 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005858
Franky Lin83cf17a2013-04-11 13:28:50 +02005859 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005860 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005861 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005862 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005863 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005864 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005865 continue;
5866 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005867 if (!band)
5868 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005869 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005870 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005871 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005872 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005873 ch.bw == BRCMU_CHAN_BW_80)
5874 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005875
5876 channel = band->channels;
5877 index = band->n_channels;
5878 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02005879 if (channel[j].hw_value == ch.control_ch_num) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005880 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005881 break;
5882 }
5883 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005884 channel[index].center_freq =
Rafał Miłecki4712d882016-05-20 13:38:57 +02005885 ieee80211_channel_to_frequency(ch.control_ch_num,
5886 band->band);
5887 channel[index].hw_value = ch.control_ch_num;
Hante Meulemand48200b2013-04-03 12:40:29 +02005888
Arend van Sprielb48d8912014-07-12 08:49:41 +02005889 /* assuming the chanspecs order is HT20,
5890 * HT40 upper, HT40 lower, and VHT80.
5891 */
5892 if (ch.bw == BRCMU_CHAN_BW_80) {
5893 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5894 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5895 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5896 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005897 /* enable the channel and disable other bandwidths
5898 * for now as mentioned order assure they are enabled
5899 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005900 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005901 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5902 IEEE80211_CHAN_NO_80MHZ;
5903 ch.bw = BRCMU_CHAN_BW_20;
5904 cfg->d11inf.encchspec(&ch);
5905 chaninfo = ch.chspec;
5906 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5907 &chaninfo);
5908 if (!err) {
5909 if (chaninfo & WL_CHAN_RADAR)
5910 channel[index].flags |=
5911 (IEEE80211_CHAN_RADAR |
5912 IEEE80211_CHAN_NO_IR);
5913 if (chaninfo & WL_CHAN_PASSIVE)
5914 channel[index].flags |=
5915 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005916 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005917 }
5918 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005919
Arend van Sprielb48d8912014-07-12 08:49:41 +02005920fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005921 kfree(pbuf);
5922 return err;
5923}
5924
Arend van Sprielb48d8912014-07-12 08:49:41 +02005925static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005926{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005927 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5928 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005929 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005930 struct brcmf_chanspec_list *list;
5931 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005932 u32 val;
5933 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005934 struct brcmu_chan ch;
5935 u32 num_chan;
5936 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005937
5938 /* verify support for bw_cap command */
5939 val = WLC_BAND_5G;
5940 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5941
5942 if (!err) {
5943 /* only set 2G bandwidth using bw_cap command */
5944 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5945 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5946 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5947 sizeof(band_bwcap));
5948 } else {
5949 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5950 val = WLC_N_BW_40ALL;
5951 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5952 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005953
5954 if (!err) {
5955 /* update channel info in 2G band */
5956 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5957
5958 if (pbuf == NULL)
5959 return -ENOMEM;
5960
5961 ch.band = BRCMU_CHAN_BAND_2G;
5962 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005963 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005964 ch.chnum = 0;
5965 cfg->d11inf.encchspec(&ch);
5966
5967 /* pass encoded chanspec in query */
5968 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5969
5970 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5971 BRCMF_DCMD_MEDLEN);
5972 if (err) {
5973 brcmf_err("get chanspecs error (%d)\n", err);
5974 kfree(pbuf);
5975 return err;
5976 }
5977
Johannes Berg57fbcce2016-04-12 15:56:15 +02005978 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02005979 list = (struct brcmf_chanspec_list *)pbuf;
5980 num_chan = le32_to_cpu(list->count);
5981 for (i = 0; i < num_chan; i++) {
5982 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5983 cfg->d11inf.decchspec(&ch);
5984 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5985 continue;
5986 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5987 continue;
5988 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02005989 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02005990 break;
5991 }
5992 if (WARN_ON(j == band->n_channels))
5993 continue;
5994
5995 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5996 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005997 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005998 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005999 return err;
6000}
6001
Arend van Spriel2375d972014-01-06 12:40:41 +01006002static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6003{
6004 u32 band, mimo_bwcap;
6005 int err;
6006
6007 band = WLC_BAND_2G;
6008 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6009 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006010 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006011 band = WLC_BAND_5G;
6012 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6013 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006014 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006015 return;
6016 }
6017 WARN_ON(1);
6018 return;
6019 }
6020 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6021 mimo_bwcap = 0;
6022 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6023 if (err)
6024 /* assume 20MHz if firmware does not give a clue */
6025 mimo_bwcap = WLC_N_BW_20ALL;
6026
6027 switch (mimo_bwcap) {
6028 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006029 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006030 /* fall-thru */
6031 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006032 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006033 /* fall-thru */
6034 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006035 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6036 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006037 break;
6038 default:
6039 brcmf_err("invalid mimo_bw_cap value\n");
6040 }
6041}
Hante Meulemand48200b2013-04-03 12:40:29 +02006042
Arend van Spriel18d6c532014-05-12 10:47:35 +02006043static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6044 u32 bw_cap[2], u32 nchain)
6045{
6046 band->ht_cap.ht_supported = true;
6047 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6048 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6049 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6050 }
6051 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6052 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6053 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6054 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6055 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6056 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6057}
6058
6059static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6060{
6061 u16 mcs_map;
6062 int i;
6063
6064 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6065 mcs_map = (mcs_map << 2) | supp;
6066
6067 return cpu_to_le16(mcs_map);
6068}
6069
6070static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006071 u32 bw_cap[2], u32 nchain, u32 txstreams,
6072 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006073{
6074 __le16 mcs_map;
6075
6076 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006077 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006078 return;
6079
6080 band->vht_cap.vht_supported = true;
6081 /* 80MHz is mandatory */
6082 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6083 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6084 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6085 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6086 }
6087 /* all support 256-QAM */
6088 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6089 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6090 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006091
6092 /* Beamforming support information */
6093 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6094 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6095 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6096 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6097 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6098 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6099 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6100 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6101
6102 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6103 band->vht_cap.cap |=
6104 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6105 band->vht_cap.cap |= ((txstreams - 1) <<
6106 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6107 band->vht_cap.cap |=
6108 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6109 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006110}
6111
Arend van Sprielb48d8912014-07-12 08:49:41 +02006112static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006113{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006114 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006115 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006116 u32 nmode = 0;
6117 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006118 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006119 u32 rxchain;
6120 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006121 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006122 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006123 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006124 u32 txstreams = 0;
6125 u32 txbf_bfe_cap = 0;
6126 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006127
Arend van Spriel18d6c532014-05-12 10:47:35 +02006128 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006129 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6130 if (err) {
6131 brcmf_err("nmode error (%d)\n", err);
6132 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006133 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006134 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006135 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006136 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6137 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006138
Daniel Kim4aca7a12014-02-25 20:30:36 +01006139 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6140 if (err) {
6141 brcmf_err("rxchain error (%d)\n", err);
6142 nchain = 1;
6143 } else {
6144 for (nchain = 0; rxchain; nchain++)
6145 rxchain = rxchain & (rxchain - 1);
6146 }
6147 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6148
Arend van Sprielb48d8912014-07-12 08:49:41 +02006149 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006150 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006151 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006152 return err;
6153 }
6154
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006155 if (vhtmode) {
6156 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6157 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6158 &txbf_bfe_cap);
6159 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6160 &txbf_bfr_cap);
6161 }
6162
Arend van Sprielb48d8912014-07-12 08:49:41 +02006163 wiphy = cfg_to_wiphy(cfg);
6164 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6165 band = wiphy->bands[i];
6166 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006167 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006168
Arend van Spriel18d6c532014-05-12 10:47:35 +02006169 if (nmode)
6170 brcmf_update_ht_cap(band, bw_cap, nchain);
6171 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006172 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6173 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006174 }
6175
Arend van Sprielb48d8912014-07-12 08:49:41 +02006176 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006177}
6178
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006179static const struct ieee80211_txrx_stypes
6180brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6181 [NL80211_IFTYPE_STATION] = {
6182 .tx = 0xffff,
6183 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6184 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6185 },
6186 [NL80211_IFTYPE_P2P_CLIENT] = {
6187 .tx = 0xffff,
6188 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6189 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6190 },
6191 [NL80211_IFTYPE_P2P_GO] = {
6192 .tx = 0xffff,
6193 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6194 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6195 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6196 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6197 BIT(IEEE80211_STYPE_AUTH >> 4) |
6198 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6199 BIT(IEEE80211_STYPE_ACTION >> 4)
6200 },
6201 [NL80211_IFTYPE_P2P_DEVICE] = {
6202 .tx = 0xffff,
6203 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6204 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6205 }
6206};
6207
Arend van Spriel0882dda2015-08-20 22:06:03 +02006208/**
6209 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6210 *
6211 * @wiphy: wiphy object.
6212 * @ifp: interface object needed for feat module api.
6213 *
6214 * The interface modes and combinations are determined dynamically here
6215 * based on firmware functionality.
6216 *
6217 * no p2p and no mbss:
6218 *
6219 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6220 *
6221 * no p2p and mbss:
6222 *
6223 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6224 * #AP <= 4, matching BI, channels = 1, 4 total
6225 *
6226 * p2p, no mchan, and mbss:
6227 *
6228 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6229 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6230 * #AP <= 4, matching BI, channels = 1, 4 total
6231 *
6232 * p2p, mchan, and mbss:
6233 *
6234 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6235 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6236 * #AP <= 4, matching BI, channels = 1, 4 total
6237 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006238static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6239{
6240 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006241 struct ieee80211_iface_limit *c0_limits = NULL;
6242 struct ieee80211_iface_limit *p2p_limits = NULL;
6243 struct ieee80211_iface_limit *mbss_limits = NULL;
6244 bool mbss, p2p;
6245 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006246
Arend van Spriel0882dda2015-08-20 22:06:03 +02006247 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6248 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6249
6250 n_combos = 1 + !!p2p + !!mbss;
6251 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006252 if (!combo)
6253 goto err;
6254
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006255 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6256 BIT(NL80211_IFTYPE_ADHOC) |
6257 BIT(NL80211_IFTYPE_AP);
6258
Arend van Spriel0882dda2015-08-20 22:06:03 +02006259 c = 0;
6260 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006261 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6262 if (!c0_limits)
6263 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006264 c0_limits[i].max = 1;
6265 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6266 if (p2p) {
6267 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6268 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006269 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6270 BIT(NL80211_IFTYPE_P2P_GO) |
6271 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006272 c0_limits[i].max = 1;
6273 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6274 c0_limits[i].max = 1;
6275 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6276 BIT(NL80211_IFTYPE_P2P_GO);
6277 } else {
6278 c0_limits[i].max = 1;
6279 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006280 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006281 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006282 combo[c].max_interfaces = i;
6283 combo[c].n_limits = i;
6284 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006285
Arend van Spriel0882dda2015-08-20 22:06:03 +02006286 if (p2p) {
6287 c++;
6288 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006289 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6290 if (!p2p_limits)
6291 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006292 p2p_limits[i].max = 1;
6293 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6294 p2p_limits[i].max = 1;
6295 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6296 p2p_limits[i].max = 1;
6297 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6298 p2p_limits[i].max = 1;
6299 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006300 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006301 combo[c].max_interfaces = i;
6302 combo[c].n_limits = i;
6303 combo[c].limits = p2p_limits;
6304 }
6305
6306 if (mbss) {
6307 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006308 i = 0;
6309 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6310 if (!mbss_limits)
6311 goto err;
6312 mbss_limits[i].max = 4;
6313 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006314 combo[c].beacon_int_infra_match = true;
6315 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006316 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006317 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006318 combo[c].limits = mbss_limits;
6319 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006320
Arend van Spriel0882dda2015-08-20 22:06:03 +02006321 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006322 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006323 return 0;
6324
6325err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006326 kfree(c0_limits);
6327 kfree(p2p_limits);
6328 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006329 kfree(combo);
6330 return -ENOMEM;
6331}
6332
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006333static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6334{
6335 /* scheduled scan settings */
6336 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6337 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6338 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend Van Sprielc6989fd2016-11-23 10:25:30 +00006339 wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006340 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6341}
6342
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006343#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006344static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006345 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006346 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6347 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6348 .pattern_min_len = 1,
6349 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006350};
6351#endif
6352
Hante Meuleman3021ad92016-01-05 11:05:45 +01006353static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006354{
6355#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006356 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006357
6358 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006359 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6360 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6361 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006362 }
6363 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006364 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6365 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6366 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6367 }
6368
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006369 wiphy->wowlan = &brcmf_wowlan_support;
6370#endif
6371}
6372
Arend van Sprielb48d8912014-07-12 08:49:41 +02006373static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006374{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006375 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006376 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006377 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006378 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006379 __le32 bandlist[3];
6380 u32 n_bands;
6381 int err, i;
6382
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006383 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6384 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006385 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006386
6387 err = brcmf_setup_ifmodes(wiphy, ifp);
6388 if (err)
6389 return err;
6390
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006391 for (i = 0, combo = wiphy->iface_combinations;
6392 i < wiphy->n_iface_combinations; i++, combo++) {
6393 max_interfaces = max(max_interfaces, combo->max_interfaces);
6394 }
6395
6396 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6397 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006398 u8 *addr = drvr->addresses[i].addr;
6399
6400 memcpy(addr, drvr->mac, ETH_ALEN);
6401 if (i) {
6402 addr[0] |= BIT(1);
6403 addr[ETH_ALEN - 1] ^= i;
6404 }
6405 }
6406 wiphy->addresses = drvr->addresses;
6407 wiphy->n_addresses = i;
6408
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006409 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006410 wiphy->cipher_suites = brcmf_cipher_suites;
6411 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6412 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6413 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006414 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6415 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6416 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6417
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006418 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6419 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006420 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6421 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6422 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006423 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006424 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6425 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6426 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006427 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6428 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006429
6430 /* vendor commands/events support */
6431 wiphy->vendor_commands = brcmf_vendor_cmds;
6432 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6433
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006434 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006435 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006436 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6437 sizeof(bandlist));
6438 if (err) {
6439 brcmf_err("could not obtain band info: err=%d\n", err);
6440 return err;
6441 }
6442 /* first entry in bandlist is number of bands */
6443 n_bands = le32_to_cpu(bandlist[0]);
6444 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6445 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6446 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6447 GFP_KERNEL);
6448 if (!band)
6449 return -ENOMEM;
6450
6451 band->channels = kmemdup(&__wl_2ghz_channels,
6452 sizeof(__wl_2ghz_channels),
6453 GFP_KERNEL);
6454 if (!band->channels) {
6455 kfree(band);
6456 return -ENOMEM;
6457 }
6458
6459 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006460 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006461 }
6462 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6463 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6464 GFP_KERNEL);
6465 if (!band)
6466 return -ENOMEM;
6467
6468 band->channels = kmemdup(&__wl_5ghz_channels,
6469 sizeof(__wl_5ghz_channels),
6470 GFP_KERNEL);
6471 if (!band->channels) {
6472 kfree(band);
6473 return -ENOMEM;
6474 }
6475
6476 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006477 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006478 }
6479 }
6480 err = brcmf_setup_wiphybands(wiphy);
6481 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006482}
6483
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006484static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006485{
6486 struct net_device *ndev;
6487 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006488 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006489 s32 power_mode;
6490 s32 err = 0;
6491
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006492 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006493 return err;
6494
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006495 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006496 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006497 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006498
Hante Meuleman40a23292013-01-02 15:22:51 +01006499 /* make sure RF is ready for work */
6500 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6501
Hante Meuleman1678ba82015-12-10 13:43:00 +01006502 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006503
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006504 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006505 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006506 if (err)
6507 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006508 brcmf_dbg(INFO, "power save set to %s\n",
6509 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006510
Hante Meuleman1119e232015-11-25 11:32:42 +01006511 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006512 if (err)
6513 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006514 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6515 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006516 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006517 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006518
Franky Lin52f22fb2016-02-17 11:26:55 +01006519 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006520
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006521 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006522default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006523
6524 return err;
6525
6526}
6527
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006528static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006529{
Arend van Sprielc1179032012-10-22 13:55:33 -07006530 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006531
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006532 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006533}
6534
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006535static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006536{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006537 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006538
Arend van Spriel5b435de2011-10-05 13:19:03 +02006539 /*
6540 * While going down, if associated with AP disassociate
6541 * from AP to save power
6542 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006543 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006544 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006545
6546 /* Make sure WPA_Supplicant receives all the event
6547 generated due to DISASSOC call to the fw to keep
6548 the state fw and WPA_Supplicant state consistent
6549 */
6550 brcmf_delay(500);
6551 }
6552
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006553 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006554 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006555
Arend van Spriel5b435de2011-10-05 13:19:03 +02006556 return 0;
6557}
6558
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006559s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006560{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006561 struct brcmf_if *ifp = netdev_priv(ndev);
6562 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006563 s32 err = 0;
6564
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006565 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006566 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006567 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006568
6569 return err;
6570}
6571
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006572s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006573{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006574 struct brcmf_if *ifp = netdev_priv(ndev);
6575 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006576 s32 err = 0;
6577
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006578 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006579 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006580 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006581
6582 return err;
6583}
6584
Arend van Spriela7965fb2013-04-11 17:08:37 +02006585enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6586{
6587 struct wireless_dev *wdev = &ifp->vif->wdev;
6588
6589 return wdev->iftype;
6590}
6591
Hante Meulemanbfe81972014-10-28 14:56:16 +01006592bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6593 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006594{
6595 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006596
6597 list_for_each_entry(vif, &cfg->vif_list, list) {
6598 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006599 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006600 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006601 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006602}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006603
6604static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6605 u8 action)
6606{
6607 u8 evt_action;
6608
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006609 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006610 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006611 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006612 return evt_action == action;
6613}
6614
6615void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6616 struct brcmf_cfg80211_vif *vif)
6617{
6618 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6619
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006620 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006621 event->vif = vif;
6622 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006623 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006624}
6625
6626bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6627{
6628 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6629 bool armed;
6630
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006631 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006632 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006633 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006634
6635 return armed;
6636}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006637
6638int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6639 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006640{
6641 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6642
6643 return wait_event_timeout(event->vif_wq,
6644 vif_event_equals(event, action), timeout);
6645}
6646
Hante Meuleman73345fd2016-02-17 11:26:53 +01006647static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6648 struct brcmf_fil_country_le *ccreq)
6649{
Hante Meuleman4d792892016-02-17 11:27:07 +01006650 struct brcmfmac_pd_cc *country_codes;
6651 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006652 s32 found_index;
6653 int i;
6654
6655 country_codes = drvr->settings->country_codes;
6656 if (!country_codes) {
6657 brcmf_dbg(TRACE, "No country codes configured for device\n");
6658 return -EINVAL;
6659 }
6660
6661 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6662 (alpha2[1] == ccreq->country_abbrev[1])) {
6663 brcmf_dbg(TRACE, "Country code already set\n");
6664 return -EAGAIN;
6665 }
6666
6667 found_index = -1;
6668 for (i = 0; i < country_codes->table_size; i++) {
6669 cc = &country_codes->table[i];
6670 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6671 found_index = i;
6672 if ((cc->iso3166[0] == alpha2[0]) &&
6673 (cc->iso3166[1] == alpha2[1])) {
6674 found_index = i;
6675 break;
6676 }
6677 }
6678 if (found_index == -1) {
6679 brcmf_dbg(TRACE, "No country code match found\n");
6680 return -EINVAL;
6681 }
6682 memset(ccreq, 0, sizeof(*ccreq));
6683 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6684 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6685 BRCMF_COUNTRY_BUF_SZ);
6686 ccreq->country_abbrev[0] = alpha2[0];
6687 ccreq->country_abbrev[1] = alpha2[1];
6688 ccreq->country_abbrev[2] = 0;
6689
6690 return 0;
6691}
6692
Arend van Spriel63db1a42014-12-21 12:43:51 +01006693static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6694 struct regulatory_request *req)
6695{
6696 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6697 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6698 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006699 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006700 int i;
6701
Arend van Spriel63db1a42014-12-21 12:43:51 +01006702 /* ignore non-ISO3166 country codes */
6703 for (i = 0; i < sizeof(req->alpha2); i++)
6704 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006705 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6706 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006707 return;
6708 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006709
6710 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6711 req->alpha2[0], req->alpha2[1]);
6712
6713 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6714 if (err) {
6715 brcmf_err("Country code iovar returned err = %d\n", err);
6716 return;
6717 }
6718
6719 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6720 if (err)
6721 return;
6722
6723 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6724 if (err) {
6725 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006726 return;
6727 }
6728 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006729}
6730
Arend van Sprielb48d8912014-07-12 08:49:41 +02006731static void brcmf_free_wiphy(struct wiphy *wiphy)
6732{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006733 int i;
6734
Arend van Spriel58de92d2015-04-14 20:10:24 +02006735 if (!wiphy)
6736 return;
6737
Arend van Spriel0882dda2015-08-20 22:06:03 +02006738 if (wiphy->iface_combinations) {
6739 for (i = 0; i < wiphy->n_iface_combinations; i++)
6740 kfree(wiphy->iface_combinations[i].limits);
6741 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006742 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006743 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6744 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6745 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006746 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006747 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6748 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6749 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006750 }
6751 wiphy_free(wiphy);
6752}
6753
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006754struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006755 struct device *busdev,
6756 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006757{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006758 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006759 struct brcmf_cfg80211_info *cfg;
6760 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006761 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006762 struct brcmf_cfg80211_vif *vif;
6763 struct brcmf_if *ifp;
6764 s32 err = 0;
6765 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006766 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006767
6768 if (!ndev) {
6769 brcmf_err("ndev is invalid\n");
6770 return NULL;
6771 }
6772
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306773 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006774 if (!ops)
6775 return NULL;
6776
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006777 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006778#ifdef CONFIG_PM
6779 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6780 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6781#endif
6782 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006783 if (!wiphy) {
6784 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006785 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006786 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006787 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006788 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006789
6790 cfg = wiphy_priv(wiphy);
6791 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006792 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006793 cfg->pub = drvr;
6794 init_vif_event(&cfg->vif_event);
6795 INIT_LIST_HEAD(&cfg->vif_list);
6796
Rafał Miłecki26072332016-06-06 23:03:55 +02006797 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006798 if (IS_ERR(vif))
6799 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006800
6801 vif->ifp = ifp;
6802 vif->wdev.netdev = ndev;
6803 ndev->ieee80211_ptr = &vif->wdev;
6804 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6805
6806 err = wl_init_priv(cfg);
6807 if (err) {
6808 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006809 brcmf_free_vif(vif);
6810 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006811 }
6812 ifp->vif = vif;
6813
Arend van Sprielb48d8912014-07-12 08:49:41 +02006814 /* determine d11 io type before wiphy setup */
6815 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006816 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006817 brcmf_err("Failed to get D11 version (%d)\n", err);
6818 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006819 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006820 cfg->d11inf.io_type = (u8)io_type;
6821 brcmu_d11_attach(&cfg->d11inf);
6822
6823 err = brcmf_setup_wiphy(wiphy, ifp);
6824 if (err < 0)
6825 goto priv_out;
6826
6827 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006828 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006829 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6830 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6831
6832 /* firmware defaults to 40MHz disabled in 2G band. We signal
6833 * cfg80211 here that we do and have it decide we can enable
6834 * it. But first check if device does support 2G operation.
6835 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006836 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6837 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006838 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6839 }
6840 err = wiphy_register(wiphy);
6841 if (err < 0) {
6842 brcmf_err("Could not register wiphy device (%d)\n", err);
6843 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006844 }
6845
6846 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6847 * setup 40MHz in 2GHz band and enable OBSS scanning.
6848 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006849 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6850 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006851 if (!err)
6852 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6853 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006854 else
6855 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006856 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006857 /* p2p might require that "if-events" get processed by fweh. So
6858 * activate the already registered event handlers now and activate
6859 * the rest when initialization has completed. drvr->config needs to
6860 * be assigned before activating events.
6861 */
6862 drvr->config = cfg;
6863 err = brcmf_fweh_activate_events(ifp);
6864 if (err) {
6865 brcmf_err("FWEH activation failed (%d)\n", err);
6866 goto wiphy_unreg_out;
6867 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006868
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006869 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006870 if (err) {
6871 brcmf_err("P2P initilisation failed (%d)\n", err);
6872 goto wiphy_unreg_out;
6873 }
6874 err = brcmf_btcoex_attach(cfg);
6875 if (err) {
6876 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6877 brcmf_p2p_detach(&cfg->p2p);
6878 goto wiphy_unreg_out;
6879 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006880
Hante Meulemana7b82d42015-12-10 13:43:04 +01006881 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6882 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6883 if (err) {
6884 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6885 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6886 } else {
6887 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6888 brcmf_notify_tdls_peer_event);
6889 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006890 }
6891
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006892 /* (re-) activate FWEH event handling */
6893 err = brcmf_fweh_activate_events(ifp);
6894 if (err) {
6895 brcmf_err("FWEH activation failed (%d)\n", err);
6896 goto wiphy_unreg_out;
6897 }
6898
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006899 /* Fill in some of the advertised nl80211 supported features */
6900 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6901 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6902#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006903 if (wiphy->wowlan &&
6904 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006905 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6906#endif
6907 }
6908
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006909 return cfg;
6910
Arend van Sprielb48d8912014-07-12 08:49:41 +02006911wiphy_unreg_out:
6912 wiphy_unregister(cfg->wiphy);
6913priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006914 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006915 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006916 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006917wiphy_out:
6918 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006919 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006920 return NULL;
6921}
6922
6923void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6924{
6925 if (!cfg)
6926 return;
6927
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006928 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006929 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006930 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006931 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006932 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006933}