blob: 65cbb3d1e5090257473edb3c55f864fe7199de85 [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), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200141 .max_antenna_gain = 0, \
142 .max_power = 30, \
143}
144
145#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200146 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200147 .center_freq = 5000 + (5 * (_channel)), \
148 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200149 .max_antenna_gain = 0, \
150 .max_power = 30, \
151}
152
153static struct ieee80211_channel __wl_2ghz_channels[] = {
154 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
155 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
156 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
157 CHAN2G(13, 2472), CHAN2G(14, 2484)
158};
159
160static struct ieee80211_channel __wl_5ghz_channels[] = {
161 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
162 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
163 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
164 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
165 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
166 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
167};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200168
Arend van Sprielb48d8912014-07-12 08:49:41 +0200169/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200170 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200171 */
172static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200173 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200174 .bitrates = wl_g_rates,
175 .n_bitrates = wl_g_rates_size,
176};
177
Arend van Spriel58de92d2015-04-14 20:10:24 +0200178static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200179 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180 .bitrates = wl_a_rates,
181 .n_bitrates = wl_a_rates_size,
182};
183
Hante Meulemand48200b2013-04-03 12:40:29 +0200184/* This is to override regulatory domains defined in cfg80211 module (reg.c)
185 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200186 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
187 * With respect to these flags, wpa_supplicant doesn't * start p2p
188 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200189 * domain are to be done here.
190 */
191static const struct ieee80211_regdomain brcmf_regdom = {
192 .n_reg_rules = 4,
193 .alpha2 = "99",
194 .reg_rules = {
195 /* IEEE 802.11b/g, channels 1..11 */
196 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
197 /* If any */
198 /* IEEE 802.11 channel 14 - Only JP enables
199 * this and for 802.11b only
200 */
201 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
202 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200203 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200204 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200205 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200206};
207
Hante Meuleman240d61a2016-02-17 11:27:10 +0100208/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
209 * are supported. A pointer to this array and the number of entries is passed
210 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
211 * So the cipher suite AES_CMAC has to be the last one in the array, and when
212 * device does not support MFP then the number of suites will be decreased by 1
213 */
214static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200215 WLAN_CIPHER_SUITE_WEP40,
216 WLAN_CIPHER_SUITE_WEP104,
217 WLAN_CIPHER_SUITE_TKIP,
218 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219 /* Keep as last entry: */
220 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200221};
222
Hante Meuleman1a873342012-09-27 14:17:54 +0200223/* Vendor specific ie. id = 221, oui and type defines exact ie */
224struct brcmf_vs_tlv {
225 u8 id;
226 u8 len;
227 u8 oui[3];
228 u8 oui_type;
229};
230
231struct parsed_vndr_ie_info {
232 u8 *ie_ptr;
233 u32 ie_len; /* total length including id & length field */
234 struct brcmf_vs_tlv vndrie;
235};
236
237struct parsed_vndr_ies {
238 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100239 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200240};
241
Arend van Spriel7705ba62016-04-17 16:44:58 +0200242static u8 nl80211_band_to_fwil(enum nl80211_band band)
243{
244 switch (band) {
245 case NL80211_BAND_2GHZ:
246 return WLC_BAND_2G;
247 case NL80211_BAND_5GHZ:
248 return WLC_BAND_5G;
249 default:
250 WARN_ON(1);
251 break;
252 }
253 return 0;
254}
255
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200256static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
257 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200258{
259 struct brcmu_chan ch_inf;
260 s32 primary_offset;
261
262 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
263 ch->chan->center_freq, ch->center_freq1, ch->width);
264 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100265 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200266 switch (ch->width) {
267 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100268 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200269 ch_inf.bw = BRCMU_CHAN_BW_20;
270 WARN_ON(primary_offset != 0);
271 break;
272 case NL80211_CHAN_WIDTH_40:
273 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100274 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200275 ch_inf.sb = BRCMU_CHAN_SB_U;
276 else
277 ch_inf.sb = BRCMU_CHAN_SB_L;
278 break;
279 case NL80211_CHAN_WIDTH_80:
280 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100281 if (primary_offset == -30)
282 ch_inf.sb = BRCMU_CHAN_SB_LL;
283 else if (primary_offset == -10)
284 ch_inf.sb = BRCMU_CHAN_SB_LU;
285 else if (primary_offset == 10)
286 ch_inf.sb = BRCMU_CHAN_SB_UL;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200289 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100290 case NL80211_CHAN_WIDTH_80P80:
291 case NL80211_CHAN_WIDTH_160:
292 case NL80211_CHAN_WIDTH_5:
293 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200294 default:
295 WARN_ON_ONCE(1);
296 }
297 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200298 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200299 ch_inf.band = BRCMU_CHAN_BAND_2G;
300 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200301 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200302 ch_inf.band = BRCMU_CHAN_BAND_5G;
303 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200304 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 d11inf->encchspec(&ch_inf);
309
310 return ch_inf.chspec;
311}
312
Franky Lin83cf17a2013-04-11 13:28:50 +0200313u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
314 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700315{
Franky Lin83cf17a2013-04-11 13:28:50 +0200316 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700317
Franky Lin83cf17a2013-04-11 13:28:50 +0200318 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
319 ch_inf.bw = BRCMU_CHAN_BW_20;
320 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700321
Franky Lin83cf17a2013-04-11 13:28:50 +0200322 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700323}
324
Hante Meuleman89286dc2013-02-08 15:53:46 +0100325/* Traverse a string of 1-byte tag/1-byte length/variable-length value
326 * triples, returning a pointer to the substring whose first element
327 * matches tag
328 */
Rafał Miłeckic8d87072017-01-18 11:48:51 +0100329static const struct brcmf_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100330brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100331{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100332 const struct brcmf_tlv *elt = buf;
333 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100334
335 /* find tagged parameter */
336 while (totlen >= TLV_HDR_LEN) {
337 int len = elt->len;
338
339 /* validate remaining totlen */
340 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
341 return elt;
342
343 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
344 totlen -= (len + TLV_HDR_LEN);
345 }
346
347 return NULL;
348}
349
350/* Is any of the tlvs the expected entry? If
351 * not update the tlvs buffer pointer/length.
352 */
353static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100354brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
355 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100356{
357 /* If the contents match the OUI and the type */
358 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
359 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
360 type == ie[TLV_BODY_OFF + oui_len]) {
361 return true;
362 }
363
364 if (tlvs == NULL)
365 return false;
366 /* point to the next ie */
367 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
368 /* calculate the length of the rest of the buffer */
369 *tlvs_len -= (int)(ie - *tlvs);
370 /* update the pointer to the start of the buffer */
371 *tlvs = ie;
372
373 return false;
374}
375
376static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100377brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100378{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100379 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100380
381 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100382 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100383 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
384 return (struct brcmf_vs_tlv *)ie;
385 }
386 return NULL;
387}
388
389static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100392 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100393
394 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
395 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
396 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
397 return (struct brcmf_vs_tlv *)ie;
398 }
399 return NULL;
400}
401
Arend van Spriel39504a22015-08-20 22:06:05 +0200402static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
403 struct brcmf_cfg80211_vif *vif,
404 enum nl80211_iftype new_type)
405{
Arend van Spriel39504a22015-08-20 22:06:05 +0200406 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100407 bool check_combos = false;
408 int ret = 0;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530409 struct iface_combination_params params = {
410 .num_different_channels = 1,
411 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100414 if (pos == vif) {
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530415 params.iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100416 } else {
417 /* concurrent interfaces so need check combinations */
418 check_combos = true;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530419 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100420 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
Arend van Spriel353c46a2015-12-10 13:43:06 +0100422 if (check_combos)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530423 ret = cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424
425 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200426}
427
428static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
429 enum nl80211_iftype new_type)
430{
Arend van Spriel39504a22015-08-20 22:06:05 +0200431 struct brcmf_cfg80211_vif *pos;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530432 struct iface_combination_params params = {
433 .num_different_channels = 1,
434 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200435
Arend van Spriel39504a22015-08-20 22:06:05 +0200436 list_for_each_entry(pos, &cfg->vif_list, list)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530437 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel39504a22015-08-20 22:06:05 +0200438
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530439 params.iftype_num[new_type]++;
440 return cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel39504a22015-08-20 22:06:05 +0200441}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100442
Arend van Spriel5b435de2011-10-05 13:19:03 +0200443static void convert_key_from_CPU(struct brcmf_wsec_key *key,
444 struct brcmf_wsec_key_le *key_le)
445{
446 key_le->index = cpu_to_le32(key->index);
447 key_le->len = cpu_to_le32(key->len);
448 key_le->algo = cpu_to_le32(key->algo);
449 key_le->flags = cpu_to_le32(key->flags);
450 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
451 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
452 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
453 memcpy(key_le->data, key->data, sizeof(key->data));
454 memcpy(key_le->ea, key->ea, sizeof(key->ea));
455}
456
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200457static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100458send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459{
460 int err;
461 struct brcmf_wsec_key_le key_le;
462
463 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200464
Hante Meuleman118eb302014-12-21 12:43:49 +0100465 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700466
Hante Meuleman118eb302014-12-21 12:43:49 +0100467 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700468 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200469
Arend van Spriel5b435de2011-10-05 13:19:03 +0200470 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100471 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 return err;
473}
474
Hante Meulemanb3657452013-05-27 21:09:53 +0200475static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100476brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200477{
478 s32 err;
479 u32 mode;
480
481 if (enable)
482 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
483 else
484 mode = 0;
485
486 /* Try to set and enable ARP offload feature, this may fail, then it */
487 /* is simply not supported and err 0 will be returned */
488 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
489 if (err) {
490 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
491 mode, err);
492 err = 0;
493 } else {
494 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
495 if (err) {
496 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
497 enable, err);
498 err = 0;
499 } else
500 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
501 enable, mode);
502 }
503
Franky Lin52f22fb2016-02-17 11:26:55 +0100504 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
505 if (err) {
506 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
507 enable, err);
508 err = 0;
509 } else
510 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
511 enable, mode);
512
Hante Meulemanb3657452013-05-27 21:09:53 +0200513 return err;
514}
515
Hante Meuleman8851cce2014-07-30 13:20:02 +0200516static void
517brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
518{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200519 struct brcmf_cfg80211_vif *vif;
520 struct brcmf_if *ifp;
521
522 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
523 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200524
525 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
526 (wdev->iftype == NL80211_IFTYPE_AP) ||
527 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
528 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
529 ADDR_DIRECT);
530 else
531 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
532 ADDR_INDIRECT);
533}
534
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200535static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
536{
537 int bsscfgidx;
538
539 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
540 /* bsscfgidx 1 is reserved for legacy P2P */
541 if (bsscfgidx == 1)
542 continue;
543 if (!drvr->iflist[bsscfgidx])
544 return bsscfgidx;
545 }
546
547 return -ENOMEM;
548}
549
Hante Meulemana44aa402014-12-03 21:05:33 +0100550static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
551{
552 struct brcmf_mbss_ssid_le mbss_ssid_le;
553 int bsscfgidx;
554 int err;
555
556 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200557 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100558 if (bsscfgidx < 0)
559 return bsscfgidx;
560
561 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
562 mbss_ssid_le.SSID_len = cpu_to_le32(5);
563 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
564
565 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
566 sizeof(mbss_ssid_le));
567 if (err < 0)
568 brcmf_err("setting ssid failed %d\n", err);
569
570 return err;
571}
572
573/**
574 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
575 *
576 * @wiphy: wiphy device of new interface.
577 * @name: name of the new interface.
Hante Meulemana44aa402014-12-03 21:05:33 +0100578 * @params: contains mac address for AP device.
579 */
580static
581struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
Johannes Berg818a9862017-04-12 11:23:28 +0200582 struct vif_params *params)
Hante Meulemana44aa402014-12-03 21:05:33 +0100583{
584 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
585 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
586 struct brcmf_cfg80211_vif *vif;
587 int err;
588
589 if (brcmf_cfg80211_vif_event_armed(cfg))
590 return ERR_PTR(-EBUSY);
591
592 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
593
Rafał Miłecki26072332016-06-06 23:03:55 +0200594 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100595 if (IS_ERR(vif))
596 return (struct wireless_dev *)vif;
597
598 brcmf_cfg80211_arm_vif_event(cfg, vif);
599
600 err = brcmf_cfg80211_request_ap_if(ifp);
601 if (err) {
602 brcmf_cfg80211_arm_vif_event(cfg, NULL);
603 goto fail;
604 }
605
606 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100607 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
608 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100609 brcmf_cfg80211_arm_vif_event(cfg, NULL);
610 if (!err) {
611 brcmf_err("timeout occurred\n");
612 err = -EIO;
613 goto fail;
614 }
615
616 /* interface created in firmware */
617 ifp = vif->ifp;
618 if (!ifp) {
619 brcmf_err("no if pointer provided\n");
620 err = -ENOENT;
621 goto fail;
622 }
623
624 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
625 err = brcmf_net_attach(ifp, true);
626 if (err) {
627 brcmf_err("Registering netdevice failed\n");
Arend Van Sprieldca23072017-06-24 22:08:27 +0100628 free_netdev(ifp->ndev);
Hante Meulemana44aa402014-12-03 21:05:33 +0100629 goto fail;
630 }
631
632 return &ifp->vif->wdev;
633
634fail:
635 brcmf_free_vif(vif);
636 return ERR_PTR(err);
637}
638
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100639static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
640{
641 enum nl80211_iftype iftype;
642
643 iftype = vif->wdev.iftype;
644 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
645}
646
647static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
648{
649 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
650}
651
Arend van Spriel9f440b72013-02-08 15:53:36 +0100652static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
653 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100654 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100655 enum nl80211_iftype type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100656 struct vif_params *params)
657{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200658 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200659 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200660
Arend van Spriel9f440b72013-02-08 15:53:36 +0100661 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200662 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
663 if (err) {
664 brcmf_err("iface validation failed: err=%d\n", err);
665 return ERR_PTR(err);
666 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100667 switch (type) {
668 case NL80211_IFTYPE_ADHOC:
669 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100670 case NL80211_IFTYPE_AP_VLAN:
671 case NL80211_IFTYPE_WDS:
672 case NL80211_IFTYPE_MONITOR:
673 case NL80211_IFTYPE_MESH_POINT:
674 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100675 case NL80211_IFTYPE_AP:
Johannes Berg818a9862017-04-12 11:23:28 +0200676 wdev = brcmf_ap_add_vif(wiphy, name, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200677 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100678 case NL80211_IFTYPE_P2P_CLIENT:
679 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200680 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg818a9862017-04-12 11:23:28 +0200681 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200682 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100683 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100684 default:
685 return ERR_PTR(-EINVAL);
686 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200687
688 if (IS_ERR(wdev))
689 brcmf_err("add iface %s type %d failed: err=%d\n",
690 name, type, (int)PTR_ERR(wdev));
691 else
692 brcmf_cfg80211_update_proto_addr_mode(wdev);
693
694 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100695}
696
Daniel Kim5e787f72014-06-21 12:11:18 +0200697static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
698{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200699 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200700 brcmf_set_mpc(ifp, mpc);
701}
702
Arend van Sprielf96aa072013-04-05 10:57:48 +0200703void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100704{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100705 s32 err = 0;
706
707 if (check_vif_up(ifp->vif)) {
708 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
709 if (err) {
710 brcmf_err("fail to set mpc\n");
711 return;
712 }
713 brcmf_dbg(INFO, "MPC : %d\n", mpc);
714 }
715}
716
Arend van Spriela0f472a2013-04-05 10:57:49 +0200717s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
718 struct brcmf_if *ifp, bool aborted,
719 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100720{
721 struct brcmf_scan_params_le params_le;
722 struct cfg80211_scan_request *scan_request;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100723 u64 reqid;
724 u32 bucket;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100725 s32 err = 0;
726
727 brcmf_dbg(SCAN, "Enter\n");
728
729 /* clear scan request, because the FW abort can cause a second call */
730 /* to this functon and might cause a double cfg80211_scan_done */
731 scan_request = cfg->scan_request;
732 cfg->scan_request = NULL;
733
734 if (timer_pending(&cfg->escan_timeout))
735 del_timer_sync(&cfg->escan_timeout);
736
737 if (fw_abort) {
738 /* Do a scan abort to stop the driver's scan engine */
739 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
740 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800741 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100742 params_le.bss_type = DOT11_BSSTYPE_ANY;
743 params_le.scan_type = 0;
744 params_le.channel_num = cpu_to_le32(1);
745 params_le.nprobes = cpu_to_le32(1);
746 params_le.active_time = cpu_to_le32(-1);
747 params_le.passive_time = cpu_to_le32(-1);
748 params_le.home_time = cpu_to_le32(-1);
749 /* Scan is aborted by setting channel_list[0] to -1 */
750 params_le.channel_list[0] = cpu_to_le16(-1);
751 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200752 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100753 &params_le, sizeof(params_le));
754 if (err)
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100755 brcmf_err("Scan abort failed\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100756 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200757
Daniel Kim5e787f72014-06-21 12:11:18 +0200758 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200759
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100760 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000761 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100762 * which takes precedence.
763 */
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100764 if (cfg->int_escan_map) {
765 brcmf_dbg(SCAN, "scheduled scan completed (%x)\n",
766 cfg->int_escan_map);
767 while (cfg->int_escan_map) {
768 bucket = __ffs(cfg->int_escan_map);
769 cfg->int_escan_map &= ~BIT(bucket);
770 reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno,
771 bucket);
772 if (!aborted) {
773 brcmf_dbg(SCAN, "report results: reqid=%llu\n",
774 reqid);
775 cfg80211_sched_scan_results(cfg_to_wiphy(cfg),
776 reqid);
777 }
778 }
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100779 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300780 struct cfg80211_scan_info info = {
781 .aborted = aborted,
782 };
783
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100784 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
785 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300786 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100787 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100788 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
789 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100790
791 return err;
792}
793
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200794static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
795 struct wireless_dev *wdev)
796{
797 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
798 struct net_device *ndev = wdev->netdev;
799 struct brcmf_if *ifp = netdev_priv(ndev);
800 int ret;
801 int err;
802
803 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
804
805 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
806 if (err) {
807 brcmf_err("interface_remove failed %d\n", err);
808 goto err_unarm;
809 }
810
811 /* wait for firmware event */
812 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
813 BRCMF_VIF_EVENT_TIMEOUT);
814 if (!ret) {
815 brcmf_err("timeout occurred\n");
816 err = -EIO;
817 goto err_unarm;
818 }
819
820 brcmf_remove_interface(ifp, true);
821
822err_unarm:
823 brcmf_cfg80211_arm_vif_event(cfg, NULL);
824 return err;
825}
826
Arend van Spriel9f440b72013-02-08 15:53:36 +0100827static
828int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
829{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100830 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
831 struct net_device *ndev = wdev->netdev;
832
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200833 if (ndev && ndev == cfg_to_ndev(cfg))
834 return -ENOTSUPP;
835
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100836 /* vif event pending in firmware */
837 if (brcmf_cfg80211_vif_event_armed(cfg))
838 return -EBUSY;
839
840 if (ndev) {
841 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200842 cfg->escan_info.ifp == netdev_priv(ndev))
843 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
844 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100845
846 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
847 }
848
Arend van Spriel9f440b72013-02-08 15:53:36 +0100849 switch (wdev->iftype) {
850 case NL80211_IFTYPE_ADHOC:
851 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100852 case NL80211_IFTYPE_AP_VLAN:
853 case NL80211_IFTYPE_WDS:
854 case NL80211_IFTYPE_MONITOR:
855 case NL80211_IFTYPE_MESH_POINT:
856 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200857 case NL80211_IFTYPE_AP:
858 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100859 case NL80211_IFTYPE_P2P_CLIENT:
860 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200861 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100862 return brcmf_p2p_del_vif(wiphy, wdev);
863 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100864 default:
865 return -EINVAL;
866 }
867 return -EOPNOTSUPP;
868}
869
Arend van Spriel5b435de2011-10-05 13:19:03 +0200870static s32
871brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +0200872 enum nl80211_iftype type,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200873 struct vif_params *params)
874{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100875 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700876 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100877 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200878 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200879 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200880 s32 err = 0;
881
Hante Meuleman37a869e2015-10-29 20:33:17 +0100882 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
883 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200884
885 /* WAR: There are a number of p2p interface related problems which
886 * need to be handled initially (before doing the validate).
887 * wpa_supplicant tends to do iface changes on p2p device/client/go
888 * which are not always possible/allowed. However we need to return
889 * OK otherwise the wpa_supplicant wont start. The situation differs
890 * on configuration and setup (p2pon=1 module param). The first check
891 * is to see if the request is a change to station for p2p iface.
892 */
893 if ((type == NL80211_IFTYPE_STATION) &&
894 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
895 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
896 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
897 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
898 /* Now depending on whether module param p2pon=1 was used the
899 * response needs to be either 0 or EOPNOTSUPP. The reason is
900 * that if p2pon=1 is used, but a newer supplicant is used then
901 * we should return an error, as this combination wont work.
902 * In other situations 0 is returned and supplicant will start
903 * normally. It will give a trace in cfg80211, but it is the
904 * only way to get it working. Unfortunately this will result
905 * in situation where we wont support new supplicant in
906 * combination with module param p2pon=1, but that is the way
907 * it is. If the user tries this then unloading of driver might
908 * fail/lock.
909 */
910 if (cfg->p2p.p2pdev_dynamically)
911 return -EOPNOTSUPP;
912 else
913 return 0;
914 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200915 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
916 if (err) {
917 brcmf_err("iface validation failed: err=%d\n", err);
918 return err;
919 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200920 switch (type) {
921 case NL80211_IFTYPE_MONITOR:
922 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100923 brcmf_err("type (%d) : currently we do not support this type\n",
924 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200925 return -EOPNOTSUPP;
926 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200927 infra = 0;
928 break;
929 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200930 infra = 1;
931 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200932 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100933 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200934 ap = 1;
935 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200936 default:
937 err = -EINVAL;
938 goto done;
939 }
940
Hante Meuleman1a873342012-09-27 14:17:54 +0200941 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100942 if (type == NL80211_IFTYPE_P2P_GO) {
943 brcmf_dbg(INFO, "IF Type = P2P GO\n");
944 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
945 }
946 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100947 brcmf_dbg(INFO, "IF Type = AP\n");
948 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200949 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100950 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200951 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100952 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200953 err = -EAGAIN;
954 goto done;
955 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100956 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100957 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200958 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200959 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200960
Hante Meuleman8851cce2014-07-30 13:20:02 +0200961 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
962
Arend van Spriel5b435de2011-10-05 13:19:03 +0200963done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100964 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200965
966 return err;
967}
968
Franky Lin83cf17a2013-04-11 13:28:50 +0200969static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
970 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200971 struct cfg80211_scan_request *request)
972{
973 u32 n_ssids;
974 u32 n_channels;
975 s32 i;
976 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200977 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200978 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200979 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200980
Joe Perches93803b32015-03-02 19:54:49 -0800981 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200982 params_le->bss_type = DOT11_BSSTYPE_ANY;
983 params_le->scan_type = 0;
984 params_le->channel_num = 0;
985 params_le->nprobes = cpu_to_le32(-1);
986 params_le->active_time = cpu_to_le32(-1);
987 params_le->passive_time = cpu_to_le32(-1);
988 params_le->home_time = cpu_to_le32(-1);
989 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
990
991 /* if request is null exit so it will be all channel broadcast scan */
992 if (!request)
993 return;
994
995 n_ssids = request->n_ssids;
996 n_channels = request->n_channels;
997 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100998 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
999 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +02001000 if (n_channels > 0) {
1001 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02001002 chanspec = channel_to_chanspec(&cfg->d11inf,
1003 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001004 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
1005 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +02001006 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +02001007 }
1008 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001009 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001010 }
1011 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001012 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001013 if (n_ssids > 0) {
1014 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1015 n_channels * sizeof(u16);
1016 offset = roundup(offset, sizeof(u32));
1017 ptr = (char *)params_le + offset;
1018 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001019 memset(&ssid_le, 0, sizeof(ssid_le));
1020 ssid_le.SSID_len =
1021 cpu_to_le32(request->ssids[i].ssid_len);
1022 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1023 request->ssids[i].ssid_len);
1024 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001025 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001026 else
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01001027 brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001028 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001029 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1030 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001031 }
1032 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001033 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001034 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001035 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1036 params_le->ssid_le.SSID,
1037 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001038 params_le->ssid_le.SSID_len =
1039 cpu_to_le32(request->ssids->ssid_len);
1040 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1041 request->ssids->ssid_len);
1042 }
1043 }
1044 /* Adding mask to channel numbers */
1045 params_le->channel_num =
1046 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1047 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1048}
1049
1050static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001051brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001052 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001053{
1054 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1055 offsetof(struct brcmf_escan_params_le, params_le);
1056 struct brcmf_escan_params_le *params;
1057 s32 err = 0;
1058
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001059 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001060
1061 if (request != NULL) {
1062 /* Allocate space for populating ssids in struct */
1063 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1064
1065 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001066 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001067 }
1068
1069 params = kzalloc(params_size, GFP_KERNEL);
1070 if (!params) {
1071 err = -ENOMEM;
1072 goto exit;
1073 }
1074 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001075 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001076 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001077 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001078 params->sync_id = cpu_to_le16(0x1234);
1079
Arend van Spriela0f472a2013-04-05 10:57:49 +02001080 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001081 if (err) {
1082 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001083 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001084 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001085 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001086 }
1087
1088 kfree(params);
1089exit:
1090 return err;
1091}
1092
1093static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001094brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001095{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001096 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001097 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001098 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001099 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001100 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001101
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001102 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001103 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001104 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001105 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001106 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001107 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001108 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001110 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001111 return err;
1112 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001113 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001114 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001115 results->version = 0;
1116 results->count = 0;
1117 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1118
Hante Meulemanc4958102015-11-25 11:32:41 +01001119 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001120 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001121 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001122 return err;
1123}
1124
1125static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001126brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001127 struct cfg80211_scan_request *request,
1128 struct cfg80211_ssid *this_ssid)
1129{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001130 struct brcmf_if *ifp = vif->ifp;
1131 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001132 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001133 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001134 bool escan_req;
1135 bool spec_scan;
1136 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001137 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001138 u32 SSID_len;
1139
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001140 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001141
Arend van Sprielc1179032012-10-22 13:55:33 -07001142 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001143 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001144 return -EAGAIN;
1145 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001146 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001147 brcmf_err("Scanning being aborted: status (%lu)\n",
1148 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001149 return -EAGAIN;
1150 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001151 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1152 brcmf_err("Scanning suppressed: status (%lu)\n",
1153 cfg->scan_status);
1154 return -EAGAIN;
1155 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001156 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001157 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001158 return -EAGAIN;
1159 }
1160
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001161 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001162 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1163 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001164
Hante Meulemane756af52012-09-11 21:18:52 +02001165 escan_req = false;
1166 if (request) {
1167 /* scan bss */
1168 ssids = request->ssids;
1169 escan_req = true;
1170 } else {
1171 /* scan in ibss */
1172 /* we don't do escan in ibss */
1173 ssids = this_ssid;
1174 }
1175
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001176 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001177 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001178 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001179 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001180 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001181 if (err)
1182 goto scan_out;
1183
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001184 err = brcmf_do_escan(vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001185 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001186 goto scan_out;
1187 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001188 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1189 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001190 memset(&ssid_le, 0, sizeof(ssid_le));
1191 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1192 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001193 spec_scan = false;
1194 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001195 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1196 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001197 spec_scan = true;
1198 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001199 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001200
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001201 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001202 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001203 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001204 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001205 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001206 goto scan_out;
1207 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001208 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001209 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1210 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001211 if (err) {
1212 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001213 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001214 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001215 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001216 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001217
Daniel Kim5e787f72014-06-21 12:11:18 +02001218 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001219 goto scan_out;
1220 }
1221 }
1222
Hante Meuleman661fa952015-02-06 18:36:47 +01001223 /* Arm scan timeout timer */
1224 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001225 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001226
Hante Meulemane756af52012-09-11 21:18:52 +02001227 return 0;
1228
1229scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001230 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001231 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001232 return err;
1233}
1234
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001236brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001238 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 s32 err = 0;
1240
Arend van Sprield96b8012012-12-05 15:26:02 +01001241 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001242 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1243 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001244 return -EIO;
1245
Arend van Spriela0f472a2013-04-05 10:57:49 +02001246 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001247
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001249 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250
Arend van Sprield96b8012012-12-05 15:26:02 +01001251 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001252 return err;
1253}
1254
1255static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1256{
1257 s32 err = 0;
1258
Arend van Sprielac24be62012-10-22 10:36:23 -07001259 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1260 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001261 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001262 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001263
1264 return err;
1265}
1266
1267static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1268{
1269 s32 err = 0;
1270
Arend van Sprielac24be62012-10-22 10:36:23 -07001271 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1272 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001273 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001274 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275
1276 return err;
1277}
1278
1279static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1280{
1281 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001282 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283
Arend van Sprielac24be62012-10-22 10:36:23 -07001284 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001286 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001287 return err;
1288 }
1289 return err;
1290}
1291
1292static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1293{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001294 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1295 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001296 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001297 s32 err = 0;
1298
Arend van Sprield96b8012012-12-05 15:26:02 +01001299 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001300 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301 return -EIO;
1302
1303 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001304 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1305 cfg->conf->rts_threshold = wiphy->rts_threshold;
1306 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001307 if (!err)
1308 goto done;
1309 }
1310 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001311 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1312 cfg->conf->frag_threshold = wiphy->frag_threshold;
1313 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001314 if (!err)
1315 goto done;
1316 }
1317 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001318 && (cfg->conf->retry_long != wiphy->retry_long)) {
1319 cfg->conf->retry_long = wiphy->retry_long;
1320 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 if (!err)
1322 goto done;
1323 }
1324 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001325 && (cfg->conf->retry_short != wiphy->retry_short)) {
1326 cfg->conf->retry_short = wiphy->retry_short;
1327 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001328 if (!err)
1329 goto done;
1330 }
1331
1332done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001333 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334 return err;
1335}
1336
Arend van Spriel5b435de2011-10-05 13:19:03 +02001337static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1338{
1339 memset(prof, 0, sizeof(*prof));
1340}
1341
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001342static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1343{
1344 u16 reason;
1345
1346 switch (e->event_code) {
1347 case BRCMF_E_DEAUTH:
1348 case BRCMF_E_DEAUTH_IND:
1349 case BRCMF_E_DISASSOC_IND:
1350 reason = e->reason;
1351 break;
1352 case BRCMF_E_LINK:
1353 default:
1354 reason = 0;
1355 break;
1356 }
1357 return reason;
1358}
1359
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001360static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
1361{
1362 struct brcmf_wsec_pmk_le pmk;
1363 int i, err;
1364
1365 /* convert to firmware key format */
1366 pmk.key_len = cpu_to_le16(pmk_len << 1);
1367 pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
1368 for (i = 0; i < pmk_len; i++)
1369 snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
1370
1371 /* store psk in firmware */
1372 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
1373 &pmk, sizeof(pmk));
1374 if (err < 0)
1375 brcmf_err("failed to change PSK in firmware (len=%u)\n",
1376 pmk_len);
1377
1378 return err;
1379}
1380
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001381static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001382{
Piotr Haber61730d42013-04-23 12:53:12 +02001383 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001384 s32 err = 0;
1385
Arend van Sprield96b8012012-12-05 15:26:02 +01001386 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387
Hante Meulemanb0a79082015-12-10 13:43:07 +01001388 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001389 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001390 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001391 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001392 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001393 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001394 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001395 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1396 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1397 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1398 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001400 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001401 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1402 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001403 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
1404 brcmf_set_pmk(vif->ifp, NULL, 0);
1405 vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1406 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001407 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408}
1409
1410static s32
1411brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1412 struct cfg80211_ibss_params *params)
1413{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001414 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001415 struct brcmf_if *ifp = netdev_priv(ndev);
1416 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 struct brcmf_join_params join_params;
1418 size_t join_params_size = 0;
1419 s32 err = 0;
1420 s32 wsec = 0;
1421 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001422 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001423 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424
Arend van Sprield96b8012012-12-05 15:26:02 +01001425 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001426 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 return -EIO;
1428
1429 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001430 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001432 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 return -EOPNOTSUPP;
1434 }
1435
Arend van Sprielc1179032012-10-22 13:55:33 -07001436 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001437
1438 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001439 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 else
Arend van Spriel16886732012-12-05 15:26:04 +01001441 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442
Johannes Berg683b6d32012-11-08 21:25:48 +01001443 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001444 brcmf_dbg(CONN, "channel: %d\n",
1445 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446 else
Arend van Spriel16886732012-12-05 15:26:04 +01001447 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001448
1449 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001450 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001451 else
Arend van Spriel16886732012-12-05 15:26:04 +01001452 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453
1454 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001455 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 else
Arend van Spriel16886732012-12-05 15:26:04 +01001457 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458
1459 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001460 brcmf_dbg(CONN, "beacon interval: %d\n",
1461 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001462 else
Arend van Spriel16886732012-12-05 15:26:04 +01001463 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001464
1465 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001466 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467 else
Arend van Spriel16886732012-12-05 15:26:04 +01001468 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001469
1470 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001471 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472 else
Arend van Spriel16886732012-12-05 15:26:04 +01001473 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474
1475 /* Configure Privacy for starter */
1476 if (params->privacy)
1477 wsec |= WEP_ENABLED;
1478
Arend van Sprielc1179032012-10-22 13:55:33 -07001479 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001481 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 goto done;
1483 }
1484
1485 /* Configure Beacon Interval for starter */
1486 if (params->beacon_interval)
1487 bcnprd = params->beacon_interval;
1488 else
1489 bcnprd = 100;
1490
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001491 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001492 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001493 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494 goto done;
1495 }
1496
1497 /* Configure required join parameter */
1498 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1499
1500 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001501 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1502 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1503 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001504 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505
1506 /* BSSID */
1507 if (params->bssid) {
1508 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001509 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001510 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001512 eth_broadcast_addr(join_params.params_le.bssid);
1513 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001514 }
1515
Arend van Spriel5b435de2011-10-05 13:19:03 +02001516 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001517 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518 u32 target_channel;
1519
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001520 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001521 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001522 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001523 if (params->channel_fixed) {
1524 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001525 chanspec = chandef_to_chanspec(&cfg->d11inf,
1526 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001527 join_params.params_le.chanspec_list[0] =
1528 cpu_to_le16(chanspec);
1529 join_params.params_le.chanspec_num = cpu_to_le32(1);
1530 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531 }
1532
1533 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001534 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001535 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001536 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001538 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539 goto done;
1540 }
1541 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001542 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001544 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001545
1546
Arend van Sprielc1179032012-10-22 13:55:33 -07001547 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001548 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001550 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 goto done;
1552 }
1553
1554done:
1555 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001556 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001557 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001558 return err;
1559}
1560
1561static s32
1562brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1563{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001564 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565
Arend van Sprield96b8012012-12-05 15:26:02 +01001566 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001567 if (!check_vif_up(ifp->vif)) {
1568 /* When driver is being unloaded, it can end up here. If an
1569 * error is returned then later on a debug trace in the wireless
1570 * core module will be printed. To avoid this 0 is returned.
1571 */
1572 return 0;
1573 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001575 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001576 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577
Arend van Sprield96b8012012-12-05 15:26:02 +01001578 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001579
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001580 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001581}
1582
1583static s32 brcmf_set_wpa_version(struct net_device *ndev,
1584 struct cfg80211_connect_params *sme)
1585{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001586 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587 struct brcmf_cfg80211_security *sec;
1588 s32 val = 0;
1589 s32 err = 0;
1590
1591 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1592 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1593 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1594 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1595 else
1596 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001597 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001598 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001600 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001601 return err;
1602 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001603 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001604 sec->wpa_versions = sme->crypto.wpa_versions;
1605 return err;
1606}
1607
1608static s32 brcmf_set_auth_type(struct net_device *ndev,
1609 struct cfg80211_connect_params *sme)
1610{
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 val = 0;
1614 s32 err = 0;
1615
1616 switch (sme->auth_type) {
1617 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1618 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001619 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001620 break;
1621 case NL80211_AUTHTYPE_SHARED_KEY:
1622 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001623 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 default:
1626 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001627 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001628 break;
1629 }
1630
Hante Meuleman89286dc2013-02-08 15:53:46 +01001631 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001633 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001634 return err;
1635 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001636 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001637 sec->auth_type = sme->auth_type;
1638 return err;
1639}
1640
1641static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001642brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001643 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001644{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001645 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 struct brcmf_cfg80211_security *sec;
1647 s32 pval = 0;
1648 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001649 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001650 s32 err = 0;
1651
1652 if (sme->crypto.n_ciphers_pairwise) {
1653 switch (sme->crypto.ciphers_pairwise[0]) {
1654 case WLAN_CIPHER_SUITE_WEP40:
1655 case WLAN_CIPHER_SUITE_WEP104:
1656 pval = WEP_ENABLED;
1657 break;
1658 case WLAN_CIPHER_SUITE_TKIP:
1659 pval = TKIP_ENABLED;
1660 break;
1661 case WLAN_CIPHER_SUITE_CCMP:
1662 pval = AES_ENABLED;
1663 break;
1664 case WLAN_CIPHER_SUITE_AES_CMAC:
1665 pval = AES_ENABLED;
1666 break;
1667 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001668 brcmf_err("invalid cipher pairwise (%d)\n",
1669 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001670 return -EINVAL;
1671 }
1672 }
1673 if (sme->crypto.cipher_group) {
1674 switch (sme->crypto.cipher_group) {
1675 case WLAN_CIPHER_SUITE_WEP40:
1676 case WLAN_CIPHER_SUITE_WEP104:
1677 gval = WEP_ENABLED;
1678 break;
1679 case WLAN_CIPHER_SUITE_TKIP:
1680 gval = TKIP_ENABLED;
1681 break;
1682 case WLAN_CIPHER_SUITE_CCMP:
1683 gval = AES_ENABLED;
1684 break;
1685 case WLAN_CIPHER_SUITE_AES_CMAC:
1686 gval = AES_ENABLED;
1687 break;
1688 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001689 brcmf_err("invalid cipher group (%d)\n",
1690 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001691 return -EINVAL;
1692 }
1693 }
1694
Arend van Spriel16886732012-12-05 15:26:04 +01001695 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001696 /* In case of privacy, but no security and WPS then simulate */
1697 /* setting AES. WPS-2.0 allows no security */
1698 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1699 sme->privacy)
1700 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001701
Hante Meuleman240d61a2016-02-17 11:27:10 +01001702 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001703 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001704 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001705 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001706 return err;
1707 }
1708
Arend van Spriel06bb1232012-09-27 14:17:56 +02001709 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001710 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1711 sec->cipher_group = sme->crypto.cipher_group;
1712
1713 return err;
1714}
1715
1716static s32
1717brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1718{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001719 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001720 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001721 s32 val;
1722 s32 err;
1723 const struct brcmf_tlv *rsn_ie;
1724 const u8 *ie;
1725 u32 ie_len;
1726 u32 offset;
1727 u16 rsn_cap;
1728 u32 mfp;
1729 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001730
Arend van Spriel2526ff22017-06-09 13:08:48 +01001731 profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1732
Hante Meuleman240d61a2016-02-17 11:27:10 +01001733 if (!sme->crypto.n_akm_suites)
1734 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735
Hante Meuleman240d61a2016-02-17 11:27:10 +01001736 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1737 if (err) {
1738 brcmf_err("could not get wpa_auth (%d)\n", err);
1739 return err;
1740 }
1741 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1742 switch (sme->crypto.akm_suites[0]) {
1743 case WLAN_AKM_SUITE_8021X:
1744 val = WPA_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001745 if (sme->want_1x)
1746 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001747 break;
1748 case WLAN_AKM_SUITE_PSK:
1749 val = WPA_AUTH_PSK;
1750 break;
1751 default:
1752 brcmf_err("invalid cipher group (%d)\n",
1753 sme->crypto.cipher_group);
1754 return -EINVAL;
1755 }
1756 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1757 switch (sme->crypto.akm_suites[0]) {
1758 case WLAN_AKM_SUITE_8021X:
1759 val = WPA2_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001760 if (sme->want_1x)
1761 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001762 break;
1763 case WLAN_AKM_SUITE_8021X_SHA256:
1764 val = WPA2_AUTH_1X_SHA256;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001765 if (sme->want_1x)
1766 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001767 break;
1768 case WLAN_AKM_SUITE_PSK_SHA256:
1769 val = WPA2_AUTH_PSK_SHA256;
1770 break;
1771 case WLAN_AKM_SUITE_PSK:
1772 val = WPA2_AUTH_PSK;
1773 break;
1774 default:
1775 brcmf_err("invalid cipher group (%d)\n",
1776 sme->crypto.cipher_group);
1777 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001778 }
1779 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001780
Arend van Spriel2526ff22017-06-09 13:08:48 +01001781 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
1782 brcmf_dbg(INFO, "using 1X offload\n");
1783
Hante Meuleman240d61a2016-02-17 11:27:10 +01001784 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1785 goto skip_mfp_config;
1786 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1787 * IE will not be verified, just a quick search for MFP config
1788 */
1789 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1790 WLAN_EID_RSN);
1791 if (!rsn_ie)
1792 goto skip_mfp_config;
1793 ie = (const u8 *)rsn_ie;
1794 ie_len = rsn_ie->len + TLV_HDR_LEN;
1795 /* Skip unicast suite */
1796 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1797 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1798 goto skip_mfp_config;
1799 /* Skip multicast suite */
1800 count = ie[offset] + (ie[offset + 1] << 8);
1801 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1802 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1803 goto skip_mfp_config;
1804 /* Skip auth key management suite(s) */
1805 count = ie[offset] + (ie[offset + 1] << 8);
1806 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1807 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1808 goto skip_mfp_config;
1809 /* Ready to read capabilities */
1810 mfp = BRCMF_MFP_NONE;
1811 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1812 if (rsn_cap & RSN_CAP_MFPR_MASK)
1813 mfp = BRCMF_MFP_REQUIRED;
1814 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1815 mfp = BRCMF_MFP_CAPABLE;
1816 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1817
1818skip_mfp_config:
1819 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1820 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1821 if (err) {
1822 brcmf_err("could not set wpa_auth (%d)\n", err);
1823 return err;
1824 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001825
1826 return err;
1827}
1828
1829static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001830brcmf_set_sharedkey(struct net_device *ndev,
1831 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001832{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001833 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001834 struct brcmf_cfg80211_security *sec;
1835 struct brcmf_wsec_key key;
1836 s32 val;
1837 s32 err = 0;
1838
Arend van Spriel16886732012-12-05 15:26:04 +01001839 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840
Roland Vossena718e2f2011-10-12 20:51:24 +02001841 if (sme->key_len == 0)
1842 return 0;
1843
Arend van Spriel06bb1232012-09-27 14:17:56 +02001844 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001845 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1846 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001847
1848 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1849 return 0;
1850
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001851 if (!(sec->cipher_pairwise &
1852 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1853 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001854
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001855 memset(&key, 0, sizeof(key));
1856 key.len = (u32) sme->key_len;
1857 key.index = (u32) sme->key_idx;
1858 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001859 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001860 return -EINVAL;
1861 }
1862 memcpy(key.data, sme->key, key.len);
1863 key.flags = BRCMF_PRIMARY_KEY;
1864 switch (sec->cipher_pairwise) {
1865 case WLAN_CIPHER_SUITE_WEP40:
1866 key.algo = CRYPTO_ALGO_WEP1;
1867 break;
1868 case WLAN_CIPHER_SUITE_WEP104:
1869 key.algo = CRYPTO_ALGO_WEP128;
1870 break;
1871 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001872 brcmf_err("Invalid algorithm (%d)\n",
1873 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001874 return -EINVAL;
1875 }
1876 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001877 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1878 key.len, key.index, key.algo);
1879 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001880 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001881 if (err)
1882 return err;
1883
1884 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001885 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001886 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001887 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001888 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001889 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 }
1891 return err;
1892}
1893
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001894static
1895enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1896 enum nl80211_auth_type type)
1897{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001898 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1899 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1900 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1901 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001902 }
1903 return type;
1904}
1905
Arend van Spriel7705ba62016-04-17 16:44:58 +02001906static void brcmf_set_join_pref(struct brcmf_if *ifp,
1907 struct cfg80211_bss_selection *bss_select)
1908{
1909 struct brcmf_join_pref_params join_pref_params[2];
1910 enum nl80211_band band;
1911 int err, i = 0;
1912
1913 join_pref_params[i].len = 2;
1914 join_pref_params[i].rssi_gain = 0;
1915
1916 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1917 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1918
1919 switch (bss_select->behaviour) {
1920 case __NL80211_BSS_SELECT_ATTR_INVALID:
1921 brcmf_c_set_joinpref_default(ifp);
1922 return;
1923 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1924 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1925 band = bss_select->param.band_pref;
1926 join_pref_params[i].band = nl80211_band_to_fwil(band);
1927 i++;
1928 break;
1929 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1930 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1931 band = bss_select->param.adjust.band;
1932 join_pref_params[i].band = nl80211_band_to_fwil(band);
1933 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1934 i++;
1935 break;
1936 case NL80211_BSS_SELECT_ATTR_RSSI:
1937 default:
1938 break;
1939 }
1940 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1941 join_pref_params[i].len = 2;
1942 join_pref_params[i].rssi_gain = 0;
1943 join_pref_params[i].band = 0;
1944 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1945 sizeof(join_pref_params));
1946 if (err)
1947 brcmf_err("Set join_pref error (%d)\n", err);
1948}
1949
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950static s32
1951brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001952 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001953{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001954 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001955 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001956 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 struct ieee80211_channel *chan = sme->channel;
1958 struct brcmf_join_params join_params;
1959 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001960 const struct brcmf_tlv *rsn_ie;
1961 const struct brcmf_vs_tlv *wpa_ie;
1962 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001963 u32 ie_len;
1964 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001965 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001966 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001967 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968
Arend van Sprield96b8012012-12-05 15:26:02 +01001969 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001970 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001971 return -EIO;
1972
1973 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001974 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001975 return -EOPNOTSUPP;
1976 }
1977
Hante Meuleman89286dc2013-02-08 15:53:46 +01001978 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1979 /* A normal (non P2P) connection request setup. */
1980 ie = NULL;
1981 ie_len = 0;
1982 /* find the WPA_IE */
1983 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1984 if (wpa_ie) {
1985 ie = wpa_ie;
1986 ie_len = wpa_ie->len + TLV_HDR_LEN;
1987 } else {
1988 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001989 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1990 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001991 WLAN_EID_RSN);
1992 if (rsn_ie) {
1993 ie = rsn_ie;
1994 ie_len = rsn_ie->len + TLV_HDR_LEN;
1995 }
1996 }
1997 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1998 }
1999
2000 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
2001 sme->ie, sme->ie_len);
2002 if (err)
2003 brcmf_err("Set Assoc REQ IE Failed\n");
2004 else
2005 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
2006
Arend van Sprielc1179032012-10-22 13:55:33 -07002007 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008
2009 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002010 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02002011 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02002012 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01002013 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
2014 cfg->channel, chan->center_freq, chanspec);
2015 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002016 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01002017 chanspec = 0;
2018 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002019
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002020 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021
2022 err = brcmf_set_wpa_version(ndev, sme);
2023 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002024 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002025 goto done;
2026 }
2027
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01002028 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002029 err = brcmf_set_auth_type(ndev, sme);
2030 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002031 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002032 goto done;
2033 }
2034
Hante Meuleman240d61a2016-02-17 11:27:10 +01002035 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002036 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002037 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002038 goto done;
2039 }
2040
2041 err = brcmf_set_key_mgmt(ndev, sme);
2042 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002043 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002044 goto done;
2045 }
2046
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002047 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002049 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 goto done;
2051 }
2052
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002053 if (sme->crypto.psk) {
Arend van Spriel2526ff22017-06-09 13:08:48 +01002054 if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
2055 err = -EINVAL;
2056 goto done;
2057 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002058 brcmf_dbg(INFO, "using PSK offload\n");
Arend van Spriel2526ff22017-06-09 13:08:48 +01002059 profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
2060 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002061
Arend van Spriel2526ff22017-06-09 13:08:48 +01002062 if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002063 /* enable firmware supplicant for this interface */
2064 err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
2065 if (err < 0) {
2066 brcmf_err("failed to enable fw supplicant\n");
2067 goto done;
2068 }
Arend van Spriel2526ff22017-06-09 13:08:48 +01002069 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002070
Arend van Spriel2526ff22017-06-09 13:08:48 +01002071 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002072 err = brcmf_set_pmk(ifp, sme->crypto.psk,
2073 BRCMF_WSEC_MAX_PSK_LEN);
2074 if (err)
2075 goto done;
2076 }
2077
Hante Meuleman89286dc2013-02-08 15:53:46 +01002078 /* Join with specific BSSID and cached SSID
2079 * If SSID is zero join based on BSSID only
2080 */
2081 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2082 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2083 if (cfg->channel)
2084 join_params_size += sizeof(u16);
2085 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2086 if (ext_join_params == NULL) {
2087 err = -ENOMEM;
2088 goto done;
2089 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002090 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2091 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2092 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2093 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2094 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2095 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002096
Hante Meuleman89286dc2013-02-08 15:53:46 +01002097 /* Set up join scan parameters */
2098 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002099 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2100
2101 if (sme->bssid)
2102 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2103 else
Joe Perches93803b32015-03-02 19:54:49 -08002104 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002105
2106 if (cfg->channel) {
2107 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2108
2109 ext_join_params->assoc_le.chanspec_list[0] =
2110 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002111 /* Increase dwell time to receive probe response or detect
2112 * beacon from target AP at a noisy air only during connect
2113 * command.
2114 */
2115 ext_join_params->scan_le.active_time =
2116 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2117 ext_join_params->scan_le.passive_time =
2118 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2119 /* To sync with presence period of VSDB GO send probe request
2120 * more frequently. Probe request will be stopped when it gets
2121 * probe response from target AP/GO.
2122 */
2123 ext_join_params->scan_le.nprobes =
2124 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2125 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2126 } else {
2127 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2128 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2129 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002130 }
2131
Arend van Spriel7705ba62016-04-17 16:44:58 +02002132 brcmf_set_join_pref(ifp, &sme->bss_select);
2133
Hante Meuleman89286dc2013-02-08 15:53:46 +01002134 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2135 join_params_size);
2136 kfree(ext_join_params);
2137 if (!err)
2138 /* This is it. join command worked, we are done */
2139 goto done;
2140
2141 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142 memset(&join_params, 0, sizeof(join_params));
2143 join_params_size = sizeof(join_params.ssid_le);
2144
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002145 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2146 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147
Hante Meuleman89286dc2013-02-08 15:53:46 +01002148 if (sme->bssid)
2149 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2150 else
Joe Perches93803b32015-03-02 19:54:49 -08002151 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152
Hante Meuleman17012612013-02-06 18:40:44 +01002153 if (cfg->channel) {
2154 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2155 join_params.params_le.chanspec_num = cpu_to_le32(1);
2156 join_params_size += sizeof(join_params.params_le);
2157 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002158 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002159 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002161 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
2163done:
2164 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002165 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002166 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 return err;
2168}
2169
2170static s32
2171brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2172 u16 reason_code)
2173{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002174 struct brcmf_if *ifp = netdev_priv(ndev);
2175 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002176 struct brcmf_scb_val_le scbval;
2177 s32 err = 0;
2178
Arend van Sprield96b8012012-12-05 15:26:02 +01002179 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002180 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181 return -EIO;
2182
Arend van Sprielc1179032012-10-22 13:55:33 -07002183 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002184 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002185 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002186
Arend van Spriel06bb1232012-09-27 14:17:56 +02002187 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002188 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002189 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002190 &scbval, sizeof(scbval));
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
Arend van Sprield96b8012012-12-05 15:26:02 +01002194 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 return err;
2196}
2197
2198static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002199brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002200 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002202 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002203 struct net_device *ndev = cfg_to_ndev(cfg);
2204 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002205 s32 err;
2206 s32 disable;
2207 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002208
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002209 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002210 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002211 return -EIO;
2212
2213 switch (type) {
2214 case NL80211_TX_POWER_AUTOMATIC:
2215 break;
2216 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002218 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002219 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220 err = -EINVAL;
2221 goto done;
2222 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002223 qdbm = MBM_TO_DBM(4 * mbm);
2224 if (qdbm > 127)
2225 qdbm = 127;
2226 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002227 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002228 default:
2229 brcmf_err("Unsupported type %d\n", type);
2230 err = -EINVAL;
2231 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 }
2233 /* Make sure radio is off or on as far as software is concerned */
2234 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002235 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002237 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002239 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002240 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002241 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002242
2243done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002244 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 return err;
2246}
2247
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002248static s32
2249brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2250 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002252 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002253 struct net_device *ndev = cfg_to_ndev(cfg);
2254 struct brcmf_if *ifp = netdev_priv(ndev);
2255 s32 qdbm = 0;
2256 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002257
Arend van Sprield96b8012012-12-05 15:26:02 +01002258 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002259 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260 return -EIO;
2261
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002262 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002264 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 goto done;
2266 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002267 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002268
2269done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002270 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002271 return err;
2272}
2273
2274static s32
2275brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002276 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002278 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002279 u32 index;
2280 u32 wsec;
2281 s32 err = 0;
2282
Arend van Sprield96b8012012-12-05 15:26:02 +01002283 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002284 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002285 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002286 return -EIO;
2287
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002288 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002290 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002291 goto done;
2292 }
2293
2294 if (wsec & WEP_ENABLED) {
2295 /* Just select a new current key */
2296 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002297 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002298 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002299 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002300 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 }
2302done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002303 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002304 return err;
2305}
2306
2307static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002308brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2309 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310{
Hante Meuleman992f6062013-04-02 21:06:17 +02002311 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002312 struct brcmf_wsec_key *key;
2313 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002314
2315 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002316 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2317
Hante Meuleman219e0f72016-02-17 11:27:09 +01002318 if (!check_vif_up(ifp->vif))
2319 return -EIO;
2320
2321 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2322 /* we ignore this key index in this case */
2323 return -EINVAL;
2324 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002325
Hante Meuleman240d61a2016-02-17 11:27:10 +01002326 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002327
Hante Meuleman240d61a2016-02-17 11:27:10 +01002328 if (key->algo == CRYPTO_ALGO_OFF) {
2329 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2330 return -EINVAL;
2331 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332
Hante Meuleman240d61a2016-02-17 11:27:10 +01002333 memset(key, 0, sizeof(*key));
2334 key->index = (u32)key_idx;
2335 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336
Hante Meuleman240d61a2016-02-17 11:27:10 +01002337 /* Clear the key/index */
2338 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339
Hante Meuleman219e0f72016-02-17 11:27:09 +01002340 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002341 return err;
2342}
2343
2344static s32
2345brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002346 u8 key_idx, bool pairwise, const u8 *mac_addr,
2347 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002349 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002350 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002351 s32 val;
2352 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002353 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002354 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002355 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356
Arend van Sprield96b8012012-12-05 15:26:02 +01002357 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002358 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002359 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360 return -EIO;
2361
Hante Meuleman118eb302014-12-21 12:43:49 +01002362 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2363 /* we ignore this key index in this case */
2364 brcmf_err("invalid key index (%d)\n", key_idx);
2365 return -EINVAL;
2366 }
2367
Hante Meuleman219e0f72016-02-17 11:27:09 +01002368 if (params->key_len == 0)
2369 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2370 mac_addr);
2371
2372 if (params->key_len > sizeof(key->data)) {
2373 brcmf_err("Too long key length (%u)\n", params->key_len);
2374 return -EINVAL;
2375 }
2376
2377 ext_key = false;
2378 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2379 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2380 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2381 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002383
Hante Meuleman118eb302014-12-21 12:43:49 +01002384 key = &ifp->vif->profile.key[key_idx];
2385 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002386 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2387 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002388 key->len = params->key_len;
2389 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002390 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002391 if (!ext_key)
2392 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002393
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 switch (params->cipher) {
2395 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002396 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002397 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002398 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399 break;
2400 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002401 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002402 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002403 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404 break;
2405 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002406 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002407 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002408 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2409 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2410 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002411 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002412 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002413 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002414 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 break;
2416 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002417 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002418 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002419 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002420 break;
2421 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002422 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002423 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002424 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425 break;
2426 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002427 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 err = -EINVAL;
2429 goto done;
2430 }
2431
Hante Meuleman118eb302014-12-21 12:43:49 +01002432 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002433 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434 goto done;
2435
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002436 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002437 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002438 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002439 goto done;
2440 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002441 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002442 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002443 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002444 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002445 goto done;
2446 }
2447
Arend van Spriel5b435de2011-10-05 13:19:03 +02002448done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002449 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002450 return err;
2451}
2452
2453static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002454brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2455 bool pairwise, const u8 *mac_addr, void *cookie,
2456 void (*callback)(void *cookie,
2457 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002458{
2459 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002460 struct brcmf_if *ifp = netdev_priv(ndev);
2461 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002462 struct brcmf_cfg80211_security *sec;
2463 s32 wsec;
2464 s32 err = 0;
2465
Arend van Sprield96b8012012-12-05 15:26:02 +01002466 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002467 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002468 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002469 return -EIO;
2470
2471 memset(&params, 0, sizeof(params));
2472
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002473 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002474 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002475 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002476 /* Ignore this error, may happen during DISASSOC */
2477 err = -EAGAIN;
2478 goto done;
2479 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002480 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002481 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002482 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2483 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002484 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002485 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2486 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002487 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002489 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002491 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002492 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002493 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002494 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002495 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002496 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497 err = -EINVAL;
2498 goto done;
2499 }
2500 callback(cookie, &params);
2501
2502done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002503 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002504 return err;
2505}
2506
2507static s32
2508brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002509 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002510{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002511 struct brcmf_if *ifp = netdev_priv(ndev);
2512
2513 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2514
2515 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2516 return 0;
2517
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002518 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002519
2520 return -EOPNOTSUPP;
2521}
2522
Hante Meuleman118eb302014-12-21 12:43:49 +01002523static void
2524brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2525{
2526 s32 err;
2527 u8 key_idx;
2528 struct brcmf_wsec_key *key;
2529 s32 wsec;
2530
2531 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2532 key = &ifp->vif->profile.key[key_idx];
2533 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2534 (key->algo == CRYPTO_ALGO_WEP128))
2535 break;
2536 }
2537 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2538 return;
2539
2540 err = send_key_to_dongle(ifp, key);
2541 if (err) {
2542 brcmf_err("Setting WEP key failed (%d)\n", err);
2543 return;
2544 }
2545 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2546 if (err) {
2547 brcmf_err("get wsec error (%d)\n", err);
2548 return;
2549 }
2550 wsec |= WEP_ENABLED;
2551 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2552 if (err)
2553 brcmf_err("set wsec error (%d)\n", err);
2554}
2555
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002556static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2557{
2558 struct nl80211_sta_flag_update *sfu;
2559
2560 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2561 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2562 sfu = &si->sta_flags;
2563 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2564 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2565 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2566 BIT(NL80211_STA_FLAG_AUTHORIZED);
2567 if (fw_sta_flags & BRCMF_STA_WME)
2568 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2569 if (fw_sta_flags & BRCMF_STA_AUTHE)
2570 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2571 if (fw_sta_flags & BRCMF_STA_ASSOC)
2572 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2573 if (fw_sta_flags & BRCMF_STA_AUTHO)
2574 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2575}
2576
2577static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2578{
2579 struct {
2580 __le32 len;
2581 struct brcmf_bss_info_le bss_le;
2582 } *buf;
2583 u16 capability;
2584 int err;
2585
2586 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2587 if (!buf)
2588 return;
2589
2590 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2591 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2592 WL_BSS_INFO_MAX);
2593 if (err) {
2594 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002595 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002596 }
2597 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2598 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2599 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2600 capability = le16_to_cpu(buf->bss_le.capability);
2601 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2602 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2603 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2604 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2605 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2606 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002607
2608out_kfree:
2609 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002610}
2611
Arend van Spriel5b435de2011-10-05 13:19:03 +02002612static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002613brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2614 struct station_info *sinfo)
2615{
2616 struct brcmf_scb_val_le scbval;
2617 struct brcmf_pktcnt_le pktcnt;
2618 s32 err;
2619 u32 rate;
2620 u32 rssi;
2621
2622 /* Get the current tx rate */
2623 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2624 if (err < 0) {
2625 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2626 return err;
2627 }
2628 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2629 sinfo->txrate.legacy = rate * 5;
2630
2631 memset(&scbval, 0, sizeof(scbval));
2632 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2633 sizeof(scbval));
2634 if (err) {
2635 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2636 return err;
2637 }
2638 rssi = le32_to_cpu(scbval.val);
2639 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2640 sinfo->signal = rssi;
2641
2642 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2643 sizeof(pktcnt));
2644 if (err) {
2645 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2646 return err;
2647 }
2648 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2649 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2650 BIT(NL80211_STA_INFO_TX_PACKETS) |
2651 BIT(NL80211_STA_INFO_TX_FAILED);
2652 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2653 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2654 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2655 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2656
2657 return 0;
2658}
2659
2660static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002661brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002662 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002663{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002664 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002665 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002667 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002668 u32 sta_flags;
2669 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002670 s32 total_rssi;
2671 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002672 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002673 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002674
Arend van Sprield96b8012012-12-05 15:26:02 +01002675 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002676 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002677 return -EIO;
2678
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002679 if (brcmf_is_ibssmode(ifp->vif))
2680 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2681
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002682 memset(&sta_info_le, 0, sizeof(sta_info_le));
2683 memcpy(&sta_info_le, mac, ETH_ALEN);
2684 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2685 &sta_info_le,
2686 sizeof(sta_info_le));
2687 is_tdls_peer = !err;
2688 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002689 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002690 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002691 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002692 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002693 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002694 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002695 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002696 }
2697 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2698 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2699 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2700 sta_flags = le32_to_cpu(sta_info_le.flags);
2701 brcmf_convert_sta_flags(sta_flags, sinfo);
2702 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2703 if (is_tdls_peer)
2704 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2705 else
2706 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2707 if (sta_flags & BRCMF_STA_ASSOC) {
2708 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2709 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2710 brcmf_fill_bss_param(ifp, sinfo);
2711 }
2712 if (sta_flags & BRCMF_STA_SCBSTATS) {
2713 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2714 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2715 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2716 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2717 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2718 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2719 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2720 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2721 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002722 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002723 sinfo->txrate.legacy =
2724 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002725 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002726 if (sinfo->rx_packets) {
2727 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002728 sinfo->rxrate.legacy =
2729 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002730 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002731 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2732 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2733 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2734 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2735 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2736 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002737 total_rssi = 0;
2738 count_rssi = 0;
2739 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2740 if (sta_info_le.rssi[i]) {
2741 sinfo->chain_signal_avg[count_rssi] =
2742 sta_info_le.rssi[i];
2743 sinfo->chain_signal[count_rssi] =
2744 sta_info_le.rssi[i];
2745 total_rssi += sta_info_le.rssi[i];
2746 count_rssi++;
2747 }
2748 }
2749 if (count_rssi) {
2750 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2751 sinfo->chains = count_rssi;
2752
2753 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2754 total_rssi /= count_rssi;
2755 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002756 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2757 &ifp->vif->sme_state)) {
2758 memset(&scb_val, 0, sizeof(scb_val));
2759 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2760 &scb_val, sizeof(scb_val));
2761 if (err) {
2762 brcmf_err("Could not get rssi (%d)\n", err);
2763 goto done;
2764 } else {
2765 rssi = le32_to_cpu(scb_val.val);
2766 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2767 sinfo->signal = rssi;
2768 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2769 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002770 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002771 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002773 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002774 return err;
2775}
2776
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002777static int
2778brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2779 int idx, u8 *mac, struct station_info *sinfo)
2780{
2781 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2782 struct brcmf_if *ifp = netdev_priv(ndev);
2783 s32 err;
2784
2785 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2786
2787 if (idx == 0) {
2788 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2789 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2790 &cfg->assoclist,
2791 sizeof(cfg->assoclist));
2792 if (err) {
2793 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2794 err);
2795 cfg->assoclist.count = 0;
2796 return -EOPNOTSUPP;
2797 }
2798 }
2799 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2800 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2801 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2802 }
2803 return -ENOENT;
2804}
2805
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806static s32
2807brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2808 bool enabled, s32 timeout)
2809{
2810 s32 pm;
2811 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002812 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002813 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814
Arend van Sprield96b8012012-12-05 15:26:02 +01002815 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002816
2817 /*
2818 * Powersave enable/disable request is coming from the
2819 * cfg80211 even before the interface is up. In that
2820 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002821 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 * FW later while initializing the dongle
2823 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002824 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002825 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002826
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002827 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002828 goto done;
2829 }
2830
2831 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002832 /* Do not enable the power save after assoc if it is a p2p interface */
2833 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2834 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2835 pm = PM_OFF;
2836 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002837 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002838
Arend van Sprielc1179032012-10-22 13:55:33 -07002839 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002840 if (err) {
2841 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002842 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002843 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002844 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845 }
2846done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002847 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848 return err;
2849}
2850
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002851static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002852 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002853{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002854 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002855 struct ieee80211_channel *notify_channel;
2856 struct cfg80211_bss *bss;
2857 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002858 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002859 u16 channel;
2860 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861 u16 notify_capability;
2862 u16 notify_interval;
2863 u8 *notify_ie;
2864 size_t notify_ielen;
2865 s32 notify_signal;
2866
2867 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002868 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002869 return 0;
2870 }
2871
Franky Lin83cf17a2013-04-11 13:28:50 +02002872 if (!bi->ctl_ch) {
2873 ch.chspec = le16_to_cpu(bi->chanspec);
2874 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002875 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002876 }
2877 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878
2879 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002880 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002882 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002883
2884 freq = ieee80211_channel_to_frequency(channel, band->band);
2885 notify_channel = ieee80211_get_channel(wiphy, freq);
2886
Arend van Spriel5b435de2011-10-05 13:19:03 +02002887 notify_capability = le16_to_cpu(bi->capability);
2888 notify_interval = le16_to_cpu(bi->beacon_period);
2889 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2890 notify_ielen = le32_to_cpu(bi->ie_length);
2891 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2892
Arend van Spriel16886732012-12-05 15:26:04 +01002893 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2894 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2895 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2896 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2897 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002899 bss = cfg80211_inform_bss(wiphy, notify_channel,
2900 CFG80211_BSS_FTYPE_UNKNOWN,
2901 (const u8 *)bi->BSSID,
2902 0, notify_capability,
2903 notify_interval, notify_ie,
2904 notify_ielen, notify_signal,
2905 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002906
Franky Line78946e2011-11-10 20:30:34 +01002907 if (!bss)
2908 return -ENOMEM;
2909
Johannes Berg5b112d32013-02-01 01:49:58 +01002910 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002911
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002912 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913}
2914
Roland Vossen6f09be02011-10-18 14:03:02 +02002915static struct brcmf_bss_info_le *
2916next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2917{
2918 if (bss == NULL)
2919 return list->bss_info_le;
2920 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2921 le32_to_cpu(bss->length));
2922}
2923
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002924static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002925{
2926 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002927 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928 s32 err = 0;
2929 int i;
2930
Hante Meulemanef8596e2014-09-30 10:23:13 +02002931 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002932 if (bss_list->count != 0 &&
2933 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002934 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2935 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002936 return -EOPNOTSUPP;
2937 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002938 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002939 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002940 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002941 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002942 if (err)
2943 break;
2944 }
2945 return err;
2946}
2947
Hante Meulemanb0a79082015-12-10 13:43:07 +01002948static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2949 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002950{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002951 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002952 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002953 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002954 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002955 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002956 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002957 u8 *buf = NULL;
2958 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002959 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002960 u16 notify_capability;
2961 u16 notify_interval;
2962 u8 *notify_ie;
2963 size_t notify_ielen;
2964 s32 notify_signal;
2965
Arend van Sprield96b8012012-12-05 15:26:02 +01002966 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002967
2968 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2969 if (buf == NULL) {
2970 err = -ENOMEM;
2971 goto CleanUp;
2972 }
2973
2974 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2975
Arend van Sprielac24be62012-10-22 10:36:23 -07002976 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2977 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002978 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002979 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002980 goto CleanUp;
2981 }
2982
Roland Vossend34bf642011-10-18 14:03:01 +02002983 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002984
Franky Lin83cf17a2013-04-11 13:28:50 +02002985 ch.chspec = le16_to_cpu(bi->chanspec);
2986 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002987
Franky Lin83cf17a2013-04-11 13:28:50 +02002988 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002989 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002990 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002991 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002992
Rafał Miłecki4712d882016-05-20 13:38:57 +02002993 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002994 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002995 notify_channel = ieee80211_get_channel(wiphy, freq);
2996
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997 notify_capability = le16_to_cpu(bi->capability);
2998 notify_interval = le16_to_cpu(bi->beacon_period);
2999 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
3000 notify_ielen = le32_to_cpu(bi->ie_length);
3001 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
3002
Rafał Miłecki4712d882016-05-20 13:38:57 +02003003 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01003004 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
3005 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
3006 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003007
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02003008 bss = cfg80211_inform_bss(wiphy, notify_channel,
3009 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
3010 notify_capability, notify_interval,
3011 notify_ie, notify_ielen, notify_signal,
3012 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003013
Franky Line78946e2011-11-10 20:30:34 +01003014 if (!bss) {
3015 err = -ENOMEM;
3016 goto CleanUp;
3017 }
3018
Johannes Berg5b112d32013-02-01 01:49:58 +01003019 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01003020
Arend van Spriel5b435de2011-10-05 13:19:03 +02003021CleanUp:
3022
3023 kfree(buf);
3024
Arend van Sprield96b8012012-12-05 15:26:02 +01003025 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003026
3027 return err;
3028}
3029
Hante Meuleman89286dc2013-02-08 15:53:46 +01003030static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
3031 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02003032{
Roland Vossend34bf642011-10-18 14:03:01 +02003033 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01003034 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003035 u16 beacon_interval;
3036 u8 dtim_period;
3037 size_t ie_len;
3038 u8 *ie;
3039 s32 err = 0;
3040
Arend van Sprield96b8012012-12-05 15:26:02 +01003041 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003042 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003043 return err;
3044
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003045 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07003046 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003047 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003048 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003049 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003050 goto update_bss_info_out;
3051 }
3052
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003053 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
3054 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003055 if (err)
3056 goto update_bss_info_out;
3057
3058 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
3059 ie_len = le32_to_cpu(bi->ie_length);
3060 beacon_interval = le16_to_cpu(bi->beacon_period);
3061
Alwin Beukersf8e4b412011-10-12 20:51:28 +02003062 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003063 if (tim)
3064 dtim_period = tim->data[1];
3065 else {
3066 /*
3067 * active scan was done so we could not get dtim
3068 * information out of probe response.
3069 * so we speficially query dtim information to dongle.
3070 */
3071 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07003072 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003073 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003074 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003075 goto update_bss_info_out;
3076 }
3077 dtim_period = (u8)var;
3078 }
3079
Arend van Spriel5b435de2011-10-05 13:19:03 +02003080update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003081 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003082 return err;
3083}
3084
Hante Meuleman18e2f612013-02-08 15:53:49 +01003085void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003086{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003087 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003088
Arend van Sprielc1179032012-10-22 13:55:33 -07003089 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003090 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003091 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003092 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003093 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003094 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3095 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003096}
3097
Hante Meulemane756af52012-09-11 21:18:52 +02003098static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3099{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003100 struct brcmf_cfg80211_info *cfg =
3101 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003102 escan_timeout_work);
3103
Hante Meulemanef8596e2014-09-30 10:23:13 +02003104 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003105 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003106}
3107
3108static void brcmf_escan_timeout(unsigned long data)
3109{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003110 struct brcmf_cfg80211_info *cfg =
3111 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003112
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003113 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003115 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003116 }
3117}
3118
3119static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003120brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3121 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003122 struct brcmf_bss_info_le *bss_info_le)
3123{
Franky Lin83cf17a2013-04-11 13:28:50 +02003124 struct brcmu_chan ch_bss, ch_bss_info_le;
3125
3126 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3127 cfg->d11inf.decchspec(&ch_bss);
3128 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3129 cfg->d11inf.decchspec(&ch_bss_info_le);
3130
Hante Meulemane756af52012-09-11 21:18:52 +02003131 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003132 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003133 bss_info_le->SSID_len == bss->SSID_len &&
3134 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003135 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3136 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003137 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3138 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3139
Hante Meulemane756af52012-09-11 21:18:52 +02003140 /* preserve max RSSI if the measurements are
3141 * both on-channel or both off-channel
3142 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003143 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003144 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003145 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3146 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003147 /* preserve the on-channel rssi measurement
3148 * if the new measurement is off channel
3149 */
3150 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003151 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003152 }
3153 return 1;
3154 }
3155 return 0;
3156}
3157
3158static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003159brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003160 const struct brcmf_event_msg *e, void *data)
3161{
Arend van Spriel19937322012-11-05 16:22:32 -08003162 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003163 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003164 struct brcmf_escan_result_le *escan_result_le;
3165 struct brcmf_bss_info_le *bss_info_le;
3166 struct brcmf_bss_info_le *bss = NULL;
3167 u32 bi_length;
3168 struct brcmf_scan_results *list;
3169 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003170 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003171
Arend van Spriel5c36b992012-11-14 18:46:05 -08003172 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003173
Hans de Goedeb9472a22017-03-08 14:50:17 +01003174 if (status == BRCMF_E_STATUS_ABORT)
3175 goto exit;
3176
Arend van Spriela0f472a2013-04-05 10:57:49 +02003177 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003178 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003179 return -EPERM;
3180 }
3181
3182 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003183 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003184 escan_result_le = (struct brcmf_escan_result_le *) data;
3185 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003186 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003187 goto exit;
3188 }
Hante Meulemane756af52012-09-11 21:18:52 +02003189 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003190 brcmf_err("Invalid bss_count %d: ignoring\n",
3191 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003192 goto exit;
3193 }
3194 bss_info_le = &escan_result_le->bss_info_le;
3195
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003196 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3197 goto exit;
3198
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003199 if (!cfg->int_escan_map && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003200 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3201 goto exit;
3202 }
3203
Hante Meulemane756af52012-09-11 21:18:52 +02003204 bi_length = le32_to_cpu(bss_info_le->length);
3205 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3206 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003207 brcmf_err("Invalid bss_info length %d: ignoring\n",
3208 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003209 goto exit;
3210 }
3211
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003212 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003213 BIT(NL80211_IFTYPE_ADHOC))) {
3214 if (le16_to_cpu(bss_info_le->capability) &
3215 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003216 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003217 goto exit;
3218 }
3219 }
3220
3221 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003222 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003223 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003224 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003225 goto exit;
3226 }
3227
3228 for (i = 0; i < list->count; i++) {
3229 bss = bss ? (struct brcmf_bss_info_le *)
3230 ((unsigned char *)bss +
3231 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003232 if (brcmf_compare_update_same_bss(cfg, bss,
3233 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003234 goto exit;
3235 }
Hante Meulemand5367332016-02-17 11:26:51 +01003236 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3237 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003238 list->version = le32_to_cpu(bss_info_le->version);
3239 list->buflen += bi_length;
3240 list->count++;
3241 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003242 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003243 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3244 goto exit;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003245 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003246 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003247 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003248 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003249 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003250 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3251 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003252 }
3253exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003254 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003255}
3256
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003257static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003258{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003259 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3260 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003261 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3262 /* Init scan_timeout timer */
3263 init_timer(&cfg->escan_timeout);
3264 cfg->escan_timeout.data = (unsigned long) cfg;
3265 cfg->escan_timeout.function = brcmf_escan_timeout;
3266 INIT_WORK(&cfg->escan_timeout_work,
3267 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003268}
3269
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003270static struct cfg80211_scan_request *
3271brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3272 struct cfg80211_scan_request *req;
3273 size_t req_size;
3274
3275 req_size = sizeof(*req) +
3276 n_netinfo * sizeof(req->channels[0]) +
3277 n_netinfo * sizeof(*req->ssids);
3278
3279 req = kzalloc(req_size, GFP_KERNEL);
3280 if (req) {
3281 req->wiphy = wiphy;
3282 req->ssids = (void *)(&req->channels[0]) +
3283 n_netinfo * sizeof(req->channels[0]);
3284 }
3285 return req;
3286}
3287
3288static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3289 u8 *ssid, u8 ssid_len, u8 channel)
3290{
3291 struct ieee80211_channel *chan;
3292 enum nl80211_band band;
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003293 int freq, i;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003294
3295 if (channel <= CH_MAX_2G_CHANNEL)
3296 band = NL80211_BAND_2GHZ;
3297 else
3298 band = NL80211_BAND_5GHZ;
3299
3300 freq = ieee80211_channel_to_frequency(channel, band);
3301 if (!freq)
3302 return -EINVAL;
3303
3304 chan = ieee80211_get_channel(req->wiphy, freq);
3305 if (!chan)
3306 return -EINVAL;
3307
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003308 for (i = 0; i < req->n_channels; i++) {
3309 if (req->channels[i] == chan)
3310 break;
3311 }
3312 if (i == req->n_channels)
3313 req->channels[req->n_channels++] = chan;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003314
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003315 for (i = 0; i < req->n_ssids; i++) {
3316 if (req->ssids[i].ssid_len == ssid_len &&
3317 !memcmp(req->ssids[i].ssid, ssid, ssid_len))
3318 break;
3319 }
3320 if (i == req->n_ssids) {
3321 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3322 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3323 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003324 return 0;
3325}
3326
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003327static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003328 struct cfg80211_scan_request *request)
3329{
3330 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3331 int err;
3332
3333 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003334 if (cfg->int_escan_map)
3335 brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
3336 cfg->int_escan_map);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003337 /* Abort any on-going scan */
3338 brcmf_abort_scanning(cfg);
3339 }
3340
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003341 brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003342 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3343 cfg->escan_info.run = brcmf_run_escan;
3344 err = brcmf_do_escan(ifp, request);
3345 if (err) {
3346 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3347 return err;
3348 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003349 cfg->int_escan_map = fwmap;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003350 return 0;
3351}
3352
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003353static struct brcmf_pno_net_info_le *
3354brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3355{
3356 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3357 struct brcmf_pno_net_info_le *netinfo;
3358
3359 switch (pfn_v1->version) {
3360 default:
3361 WARN_ON(1);
3362 /* fall-thru */
3363 case cpu_to_le32(1):
3364 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3365 break;
3366 case cpu_to_le32(2):
3367 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3368 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3369 break;
3370 }
3371
3372 return netinfo;
3373}
3374
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003375/* PFN result doesn't have all the info which are required by the supplicant
3376 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3377 * via wl_inform_single_bss in the required format. Escan does require the
3378 * scan request in the form of cfg80211_scan_request. For timebeing, create
3379 * cfg80211_scan_request one out of the received PNO event.
3380 */
3381static s32
3382brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3383 const struct brcmf_event_msg *e, void *data)
3384{
3385 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3386 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3387 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003388 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003389 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003390 struct brcmf_pno_scanresults_le *pfn_result;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003391 u32 bucket_map;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003392 u32 result_count;
3393 u32 status;
Arend Van Spriel4835f372017-04-06 13:14:40 +01003394 u32 datalen;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003395
3396 brcmf_dbg(SCAN, "Enter\n");
3397
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003398 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3399 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3400 return 0;
3401 }
3402
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003403 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3404 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3405 return 0;
3406 }
3407
3408 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3409 result_count = le32_to_cpu(pfn_result->count);
3410 status = le32_to_cpu(pfn_result->status);
3411
3412 /* PFN event is limited to fit 512 bytes so we may get
3413 * multiple NET_FOUND events. For now place a warning here.
3414 */
3415 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3416 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003417 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003418 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3419 goto out_err;
3420 }
Arend Van Spriel4835f372017-04-06 13:14:40 +01003421
3422 netinfo_start = brcmf_get_netinfo_array(pfn_result);
3423 datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
3424 if (datalen < result_count * sizeof(*netinfo)) {
3425 brcmf_err("insufficient event data\n");
3426 goto out_err;
3427 }
3428
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003429 request = brcmf_alloc_internal_escan_request(wiphy,
3430 result_count);
3431 if (!request) {
3432 err = -ENOMEM;
3433 goto out_err;
3434 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003435
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003436 bucket_map = 0;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003437 for (i = 0; i < result_count; i++) {
3438 netinfo = &netinfo_start[i];
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003439
Arend Van Spriel4835f372017-04-06 13:14:40 +01003440 if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
3441 netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003442 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3443 netinfo->SSID, netinfo->channel);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003444 bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003445 err = brcmf_internal_escan_add_info(request,
3446 netinfo->SSID,
3447 netinfo->SSID_len,
3448 netinfo->channel);
3449 if (err)
3450 goto out_err;
3451 }
3452
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003453 if (!bucket_map)
3454 goto free_req;
3455
3456 err = brcmf_start_internal_escan(ifp, bucket_map, request);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003457 if (!err)
3458 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003459
3460out_err:
Arend Van Sprielb34939b2017-04-28 13:40:28 +01003461 cfg80211_sched_scan_stopped(wiphy, 0);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003462free_req:
3463 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003464 return err;
3465}
3466
3467static int
3468brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3469 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003470 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003471{
3472 struct brcmf_if *ifp = netdev_priv(ndev);
3473 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003474
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003475 brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003476 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003477
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003478 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003479 brcmf_err("Scanning suppressed: status=%lu\n",
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003480 cfg->scan_status);
3481 return -EAGAIN;
3482 }
3483
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003484 if (req->n_match_sets <= 0) {
3485 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3486 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003487 return -EINVAL;
3488 }
3489
Arend Van Spriel3e486112016-11-23 10:25:27 +00003490 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003491}
3492
3493static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003494 struct net_device *ndev, u64 reqid)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003495{
3496 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003497 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003498
3499 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003500 brcmf_pno_stop_sched_scan(ifp, reqid);
3501 if (cfg->int_escan_map)
Arend Van Sprielac551362016-11-23 10:25:22 +00003502 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003503 return 0;
3504}
3505
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003506static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003507{
3508 if (ms < 1000 / HZ) {
3509 cond_resched();
3510 mdelay(ms);
3511 } else {
3512 msleep(ms);
3513 }
3514}
3515
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003516static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3517 u8 *pattern, u32 patternsize, u8 *mask,
3518 u32 packet_offset)
3519{
3520 struct brcmf_fil_wowl_pattern_le *filter;
3521 u32 masksize;
3522 u32 patternoffset;
3523 u8 *buf;
3524 u32 bufsize;
3525 s32 ret;
3526
3527 masksize = (patternsize + 7) / 8;
3528 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3529
3530 bufsize = sizeof(*filter) + patternsize + masksize;
3531 buf = kzalloc(bufsize, GFP_KERNEL);
3532 if (!buf)
3533 return -ENOMEM;
3534 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3535
3536 memcpy(filter->cmd, cmd, 4);
3537 filter->masksize = cpu_to_le32(masksize);
3538 filter->offset = cpu_to_le32(packet_offset);
3539 filter->patternoffset = cpu_to_le32(patternoffset);
3540 filter->patternsize = cpu_to_le32(patternsize);
3541 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3542
3543 if ((mask) && (masksize))
3544 memcpy(buf + sizeof(*filter), mask, masksize);
3545 if ((pattern) && (patternsize))
3546 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3547
3548 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3549
3550 kfree(buf);
3551 return ret;
3552}
3553
Hante Meuleman3021ad92016-01-05 11:05:45 +01003554static s32
3555brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3556 void *data)
3557{
3558 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3559 struct brcmf_pno_scanresults_le *pfn_result;
3560 struct brcmf_pno_net_info_le *netinfo;
3561
3562 brcmf_dbg(SCAN, "Enter\n");
3563
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003564 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3565 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3566 return 0;
3567 }
3568
Hante Meuleman3021ad92016-01-05 11:05:45 +01003569 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3570
3571 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3572 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3573 return 0;
3574 }
3575
3576 if (le32_to_cpu(pfn_result->count) < 1) {
3577 brcmf_err("Invalid result count, expected 1 (%d)\n",
3578 le32_to_cpu(pfn_result->count));
3579 return -EINVAL;
3580 }
3581
Arend Van Sprield29afe92017-01-27 12:27:46 +00003582 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003583 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3584 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3585 cfg->wowl.nd->n_channels = 1;
3586 cfg->wowl.nd->channels[0] =
3587 ieee80211_channel_to_frequency(netinfo->channel,
3588 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3589 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3590 cfg->wowl.nd_info->n_matches = 1;
3591 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3592
3593 /* Inform (the resume task) that the net detect information was recvd */
3594 cfg->wowl.nd_data_completed = true;
3595 wake_up(&cfg->wowl.nd_data_wait);
3596
3597 return 0;
3598}
3599
Hante Meulemanaeb64222015-10-29 20:33:19 +01003600#ifdef CONFIG_PM
3601
3602static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3603{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003604 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003605 struct brcmf_wowl_wakeind_le wake_ind_le;
3606 struct cfg80211_wowlan_wakeup wakeup_data;
3607 struct cfg80211_wowlan_wakeup *wakeup;
3608 u32 wakeind;
3609 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003610 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003611
3612 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3613 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003614 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003615 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3616 return;
3617 }
3618
3619 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3620 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003621 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3622 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003623 wakeup = &wakeup_data;
3624 memset(&wakeup_data, 0, sizeof(wakeup_data));
3625 wakeup_data.pattern_idx = -1;
3626
3627 if (wakeind & BRCMF_WOWL_MAGIC) {
3628 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3629 wakeup_data.magic_pkt = true;
3630 }
3631 if (wakeind & BRCMF_WOWL_DIS) {
3632 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3633 wakeup_data.disconnect = true;
3634 }
3635 if (wakeind & BRCMF_WOWL_BCN) {
3636 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3637 wakeup_data.disconnect = true;
3638 }
3639 if (wakeind & BRCMF_WOWL_RETR) {
3640 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3641 wakeup_data.disconnect = true;
3642 }
3643 if (wakeind & BRCMF_WOWL_NET) {
3644 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3645 /* For now always map to pattern 0, no API to get
3646 * correct information available at the moment.
3647 */
3648 wakeup_data.pattern_idx = 0;
3649 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003650 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3651 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3652 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3653 cfg->wowl.nd_data_completed,
3654 BRCMF_ND_INFO_TIMEOUT);
3655 if (!timeout)
3656 brcmf_err("No result for wowl net detect\n");
3657 else
3658 wakeup_data.net_detect = cfg->wowl.nd_info;
3659 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003660 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3661 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3662 wakeup_data.gtk_rekey_failure = true;
3663 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003664 } else {
3665 wakeup = NULL;
3666 }
3667 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3668}
3669
3670#else
3671
3672static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3673{
3674}
3675
3676#endif /* CONFIG_PM */
3677
Arend van Spriel5b435de2011-10-05 13:19:03 +02003678static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3679{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003680 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3681 struct net_device *ndev = cfg_to_ndev(cfg);
3682 struct brcmf_if *ifp = netdev_priv(ndev);
3683
Arend van Sprield96b8012012-12-05 15:26:02 +01003684 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003685
Hante Meuleman3021ad92016-01-05 11:05:45 +01003686 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003687 brcmf_report_wowl_wakeind(wiphy, ifp);
3688 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3689 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003690 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3691 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003692 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003693 cfg->wowl.pre_pmmode);
3694 cfg->wowl.active = false;
3695 if (cfg->wowl.nd_enabled) {
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003696 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003697 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3698 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3699 brcmf_notify_sched_scan_results);
3700 cfg->wowl.nd_enabled = false;
3701 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003702 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003703 return 0;
3704}
3705
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003706static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3707 struct brcmf_if *ifp,
3708 struct cfg80211_wowlan *wowl)
3709{
3710 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003711 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003712 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003713
3714 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3715
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003716 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3717 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003718 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003719 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3720
3721 wowl_config = 0;
3722 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003723 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003724 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003725 wowl_config |= BRCMF_WOWL_MAGIC;
3726 if ((wowl->patterns) && (wowl->n_patterns)) {
3727 wowl_config |= BRCMF_WOWL_NET;
3728 for (i = 0; i < wowl->n_patterns; i++) {
3729 brcmf_config_wowl_pattern(ifp, "add",
3730 (u8 *)wowl->patterns[i].pattern,
3731 wowl->patterns[i].pattern_len,
3732 (u8 *)wowl->patterns[i].mask,
3733 wowl->patterns[i].pkt_offset);
3734 }
3735 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003736 if (wowl->nd_config) {
3737 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3738 wowl->nd_config);
3739 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3740
3741 cfg->wowl.nd_data_completed = false;
3742 cfg->wowl.nd_enabled = true;
3743 /* Now reroute the event for PFN to the wowl function. */
3744 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3745 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3746 brcmf_wowl_nd_results);
3747 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003748 if (wowl->gtk_rekey_failure)
3749 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003750 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3751 wowl_config |= BRCMF_WOWL_UNASSOC;
3752
Hante Meulemana7ed7822016-09-19 12:09:58 +01003753 memcpy(&wowl_wakeind, "clear", 6);
3754 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3755 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003756 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3757 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3758 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003759 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003760}
3761
Arend van Spriel5b435de2011-10-05 13:19:03 +02003762static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003763 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003765 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3766 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003767 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003768 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769
Arend van Sprield96b8012012-12-05 15:26:02 +01003770 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003771
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003772 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003773 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003774 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003775 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003776 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777
Hante Meuleman3021ad92016-01-05 11:05:45 +01003778 /* Stop scheduled scan */
3779 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003780 brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003781
Arend van Spriel7d641072012-10-22 13:55:39 -07003782 /* end any scanning */
3783 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003784 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003785
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003786 if (wowl == NULL) {
3787 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3788 list_for_each_entry(vif, &cfg->vif_list, list) {
3789 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3790 continue;
3791 /* While going to suspend if associated with AP
3792 * disassociate from AP to save power while system is
3793 * in suspended state
3794 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003795 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003796 /* Make sure WPA_Supplicant receives all the event
3797 * generated due to DISASSOC call to the fw to keep
3798 * the state fw and WPA_Supplicant state consistent
3799 */
3800 brcmf_delay(500);
3801 }
3802 /* Configure MPC */
3803 brcmf_set_mpc(ifp, 1);
3804
3805 } else {
3806 /* Configure WOWL paramaters */
3807 brcmf_configure_wowl(cfg, ifp, wowl);
3808 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003809
Arend van Spriel7d641072012-10-22 13:55:39 -07003810exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003811 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003812 /* clear any scanning activity */
3813 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003814 return 0;
3815}
3816
3817static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003818brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003819{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003820 struct brcmf_pmk_list_le *pmk_list;
3821 int i;
3822 u32 npmk;
3823 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003824
Hante Meuleman6c404f32015-12-10 13:43:03 +01003825 pmk_list = &cfg->pmk_list;
3826 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003827
Hante Meuleman6c404f32015-12-10 13:43:03 +01003828 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3829 for (i = 0; i < npmk; i++)
3830 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003831
Hante Meuleman6c404f32015-12-10 13:43:03 +01003832 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3833 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003834
3835 return err;
3836}
3837
3838static s32
3839brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3840 struct cfg80211_pmksa *pmksa)
3841{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003842 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003843 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003844 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3845 s32 err;
3846 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003847
Arend van Sprield96b8012012-12-05 15:26:02 +01003848 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003849 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003850 return -EIO;
3851
Hante Meuleman6c404f32015-12-10 13:43:03 +01003852 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3853 for (i = 0; i < npmk; i++)
3854 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003855 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003856 if (i < BRCMF_MAXPMKID) {
3857 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3858 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3859 if (i == npmk) {
3860 npmk++;
3861 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003862 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003863 } else {
3864 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3865 return -EINVAL;
3866 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003867
Hante Meuleman6c404f32015-12-10 13:43:03 +01003868 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3869 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3870 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3871 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3872 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003873
Hante Meuleman6c404f32015-12-10 13:43:03 +01003874 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003875
Arend van Sprield96b8012012-12-05 15:26:02 +01003876 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003877 return err;
3878}
3879
3880static s32
3881brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003882 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003883{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003884 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003885 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003886 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3887 s32 err;
3888 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003889
Arend van Sprield96b8012012-12-05 15:26:02 +01003890 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003891 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003892 return -EIO;
3893
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003894 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003895
Hante Meuleman6c404f32015-12-10 13:43:03 +01003896 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3897 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003898 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003899 break;
3900
Hante Meuleman6c404f32015-12-10 13:43:03 +01003901 if ((npmk > 0) && (i < npmk)) {
3902 for (; i < (npmk - 1); i++) {
3903 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3904 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003905 WLAN_PMKID_LEN);
3906 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003907 memset(&pmk[i], 0, sizeof(*pmk));
3908 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3909 } else {
3910 brcmf_err("Cache entry not found\n");
3911 return -EINVAL;
3912 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003913
Hante Meuleman6c404f32015-12-10 13:43:03 +01003914 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003915
Arend van Sprield96b8012012-12-05 15:26:02 +01003916 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003917 return err;
3918
3919}
3920
3921static s32
3922brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3923{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003924 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003925 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003926 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003927
Arend van Sprield96b8012012-12-05 15:26:02 +01003928 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003929 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003930 return -EIO;
3931
Hante Meuleman6c404f32015-12-10 13:43:03 +01003932 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3933 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003934
Arend van Sprield96b8012012-12-05 15:26:02 +01003935 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003936 return err;
3937
3938}
3939
Hante Meuleman1f170112013-02-06 18:40:38 +01003940static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003941{
3942 s32 err;
Wright Fengfdfb0f92017-08-03 17:37:57 +08003943 s32 wpa_val;
Hante Meuleman1a873342012-09-27 14:17:54 +02003944
3945 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003946 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003947 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003948 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003949 return err;
3950 }
3951 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003952 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003953 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003954 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003955 return err;
3956 }
3957 /* set upper-layer auth */
Wright Fengfdfb0f92017-08-03 17:37:57 +08003958 if (brcmf_is_ibssmode(ifp->vif))
3959 wpa_val = WPA_AUTH_NONE;
3960 else
3961 wpa_val = WPA_AUTH_DISABLED;
3962 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val);
Hante Meuleman1a873342012-09-27 14:17:54 +02003963 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003964 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003965 return err;
3966 }
3967
3968 return 0;
3969}
3970
3971static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3972{
3973 if (is_rsn_ie)
3974 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3975
3976 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3977}
3978
3979static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003980brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003981 const struct brcmf_vs_tlv *wpa_ie,
3982 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003983{
3984 u32 auth = 0; /* d11 open authentication */
3985 u16 count;
3986 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003987 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 u32 i;
3989 u32 wsec;
3990 u32 pval = 0;
3991 u32 gval = 0;
3992 u32 wpa_auth = 0;
3993 u32 offset;
3994 u8 *data;
3995 u16 rsn_cap;
3996 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003997 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003998
Arend van Sprield96b8012012-12-05 15:26:02 +01003999 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004000 if (wpa_ie == NULL)
4001 goto exit;
4002
4003 len = wpa_ie->len + TLV_HDR_LEN;
4004 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004005 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 if (!is_rsn_ie)
4007 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004008 else
4009 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004010
4011 /* check for multicast cipher suite */
4012 if (offset + WPA_IE_MIN_OUI_LEN > len) {
4013 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004014 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004015 goto exit;
4016 }
4017
4018 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4019 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004020 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004021 goto exit;
4022 }
4023 offset += TLV_OUI_LEN;
4024
4025 /* pick up multicast cipher */
4026 switch (data[offset]) {
4027 case WPA_CIPHER_NONE:
4028 gval = 0;
4029 break;
4030 case WPA_CIPHER_WEP_40:
4031 case WPA_CIPHER_WEP_104:
4032 gval = WEP_ENABLED;
4033 break;
4034 case WPA_CIPHER_TKIP:
4035 gval = TKIP_ENABLED;
4036 break;
4037 case WPA_CIPHER_AES_CCM:
4038 gval = AES_ENABLED;
4039 break;
4040 default:
4041 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004042 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004043 goto exit;
4044 }
4045
4046 offset++;
4047 /* walk thru unicast cipher list and pick up what we recognize */
4048 count = data[offset] + (data[offset + 1] << 8);
4049 offset += WPA_IE_SUITE_COUNT_LEN;
4050 /* Check for unicast suite(s) */
4051 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4052 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004053 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004054 goto exit;
4055 }
4056 for (i = 0; i < count; i++) {
4057 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4058 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004059 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004060 goto exit;
4061 }
4062 offset += TLV_OUI_LEN;
4063 switch (data[offset]) {
4064 case WPA_CIPHER_NONE:
4065 break;
4066 case WPA_CIPHER_WEP_40:
4067 case WPA_CIPHER_WEP_104:
4068 pval |= WEP_ENABLED;
4069 break;
4070 case WPA_CIPHER_TKIP:
4071 pval |= TKIP_ENABLED;
4072 break;
4073 case WPA_CIPHER_AES_CCM:
4074 pval |= AES_ENABLED;
4075 break;
4076 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004077 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004078 }
4079 offset++;
4080 }
4081 /* walk thru auth management suite list and pick up what we recognize */
4082 count = data[offset] + (data[offset + 1] << 8);
4083 offset += WPA_IE_SUITE_COUNT_LEN;
4084 /* Check for auth key management suite(s) */
4085 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4086 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004087 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004088 goto exit;
4089 }
4090 for (i = 0; i < count; i++) {
4091 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4092 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004093 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004094 goto exit;
4095 }
4096 offset += TLV_OUI_LEN;
4097 switch (data[offset]) {
4098 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004099 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004100 wpa_auth |= WPA_AUTH_NONE;
4101 break;
4102 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004103 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004104 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4105 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4106 break;
4107 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004108 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004109 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4110 (wpa_auth |= WPA_AUTH_PSK);
4111 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004112 case RSN_AKM_SHA256_PSK:
4113 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4114 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4115 break;
4116 case RSN_AKM_SHA256_1X:
4117 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4118 wpa_auth |= WPA2_AUTH_1X_SHA256;
4119 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004120 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004121 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004122 }
4123 offset++;
4124 }
4125
Hante Meuleman240d61a2016-02-17 11:27:10 +01004126 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004127 if (is_rsn_ie) {
4128 wme_bss_disable = 1;
4129 if ((offset + RSN_CAP_LEN) <= len) {
4130 rsn_cap = data[offset] + (data[offset + 1] << 8);
4131 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4132 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004133 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4134 brcmf_dbg(TRACE, "MFP Required\n");
4135 mfp = BRCMF_MFP_REQUIRED;
4136 /* Firmware only supports mfp required in
4137 * combination with WPA2_AUTH_PSK_SHA256 or
4138 * WPA2_AUTH_1X_SHA256.
4139 */
4140 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4141 WPA2_AUTH_1X_SHA256))) {
4142 err = -EINVAL;
4143 goto exit;
4144 }
4145 /* Firmware has requirement that WPA2_AUTH_PSK/
4146 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4147 * is to be included in the rsn ie.
4148 */
4149 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4150 wpa_auth |= WPA2_AUTH_PSK;
4151 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4152 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4153 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4154 brcmf_dbg(TRACE, "MFP Capable\n");
4155 mfp = BRCMF_MFP_CAPABLE;
4156 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004157 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004158 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004159 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004160 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004161 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004162 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004163 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004164 goto exit;
4165 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004166
4167 /* Skip PMKID cnt as it is know to be 0 for AP. */
4168 offset += RSN_PMKID_COUNT_LEN;
4169
4170 /* See if there is BIP wpa suite left for MFP */
4171 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4172 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4173 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4174 &data[offset],
4175 WPA_IE_MIN_OUI_LEN);
4176 if (err < 0) {
4177 brcmf_err("bip error %d\n", err);
4178 goto exit;
4179 }
4180 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004181 }
4182 /* FOR WPS , set SES_OW_ENABLED */
4183 wsec = (pval | gval | SES_OW_ENABLED);
4184
4185 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004186 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004187 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004188 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004189 goto exit;
4190 }
4191 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004192 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004193 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004194 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004195 goto exit;
4196 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004197 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4198 * will overwrite the values set by MFP
4199 */
4200 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4201 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4202 if (err < 0) {
4203 brcmf_err("mfp error %d\n", err);
4204 goto exit;
4205 }
4206 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004207 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004208 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004209 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004210 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004211 goto exit;
4212 }
4213
4214exit:
4215 return err;
4216}
4217
4218static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004219brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004220 struct parsed_vndr_ies *vndr_ies)
4221{
Hante Meuleman1a873342012-09-27 14:17:54 +02004222 struct brcmf_vs_tlv *vndrie;
4223 struct brcmf_tlv *ie;
4224 struct parsed_vndr_ie_info *parsed_info;
4225 s32 remaining_len;
4226
4227 remaining_len = (s32)vndr_ie_len;
4228 memset(vndr_ies, 0, sizeof(*vndr_ies));
4229
4230 ie = (struct brcmf_tlv *)vndr_ie_buf;
4231 while (ie) {
4232 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4233 goto next;
4234 vndrie = (struct brcmf_vs_tlv *)ie;
4235 /* len should be bigger than OUI length + one */
4236 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004237 brcmf_err("invalid vndr ie. length is too small %d\n",
4238 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004239 goto next;
4240 }
4241 /* if wpa or wme ie, do not add ie */
4242 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4243 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4244 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004245 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004246 goto next;
4247 }
4248
4249 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4250
4251 /* save vndr ie information */
4252 parsed_info->ie_ptr = (char *)vndrie;
4253 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4254 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4255
4256 vndr_ies->count++;
4257
Arend van Sprield96b8012012-12-05 15:26:02 +01004258 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4259 parsed_info->vndrie.oui[0],
4260 parsed_info->vndrie.oui[1],
4261 parsed_info->vndrie.oui[2],
4262 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004263
Arend van Spriel9f440b72013-02-08 15:53:36 +01004264 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004265 break;
4266next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004267 remaining_len -= (ie->len + TLV_HDR_LEN);
4268 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004269 ie = NULL;
4270 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004271 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4272 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004273 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004274 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004275}
4276
4277static u32
4278brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4279{
4280
Hante Meuleman1a873342012-09-27 14:17:54 +02004281 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4282 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4283
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304284 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004285
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304286 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004287
4288 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4289
4290 return ie_len + VNDR_IE_HDR_SIZE;
4291}
4292
Arend van Spriel1332e262012-11-05 16:22:18 -08004293s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4294 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004295{
Arend van Spriel1332e262012-11-05 16:22:18 -08004296 struct brcmf_if *ifp;
4297 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004298 s32 err = 0;
4299 u8 *iovar_ie_buf;
4300 u8 *curr_ie_buf;
4301 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004302 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004303 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004304 u32 del_add_ie_buf_len = 0;
4305 u32 total_ie_buf_len = 0;
4306 u32 parsed_ie_buf_len = 0;
4307 struct parsed_vndr_ies old_vndr_ies;
4308 struct parsed_vndr_ies new_vndr_ies;
4309 struct parsed_vndr_ie_info *vndrie_info;
4310 s32 i;
4311 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004312 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004313
Arend van Spriel1332e262012-11-05 16:22:18 -08004314 if (!vif)
4315 return -ENODEV;
4316 ifp = vif->ifp;
4317 saved_ie = &vif->saved_ie;
4318
Hante Meuleman37a869e2015-10-29 20:33:17 +01004319 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4320 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004321 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4322 if (!iovar_ie_buf)
4323 return -ENOMEM;
4324 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004325 switch (pktflag) {
4326 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4327 mgmt_ie_buf = saved_ie->probe_req_ie;
4328 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4329 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4330 break;
4331 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4332 mgmt_ie_buf = saved_ie->probe_res_ie;
4333 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4334 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4335 break;
4336 case BRCMF_VNDR_IE_BEACON_FLAG:
4337 mgmt_ie_buf = saved_ie->beacon_ie;
4338 mgmt_ie_len = &saved_ie->beacon_ie_len;
4339 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4340 break;
4341 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4342 mgmt_ie_buf = saved_ie->assoc_req_ie;
4343 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4344 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4345 break;
4346 default:
4347 err = -EPERM;
4348 brcmf_err("not suitable type\n");
4349 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004350 }
4351
4352 if (vndr_ie_len > mgmt_ie_buf_len) {
4353 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004354 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004355 goto exit;
4356 }
4357
4358 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4359 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4360 ptr = curr_ie_buf;
4361 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4362 for (i = 0; i < new_vndr_ies.count; i++) {
4363 vndrie_info = &new_vndr_ies.ie_info[i];
4364 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4365 vndrie_info->ie_len);
4366 parsed_ie_buf_len += vndrie_info->ie_len;
4367 }
4368 }
4369
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004370 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004371 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4372 (memcmp(mgmt_ie_buf, curr_ie_buf,
4373 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004374 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004375 goto exit;
4376 }
4377
4378 /* parse old vndr_ie */
4379 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4380
4381 /* make a command to delete old ie */
4382 for (i = 0; i < old_vndr_ies.count; i++) {
4383 vndrie_info = &old_vndr_ies.ie_info[i];
4384
Arend van Sprield96b8012012-12-05 15:26:02 +01004385 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4386 vndrie_info->vndrie.id,
4387 vndrie_info->vndrie.len,
4388 vndrie_info->vndrie.oui[0],
4389 vndrie_info->vndrie.oui[1],
4390 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004391
4392 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4393 vndrie_info->ie_ptr,
4394 vndrie_info->ie_len,
4395 "del");
4396 curr_ie_buf += del_add_ie_buf_len;
4397 total_ie_buf_len += del_add_ie_buf_len;
4398 }
4399 }
4400
4401 *mgmt_ie_len = 0;
4402 /* Add if there is any extra IE */
4403 if (mgmt_ie_buf && parsed_ie_buf_len) {
4404 ptr = mgmt_ie_buf;
4405
4406 remained_buf_len = mgmt_ie_buf_len;
4407
4408 /* make a command to add new ie */
4409 for (i = 0; i < new_vndr_ies.count; i++) {
4410 vndrie_info = &new_vndr_ies.ie_info[i];
4411
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004412 /* verify remained buf size before copy data */
4413 if (remained_buf_len < (vndrie_info->vndrie.len +
4414 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004415 brcmf_err("no space in mgmt_ie_buf: len left %d",
4416 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004417 break;
4418 }
4419 remained_buf_len -= (vndrie_info->ie_len +
4420 VNDR_IE_VSIE_OFFSET);
4421
Arend van Sprield96b8012012-12-05 15:26:02 +01004422 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4423 vndrie_info->vndrie.id,
4424 vndrie_info->vndrie.len,
4425 vndrie_info->vndrie.oui[0],
4426 vndrie_info->vndrie.oui[1],
4427 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004428
4429 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4430 vndrie_info->ie_ptr,
4431 vndrie_info->ie_len,
4432 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004433
4434 /* save the parsed IE in wl struct */
4435 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4436 vndrie_info->ie_len);
4437 *mgmt_ie_len += vndrie_info->ie_len;
4438
4439 curr_ie_buf += del_add_ie_buf_len;
4440 total_ie_buf_len += del_add_ie_buf_len;
4441 }
4442 }
4443 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004444 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004445 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004446 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004447 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004448 }
4449
4450exit:
4451 kfree(iovar_ie_buf);
4452 return err;
4453}
4454
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004455s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4456{
4457 s32 pktflags[] = {
4458 BRCMF_VNDR_IE_PRBREQ_FLAG,
4459 BRCMF_VNDR_IE_PRBRSP_FLAG,
4460 BRCMF_VNDR_IE_BEACON_FLAG
4461 };
4462 int i;
4463
4464 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4465 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4466
4467 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4468 return 0;
4469}
4470
Hante Meuleman1a873342012-09-27 14:17:54 +02004471static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004472brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4473 struct cfg80211_beacon_data *beacon)
4474{
4475 s32 err;
4476
4477 /* Set Beacon IEs to FW */
4478 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4479 beacon->tail, beacon->tail_len);
4480 if (err) {
4481 brcmf_err("Set Beacon IE Failed\n");
4482 return err;
4483 }
4484 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4485
4486 /* Set Probe Response IEs to FW */
4487 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4488 beacon->proberesp_ies,
4489 beacon->proberesp_ies_len);
4490 if (err)
4491 brcmf_err("Set Probe Resp IE Failed\n");
4492 else
4493 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4494
4495 return err;
4496}
4497
4498static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004499brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4500 struct cfg80211_ap_settings *settings)
4501{
4502 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004503 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004504 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004505 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004506 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004507 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004508 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004509 const struct brcmf_tlv *rsn_ie;
4510 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004511 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004512 enum nl80211_iftype dev_role;
4513 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004514 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004515 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004516 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004517 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004518
Arend van Spriel06c01582014-05-12 10:47:37 +02004519 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4520 settings->chandef.chan->hw_value,
4521 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004522 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004523 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4524 settings->ssid, settings->ssid_len, settings->auth_type,
4525 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004526 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004527 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004528
Arend van Spriel98027762014-12-21 12:43:53 +01004529 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004530 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4531 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004532 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004533 } else {
4534 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4535 settings->beacon.tail_len,
4536 WLAN_EID_COUNTRY);
4537 is_11d = country_ie ? 1 : 0;
4538 supports_11d = true;
4539 }
Arend van Spriel98027762014-12-21 12:43:53 +01004540
Hante Meuleman1a873342012-09-27 14:17:54 +02004541 memset(&ssid_le, 0, sizeof(ssid_le));
4542 if (settings->ssid == NULL || settings->ssid_len == 0) {
4543 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4544 ssid_ie = brcmf_parse_tlvs(
4545 (u8 *)&settings->beacon.head[ie_offset],
4546 settings->beacon.head_len - ie_offset,
4547 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004548 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004549 return -EINVAL;
4550
4551 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4552 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004553 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004554 } else {
4555 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4556 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4557 }
4558
Hante Meulemana44aa402014-12-03 21:05:33 +01004559 if (!mbss) {
4560 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004561 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004562 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004563
4564 /* find the RSN_IE */
4565 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4566 settings->beacon.tail_len, WLAN_EID_RSN);
4567
4568 /* find the WPA_IE */
4569 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4570 settings->beacon.tail_len);
4571
Hante Meuleman1a873342012-09-27 14:17:54 +02004572 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004573 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 if (wpa_ie != NULL) {
4575 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004576 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004577 if (err < 0)
4578 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004579 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004580 struct brcmf_vs_tlv *tmp_ie;
4581
4582 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4583
Hante Meuleman1a873342012-09-27 14:17:54 +02004584 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004585 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004586 if (err < 0)
4587 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004588 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004589 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004590 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004591 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004592 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004593
Rafał Miłecki8707e082016-05-27 21:07:19 +02004594 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004595 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004596 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004597 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4598 is_11d);
4599 if (err < 0) {
4600 brcmf_err("Regulatory Set Error, %d\n", err);
4601 goto exit;
4602 }
4603 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004604 if (settings->beacon_interval) {
4605 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4606 settings->beacon_interval);
4607 if (err < 0) {
4608 brcmf_err("Beacon Interval Set Error, %d\n",
4609 err);
4610 goto exit;
4611 }
4612 }
4613 if (settings->dtim_period) {
4614 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4615 settings->dtim_period);
4616 if (err < 0) {
4617 brcmf_err("DTIM Interval Set Error, %d\n", err);
4618 goto exit;
4619 }
4620 }
4621
Hante Meuleman8abffd82015-10-29 20:33:16 +01004622 if ((dev_role == NL80211_IFTYPE_AP) &&
4623 ((ifp->ifidx == 0) ||
4624 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004625 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4626 if (err < 0) {
4627 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4628 goto exit;
4629 }
4630 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4631 }
4632
4633 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004634 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004635 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004636 goto exit;
4637 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004638 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004639 /* Multiple-BSS should use same 11d configuration */
4640 err = -EINVAL;
4641 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004642 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004643
4644 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004645 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004646 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4647 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4648
Hante Meulemana0f07952013-02-08 15:53:47 +01004649 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4650 if (err < 0) {
4651 brcmf_err("setting AP mode failed %d\n", err);
4652 goto exit;
4653 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004654 if (!mbss) {
4655 /* Firmware 10.x requires setting channel after enabling
4656 * AP and before bringing interface up.
4657 */
4658 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4659 if (err < 0) {
4660 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4661 chanspec, err);
4662 goto exit;
4663 }
4664 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004665 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4666 if (err < 0) {
4667 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4668 goto exit;
4669 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004670 /* On DOWN the firmware removes the WEP keys, reconfigure
4671 * them if they were set.
4672 */
4673 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004674
4675 memset(&join_params, 0, sizeof(join_params));
4676 /* join parameters starts with ssid */
4677 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4678 /* create softap */
4679 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4680 &join_params, sizeof(join_params));
4681 if (err < 0) {
4682 brcmf_err("SET SSID error (%d)\n", err);
4683 goto exit;
4684 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004685
4686 if (settings->hidden_ssid) {
4687 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4688 if (err) {
4689 brcmf_err("closednet error (%d)\n", err);
4690 goto exit;
4691 }
4692 }
4693
Hante Meulemana0f07952013-02-08 15:53:47 +01004694 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004695 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4696 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4697 if (err < 0) {
4698 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4699 chanspec, err);
4700 goto exit;
4701 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004702 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4703 sizeof(ssid_le));
4704 if (err < 0) {
4705 brcmf_err("setting ssid failed %d\n", err);
4706 goto exit;
4707 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004708 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004709 bss_enable.enable = cpu_to_le32(1);
4710 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4711 sizeof(bss_enable));
4712 if (err < 0) {
4713 brcmf_err("bss_enable config failed %d\n", err);
4714 goto exit;
4715 }
4716
4717 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004718 } else {
4719 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004720 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004721
Wright Fengf25ba692016-11-18 09:59:52 +08004722 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004723 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004724 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004725
4726exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004727 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004728 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004729 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004730 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004731 return err;
4732}
4733
4734static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4735{
Arend van Sprielc1179032012-10-22 13:55:33 -07004736 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004737 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004738 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004739 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004740
Arend van Sprield96b8012012-12-05 15:26:02 +01004741 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004742
Hante Meuleman426d0a52013-02-08 15:53:53 +01004743 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004744 /* Due to most likely deauths outstanding we sleep */
4745 /* first to make sure they get processed by fw. */
4746 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004747
Hante Meulemana44aa402014-12-03 21:05:33 +01004748 if (ifp->vif->mbss) {
4749 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4750 return err;
4751 }
4752
Rafał Miłeckic940de12016-07-06 12:22:54 +02004753 /* First BSS doesn't get a full reset */
4754 if (ifp->bsscfgidx == 0)
4755 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4756
Hante Meuleman5c33a942013-04-02 21:06:18 +02004757 memset(&join_params, 0, sizeof(join_params));
4758 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4759 &join_params, sizeof(join_params));
4760 if (err < 0)
4761 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004762 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004763 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004764 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004765 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4766 if (err < 0)
4767 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004768 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4769 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004770 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4771 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004772 /* Bring device back up so it can be used again */
4773 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4774 if (err < 0)
4775 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004776
4777 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004778 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004779 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004780 bss_enable.enable = cpu_to_le32(0);
4781 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4782 sizeof(bss_enable));
4783 if (err < 0)
4784 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004785 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004786 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004787 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004788 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004789 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004790
Hante Meuleman1a873342012-09-27 14:17:54 +02004791 return err;
4792}
4793
Hante Meulemana0f07952013-02-08 15:53:47 +01004794static s32
4795brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4796 struct cfg80211_beacon_data *info)
4797{
Hante Meulemana0f07952013-02-08 15:53:47 +01004798 struct brcmf_if *ifp = netdev_priv(ndev);
4799 s32 err;
4800
4801 brcmf_dbg(TRACE, "Enter\n");
4802
Hante Meulemana0f07952013-02-08 15:53:47 +01004803 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4804
4805 return err;
4806}
4807
Hante Meuleman1a873342012-09-27 14:17:54 +02004808static int
4809brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004810 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004811{
Hante Meulemana0f07952013-02-08 15:53:47 +01004812 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004813 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004814 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004815 s32 err;
4816
Jouni Malinen89c771e2014-10-10 20:52:40 +03004817 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004818 return -EFAULT;
4819
Jouni Malinen89c771e2014-10-10 20:52:40 +03004820 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004821
Hante Meulemana0f07952013-02-08 15:53:47 +01004822 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4823 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004824 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004825 return -EIO;
4826
Jouni Malinen89c771e2014-10-10 20:52:40 +03004827 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004828 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004829 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004830 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004831 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004832 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004833
Arend van Sprield96b8012012-12-05 15:26:02 +01004834 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004835 return err;
4836}
4837
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004838static int
4839brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4840 const u8 *mac, struct station_parameters *params)
4841{
4842 struct brcmf_if *ifp = netdev_priv(ndev);
4843 s32 err;
4844
4845 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4846 params->sta_flags_mask, params->sta_flags_set);
4847
4848 /* Ignore all 00 MAC */
4849 if (is_zero_ether_addr(mac))
4850 return 0;
4851
4852 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4853 return 0;
4854
4855 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4856 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4857 (void *)mac, ETH_ALEN);
4858 else
4859 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4860 (void *)mac, ETH_ALEN);
4861 if (err < 0)
4862 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4863
4864 return err;
4865}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004866
4867static void
4868brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4869 struct wireless_dev *wdev,
4870 u16 frame_type, bool reg)
4871{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004872 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004873 u16 mgmt_type;
4874
4875 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4876
4877 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004878 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004879 if (reg)
4880 vif->mgmt_rx_reg |= BIT(mgmt_type);
4881 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004882 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004883}
4884
4885
4886static int
4887brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004888 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004889{
4890 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004891 struct ieee80211_channel *chan = params->chan;
4892 const u8 *buf = params->buf;
4893 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004894 const struct ieee80211_mgmt *mgmt;
4895 struct brcmf_cfg80211_vif *vif;
4896 s32 err = 0;
4897 s32 ie_offset;
4898 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004899 struct brcmf_fil_action_frame_le *action_frame;
4900 struct brcmf_fil_af_params_le *af_params;
4901 bool ack;
4902 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004903 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004904
4905 brcmf_dbg(TRACE, "Enter\n");
4906
4907 *cookie = 0;
4908
4909 mgmt = (const struct ieee80211_mgmt *)buf;
4910
Hante Meulemana0f07952013-02-08 15:53:47 +01004911 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4912 brcmf_err("Driver only allows MGMT packet type\n");
4913 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004914 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004915
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004916 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4917
Hante Meulemana0f07952013-02-08 15:53:47 +01004918 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4919 /* Right now the only reason to get a probe response */
4920 /* is for p2p listen response or for p2p GO from */
4921 /* wpa_supplicant. Unfortunately the probe is send */
4922 /* on primary ndev, while dongle wants it on the p2p */
4923 /* vif. Since this is only reason for a probe */
4924 /* response to be sent, the vif is taken from cfg. */
4925 /* If ever desired to send proberesp for non p2p */
4926 /* response then data should be checked for */
4927 /* "DIRECT-". Note in future supplicant will take */
4928 /* dedicated p2p wdev to do this and then this 'hack'*/
4929 /* is not needed anymore. */
4930 ie_offset = DOT11_MGMT_HDR_LEN +
4931 DOT11_BCN_PRB_FIXED_LEN;
4932 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004933 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4934 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4935 err = brcmf_vif_set_mgmt_ie(vif,
4936 BRCMF_VNDR_IE_PRBRSP_FLAG,
4937 &buf[ie_offset],
4938 ie_len);
4939 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4940 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004941 } else if (ieee80211_is_action(mgmt->frame_control)) {
Arend van Spriel8f44c9a2017-07-07 21:09:06 +01004942 if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
4943 brcmf_err("invalid action frame length\n");
4944 err = -EINVAL;
4945 goto exit;
4946 }
Hante Meuleman18e2f612013-02-08 15:53:49 +01004947 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4948 if (af_params == NULL) {
4949 brcmf_err("unable to allocate frame\n");
4950 err = -ENOMEM;
4951 goto exit;
4952 }
4953 action_frame = &af_params->action_frame;
4954 /* Add the packet Id */
4955 action_frame->packet_id = cpu_to_le32(*cookie);
4956 /* Add BSSID */
4957 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4958 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4959 /* Add the length exepted for 802.11 header */
4960 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004961 /* Add the channel. Use the one specified as parameter if any or
4962 * the current one (got from the firmware) otherwise
4963 */
4964 if (chan)
4965 freq = chan->center_freq;
4966 else
4967 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4968 &freq);
4969 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004970 af_params->channel = cpu_to_le32(chan_nr);
4971
4972 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4973 le16_to_cpu(action_frame->len));
4974
4975 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004976 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004977
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004978 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004979 af_params);
4980
4981 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4982 GFP_KERNEL);
4983 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004984 } else {
4985 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004986 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004987 }
4988
Hante Meuleman18e2f612013-02-08 15:53:49 +01004989exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004990 return err;
4991}
4992
4993
4994static int
4995brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4996 struct wireless_dev *wdev,
4997 u64 cookie)
4998{
4999 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5000 struct brcmf_cfg80211_vif *vif;
5001 int err = 0;
5002
5003 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
5004
5005 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
5006 if (vif == NULL) {
5007 brcmf_err("No p2p device available for probe response\n");
5008 err = -ENODEV;
5009 goto exit;
5010 }
5011 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
5012exit:
5013 return err;
5014}
5015
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005016static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
5017 struct wireless_dev *wdev,
5018 struct cfg80211_chan_def *chandef)
5019{
5020 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5021 struct net_device *ndev = wdev->netdev;
5022 struct brcmf_if *ifp;
5023 struct brcmu_chan ch;
5024 enum nl80211_band band = 0;
5025 enum nl80211_chan_width width = 0;
5026 u32 chanspec;
5027 int freq, err;
5028
5029 if (!ndev)
5030 return -ENODEV;
5031 ifp = netdev_priv(ndev);
5032
5033 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
5034 if (err) {
5035 brcmf_err("chanspec failed (%d)\n", err);
5036 return err;
5037 }
5038
5039 ch.chspec = chanspec;
5040 cfg->d11inf.decchspec(&ch);
5041
5042 switch (ch.band) {
5043 case BRCMU_CHAN_BAND_2G:
5044 band = NL80211_BAND_2GHZ;
5045 break;
5046 case BRCMU_CHAN_BAND_5G:
5047 band = NL80211_BAND_5GHZ;
5048 break;
5049 }
5050
5051 switch (ch.bw) {
5052 case BRCMU_CHAN_BW_80:
5053 width = NL80211_CHAN_WIDTH_80;
5054 break;
5055 case BRCMU_CHAN_BW_40:
5056 width = NL80211_CHAN_WIDTH_40;
5057 break;
5058 case BRCMU_CHAN_BW_20:
5059 width = NL80211_CHAN_WIDTH_20;
5060 break;
5061 case BRCMU_CHAN_BW_80P80:
5062 width = NL80211_CHAN_WIDTH_80P80;
5063 break;
5064 case BRCMU_CHAN_BW_160:
5065 width = NL80211_CHAN_WIDTH_160;
5066 break;
5067 }
5068
5069 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
5070 chandef->chan = ieee80211_get_channel(wiphy, freq);
5071 chandef->width = width;
5072 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
5073 chandef->center_freq2 = 0;
5074
5075 return 0;
5076}
5077
Piotr Haber61730d42013-04-23 12:53:12 +02005078static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
5079 struct wireless_dev *wdev,
5080 enum nl80211_crit_proto_id proto,
5081 u16 duration)
5082{
5083 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5084 struct brcmf_cfg80211_vif *vif;
5085
5086 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5087
5088 /* only DHCP support for now */
5089 if (proto != NL80211_CRIT_PROTO_DHCP)
5090 return -EINVAL;
5091
5092 /* suppress and abort scanning */
5093 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5094 brcmf_abort_scanning(cfg);
5095
5096 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5097}
5098
5099static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5100 struct wireless_dev *wdev)
5101{
5102 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5103 struct brcmf_cfg80211_vif *vif;
5104
5105 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5106
5107 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5108 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5109}
5110
Hante Meuleman70b7d942014-07-30 13:20:07 +02005111static s32
5112brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5113 const struct brcmf_event_msg *e, void *data)
5114{
5115 switch (e->reason) {
5116 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5117 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5118 break;
5119 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5120 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5121 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5122 break;
5123 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5124 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5125 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5126 break;
5127 }
5128
5129 return 0;
5130}
5131
Arend van Spriel89c2f382013-08-10 12:27:25 +02005132static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5133{
5134 int ret;
5135
5136 switch (oper) {
5137 case NL80211_TDLS_DISCOVERY_REQ:
5138 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5139 break;
5140 case NL80211_TDLS_SETUP:
5141 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5142 break;
5143 case NL80211_TDLS_TEARDOWN:
5144 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5145 break;
5146 default:
5147 brcmf_err("unsupported operation: %d\n", oper);
5148 ret = -EOPNOTSUPP;
5149 }
5150 return ret;
5151}
5152
5153static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005154 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005155 enum nl80211_tdls_operation oper)
5156{
5157 struct brcmf_if *ifp;
5158 struct brcmf_tdls_iovar_le info;
5159 int ret = 0;
5160
5161 ret = brcmf_convert_nl80211_tdls_oper(oper);
5162 if (ret < 0)
5163 return ret;
5164
5165 ifp = netdev_priv(ndev);
5166 memset(&info, 0, sizeof(info));
5167 info.mode = (u8)ret;
5168 if (peer)
5169 memcpy(info.ea, peer, ETH_ALEN);
5170
5171 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5172 &info, sizeof(info));
5173 if (ret < 0)
5174 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5175
5176 return ret;
5177}
5178
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005179static int
5180brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5181 struct net_device *ndev,
5182 struct cfg80211_connect_params *sme,
5183 u32 changed)
5184{
5185 struct brcmf_if *ifp;
5186 int err;
5187
5188 if (!(changed & UPDATE_ASSOC_IES))
5189 return 0;
5190
5191 ifp = netdev_priv(ndev);
5192 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5193 sme->ie, sme->ie_len);
5194 if (err)
5195 brcmf_err("Set Assoc REQ IE Failed\n");
5196 else
5197 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5198
5199 return err;
5200}
5201
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005202#ifdef CONFIG_PM
5203static int
5204brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5205 struct cfg80211_gtk_rekey_data *gtk)
5206{
5207 struct brcmf_if *ifp = netdev_priv(ndev);
5208 struct brcmf_gtk_keyinfo_le gtk_le;
5209 int ret;
5210
5211 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5212
5213 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5214 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5215 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5216 sizeof(gtk_le.replay_counter));
5217
5218 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5219 sizeof(gtk_le));
5220 if (ret < 0)
5221 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5222
5223 return ret;
5224}
5225#endif
5226
Arend van Spriel2526ff22017-06-09 13:08:48 +01005227static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
5228 const struct cfg80211_pmk_conf *conf)
5229{
5230 struct brcmf_if *ifp;
5231
5232 brcmf_dbg(TRACE, "enter\n");
5233
5234 /* expect using firmware supplicant for 1X */
5235 ifp = netdev_priv(dev);
5236 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5237 return -EINVAL;
5238
5239 return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
5240}
5241
5242static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
5243 const u8 *aa)
5244{
5245 struct brcmf_if *ifp;
5246
5247 brcmf_dbg(TRACE, "enter\n");
5248 ifp = netdev_priv(dev);
5249 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5250 return -EINVAL;
5251
5252 return brcmf_set_pmk(ifp, NULL, 0);
5253}
5254
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005255static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005256 .add_virtual_intf = brcmf_cfg80211_add_iface,
5257 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005258 .change_virtual_intf = brcmf_cfg80211_change_iface,
5259 .scan = brcmf_cfg80211_scan,
5260 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5261 .join_ibss = brcmf_cfg80211_join_ibss,
5262 .leave_ibss = brcmf_cfg80211_leave_ibss,
5263 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005264 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005265 .set_tx_power = brcmf_cfg80211_set_tx_power,
5266 .get_tx_power = brcmf_cfg80211_get_tx_power,
5267 .add_key = brcmf_cfg80211_add_key,
5268 .del_key = brcmf_cfg80211_del_key,
5269 .get_key = brcmf_cfg80211_get_key,
5270 .set_default_key = brcmf_cfg80211_config_default_key,
5271 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5272 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005273 .connect = brcmf_cfg80211_connect,
5274 .disconnect = brcmf_cfg80211_disconnect,
5275 .suspend = brcmf_cfg80211_suspend,
5276 .resume = brcmf_cfg80211_resume,
5277 .set_pmksa = brcmf_cfg80211_set_pmksa,
5278 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005279 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005280 .start_ap = brcmf_cfg80211_start_ap,
5281 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005282 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005283 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005284 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005285 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5286 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005287 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5288 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5289 .remain_on_channel = brcmf_p2p_remain_on_channel,
5290 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005291 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005292 .start_p2p_device = brcmf_p2p_start_device,
5293 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005294 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5295 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005296 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005297 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel2526ff22017-06-09 13:08:48 +01005298 .set_pmk = brcmf_cfg80211_set_pmk,
5299 .del_pmk = brcmf_cfg80211_del_pmk,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005300};
5301
Arend van Spriel3eacf862012-10-22 13:55:30 -07005302struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005303 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005304{
Hante Meulemana44aa402014-12-03 21:05:33 +01005305 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005306 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005307 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005308
Arend van Spriel33a6b152013-02-08 15:53:39 +01005309 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005310 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005311 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5312 if (!vif)
5313 return ERR_PTR(-ENOMEM);
5314
5315 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005316 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005317
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005318 brcmf_init_prof(&vif->profile);
5319
Hante Meulemana44aa402014-12-03 21:05:33 +01005320 if (type == NL80211_IFTYPE_AP) {
5321 mbss = false;
5322 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5323 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5324 mbss = true;
5325 break;
5326 }
5327 }
5328 vif->mbss = mbss;
5329 }
5330
Arend van Spriel3eacf862012-10-22 13:55:30 -07005331 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005332 return vif;
5333}
5334
Arend van Spriel427dec52014-01-06 12:40:47 +01005335void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005336{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005337 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005338 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005339}
5340
Arend van Spriel9df4d542014-01-06 12:40:49 +01005341void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5342{
5343 struct brcmf_cfg80211_vif *vif;
5344 struct brcmf_if *ifp;
5345
5346 ifp = netdev_priv(ndev);
5347 vif = ifp->vif;
5348
Arend van Spriel95ef1232015-08-26 22:15:04 +02005349 if (vif)
5350 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005351}
5352
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005353static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
5354 const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005355{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005356 u32 event = e->event_code;
5357 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005358
Arend van Spriel2526ff22017-06-09 13:08:48 +01005359 if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
5360 event == BRCMF_E_PSK_SUP &&
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005361 status == BRCMF_E_STATUS_FWSUP_COMPLETED)
5362 set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005364 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005365 memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
5366 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
5367 return true;
5368
5369 set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005370 }
5371
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005372 if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
5373 test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
5374 clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
5375 clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
5376 return true;
5377 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378 return false;
5379}
5380
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005381static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005382{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005383 u32 event = e->event_code;
5384 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005385
Hante Meuleman68ca3952014-02-25 20:30:26 +01005386 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5387 (event == BRCMF_E_DISASSOC_IND) ||
5388 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005389 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390 return true;
5391 }
5392 return false;
5393}
5394
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005395static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005396 const struct brcmf_event_msg *e)
5397{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005398 u32 event = e->event_code;
5399 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005400
5401 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005402 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5403 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005404 return true;
5405 }
5406
5407 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005408 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005409 return true;
5410 }
5411
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005412 if (event == BRCMF_E_PSK_SUP &&
5413 status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
5414 brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
5415 status);
5416 return true;
5417 }
5418
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419 return false;
5420}
5421
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005422static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005423{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005424 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005425
5426 kfree(conn_info->req_ie);
5427 conn_info->req_ie = NULL;
5428 conn_info->req_ie_len = 0;
5429 kfree(conn_info->resp_ie);
5430 conn_info->resp_ie = NULL;
5431 conn_info->resp_ie_len = 0;
5432}
5433
Hante Meuleman89286dc2013-02-08 15:53:46 +01005434static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5435 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005436{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005437 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005438 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 u32 req_len;
5440 u32 resp_len;
5441 s32 err = 0;
5442
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005443 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005444
Arend van Sprielac24be62012-10-22 10:36:23 -07005445 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5446 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005447 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005448 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449 return err;
5450 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005451 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005452 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005453 req_len = le32_to_cpu(assoc_info->req_len);
5454 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005455 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005456 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005457 cfg->extra_buf,
5458 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005459 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005460 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005461 return err;
5462 }
5463 conn_info->req_ie_len = req_len;
5464 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005465 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005466 GFP_KERNEL);
5467 } else {
5468 conn_info->req_ie_len = 0;
5469 conn_info->req_ie = NULL;
5470 }
5471 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005472 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005473 cfg->extra_buf,
5474 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005475 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005476 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005477 return err;
5478 }
5479 conn_info->resp_ie_len = resp_len;
5480 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005481 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005482 GFP_KERNEL);
5483 } else {
5484 conn_info->resp_ie_len = 0;
5485 conn_info->resp_ie = NULL;
5486 }
Arend van Spriel16886732012-12-05 15:26:04 +01005487 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5488 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005489
5490 return err;
5491}
5492
5493static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005494brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005495 struct net_device *ndev,
5496 const struct brcmf_event_msg *e)
5497{
Arend van Sprielc1179032012-10-22 13:55:33 -07005498 struct brcmf_if *ifp = netdev_priv(ndev);
5499 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005500 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5501 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005502 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005503 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005504 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005505 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005506 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005507 u32 freq;
5508 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005509 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005510
Arend van Sprield96b8012012-12-05 15:26:02 +01005511 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005512
Hante Meuleman89286dc2013-02-08 15:53:46 +01005513 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005514 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005515 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005516
Franky Lina180b832012-10-10 11:13:09 -07005517 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5518 if (buf == NULL) {
5519 err = -ENOMEM;
5520 goto done;
5521 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005522
Franky Lina180b832012-10-10 11:13:09 -07005523 /* data sent to dongle has to be little endian */
5524 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005525 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005526 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005527
5528 if (err)
5529 goto done;
5530
5531 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005532 ch.chspec = le16_to_cpu(bi->chanspec);
5533 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005534
Franky Lin83cf17a2013-04-11 13:28:50 +02005535 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005536 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005537 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005538 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005539
Rafał Miłecki4712d882016-05-20 13:38:57 +02005540 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005541 notify_channel = ieee80211_get_channel(wiphy, freq);
5542
Franky Lina180b832012-10-10 11:13:09 -07005543done:
5544 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005545
5546 roam_info.channel = notify_channel;
5547 roam_info.bssid = profile->bssid;
5548 roam_info.req_ie = conn_info->req_ie;
5549 roam_info.req_ie_len = conn_info->req_ie_len;
5550 roam_info.resp_ie = conn_info->resp_ie;
5551 roam_info.resp_ie_len = conn_info->resp_ie_len;
5552
5553 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005554 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005555
Arend van Sprielc1179032012-10-22 13:55:33 -07005556 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005557 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005558 return err;
5559}
5560
5561static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005562brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005563 struct net_device *ndev, const struct brcmf_event_msg *e,
5564 bool completed)
5565{
Arend van Sprielc1179032012-10-22 13:55:33 -07005566 struct brcmf_if *ifp = netdev_priv(ndev);
5567 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005568 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel123fef32017-06-09 13:08:49 +01005569 struct cfg80211_connect_resp_params conn_params;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005570
Arend van Sprield96b8012012-12-05 15:26:02 +01005571 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005572
Arend van Sprielc1179032012-10-22 13:55:33 -07005573 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5574 &ifp->vif->sme_state)) {
Arend van Spriel123fef32017-06-09 13:08:49 +01005575 memset(&conn_params, 0, sizeof(conn_params));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005576 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005577 brcmf_get_assoc_ies(cfg, ifp);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005578 brcmf_update_bss_info(cfg, ifp);
5579 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5580 &ifp->vif->sme_state);
Arend van Spriel123fef32017-06-09 13:08:49 +01005581 conn_params.status = WLAN_STATUS_SUCCESS;
5582 } else {
5583 conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005584 }
Arend van Spriel123fef32017-06-09 13:08:49 +01005585 conn_params.bssid = profile->bssid;
5586 conn_params.req_ie = conn_info->req_ie;
5587 conn_params.req_ie_len = conn_info->req_ie_len;
5588 conn_params.resp_ie = conn_info->resp_ie;
5589 conn_params.resp_ie_len = conn_info->resp_ie_len;
5590 cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005591 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5592 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005593 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005594 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005595 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005596}
5597
5598static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005599brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005600 struct net_device *ndev,
5601 const struct brcmf_event_msg *e, void *data)
5602{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005603 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005604 u32 event = e->event_code;
5605 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005606 struct station_info sinfo;
5607
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005608 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5609 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005610 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5611 ndev != cfg_to_ndev(cfg)) {
5612 brcmf_dbg(CONN, "AP mode link down\n");
5613 complete(&cfg->vif_disabled);
5614 return 0;
5615 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005616
Hante Meuleman1a873342012-09-27 14:17:54 +02005617 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005618 (reason == BRCMF_E_STATUS_SUCCESS)) {
5619 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005620 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005621 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005622 return -EINVAL;
5623 }
5624 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005625 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005626 generation++;
5627 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005628 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005629 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5630 (event == BRCMF_E_DEAUTH_IND) ||
5631 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005632 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005633 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005634 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005635}
5636
5637static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005638brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005639 const struct brcmf_event_msg *e, void *data)
5640{
Arend van Spriel19937322012-11-05 16:22:32 -08005641 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5642 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005643 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005644 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005645 s32 err = 0;
5646
Hante Meuleman8851cce2014-07-30 13:20:02 +02005647 if ((e->event_code == BRCMF_E_DEAUTH) ||
5648 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5649 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5650 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5651 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5652 }
5653
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005654 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005655 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005656 } else if (brcmf_is_linkup(ifp->vif, e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005657 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005658 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005659 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005660 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005661 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005662 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005663 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5664 &ifp->vif->sme_state);
5665 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5666 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005667 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005668 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005669 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005670 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005671 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005672 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005673 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005674 brcmf_link_down(ifp->vif,
5675 brcmf_map_fw_linkdown_reason(e));
5676 brcmf_init_prof(ndev_to_prof(ndev));
5677 if (ndev != cfg_to_ndev(cfg))
5678 complete(&cfg->vif_disabled);
5679 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005680 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005681 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005682 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005683 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5684 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005685 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005686 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005687 }
5688
5689 return err;
5690}
5691
5692static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005693brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005694 const struct brcmf_event_msg *e, void *data)
5695{
Arend van Spriel19937322012-11-05 16:22:32 -08005696 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005697 u32 event = e->event_code;
5698 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005699
5700 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005701 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005702 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005703 else
Arend van Spriel19937322012-11-05 16:22:32 -08005704 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005705 }
5706
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005707 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005708}
5709
5710static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005711brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005712 const struct brcmf_event_msg *e, void *data)
5713{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005714 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005715 enum nl80211_key_type key_type;
5716
5717 if (flags & BRCMF_EVENT_MSG_GROUP)
5718 key_type = NL80211_KEYTYPE_GROUP;
5719 else
5720 key_type = NL80211_KEYTYPE_PAIRWISE;
5721
Arend van Spriel19937322012-11-05 16:22:32 -08005722 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005723 NULL, GFP_KERNEL);
5724
5725 return 0;
5726}
5727
Arend van Sprield3c0b632013-02-08 15:53:37 +01005728static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5729 const struct brcmf_event_msg *e, void *data)
5730{
5731 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5732 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5733 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5734 struct brcmf_cfg80211_vif *vif;
5735
Hante Meuleman37a869e2015-10-29 20:33:17 +01005736 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005737 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005738 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005739
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005740 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005741 event->action = ifevent->action;
5742 vif = event->vif;
5743
5744 switch (ifevent->action) {
5745 case BRCMF_E_IF_ADD:
5746 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005747 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005748 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005749 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005750 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005751
5752 ifp->vif = vif;
5753 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005754 if (ifp->ndev) {
5755 vif->wdev.netdev = ifp->ndev;
5756 ifp->ndev->ieee80211_ptr = &vif->wdev;
5757 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5758 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005759 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005760 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005761 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005762
5763 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005764 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005765 /* event may not be upon user request */
5766 if (brcmf_cfg80211_vif_event_armed(cfg))
5767 wake_up(&event->vif_wq);
5768 return 0;
5769
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005770 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005771 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005772 wake_up(&event->vif_wq);
5773 return 0;
5774
Arend van Sprield3c0b632013-02-08 15:53:37 +01005775 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005776 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005777 break;
5778 }
5779 return -EINVAL;
5780}
5781
Arend van Spriel5b435de2011-10-05 13:19:03 +02005782static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5783{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005784 conf->frag_threshold = (u32)-1;
5785 conf->rts_threshold = (u32)-1;
5786 conf->retry_short = (u32)-1;
5787 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005788}
5789
Arend van Spriel5c36b992012-11-14 18:46:05 -08005790static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005791{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005792 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5793 brcmf_notify_connect_status);
5794 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5795 brcmf_notify_connect_status);
5796 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5797 brcmf_notify_connect_status);
5798 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5799 brcmf_notify_connect_status);
5800 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5801 brcmf_notify_connect_status);
5802 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5803 brcmf_notify_connect_status);
5804 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5805 brcmf_notify_roaming_status);
5806 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5807 brcmf_notify_mic_status);
5808 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5809 brcmf_notify_connect_status);
5810 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5811 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005812 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5813 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005814 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005815 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005816 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5817 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005818 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5819 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005820 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5821 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005822 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5823 brcmf_p2p_notify_action_tx_complete);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005824 brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
5825 brcmf_notify_connect_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005826}
5827
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005828static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005829{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005830 kfree(cfg->conf);
5831 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005832 kfree(cfg->extra_buf);
5833 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005834 kfree(cfg->wowl.nd);
5835 cfg->wowl.nd = NULL;
5836 kfree(cfg->wowl.nd_info);
5837 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005838 kfree(cfg->escan_info.escan_buf);
5839 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005840}
5841
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005842static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005843{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005844 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5845 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005846 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005847 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5848 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005849 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005850 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5851 if (!cfg->wowl.nd)
5852 goto init_priv_mem_out;
5853 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5854 sizeof(struct cfg80211_wowlan_nd_match *),
5855 GFP_KERNEL);
5856 if (!cfg->wowl.nd_info)
5857 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005858 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5859 if (!cfg->escan_info.escan_buf)
5860 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005861
5862 return 0;
5863
5864init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005865 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005866
5867 return -ENOMEM;
5868}
5869
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005870static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005871{
5872 s32 err = 0;
5873
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005874 cfg->scan_request = NULL;
5875 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005876 cfg->active_scan = true; /* we do active scan per default */
5877 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005878 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005879 if (err)
5880 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005881 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005882 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005883 brcmf_init_escan(cfg);
5884 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005885 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005886 return err;
5887}
5888
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005889static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005890{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005891 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005892 brcmf_abort_scanning(cfg);
5893 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005894}
5895
Arend van Sprield3c0b632013-02-08 15:53:37 +01005896static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5897{
5898 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005899 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005900}
5901
Hante Meuleman1119e232015-11-25 11:32:42 +01005902static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005903{
Hante Meuleman1119e232015-11-25 11:32:42 +01005904 s32 err;
5905 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005906 __le32 roamtrigger[2];
5907 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005908
Hante Meuleman1119e232015-11-25 11:32:42 +01005909 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005910 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005911 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5912 else
5913 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5914 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5915 if (err) {
5916 brcmf_err("bcn_timeout error (%d)\n", err);
5917 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005918 }
5919
Hante Meuleman1119e232015-11-25 11:32:42 +01005920 /* Enable/Disable built-in roaming to allow supplicant to take care of
5921 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005922 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005923 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005924 ifp->drvr->settings->roamoff ? "Off" : "On");
5925 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5926 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005927 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005928 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005929 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005930 }
5931
Arend van Sprielf588bc02011-10-12 20:51:22 +02005932 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5933 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005934 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005935 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005936 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005937 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005938 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005939 }
5940
Arend van Sprielf588bc02011-10-12 20:51:22 +02005941 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5942 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005943 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005944 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005945 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005946 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005947 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005948 }
5949
Hante Meuleman1119e232015-11-25 11:32:42 +01005950roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005951 return err;
5952}
5953
5954static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005955brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005956{
5957 s32 err = 0;
5958
Arend van Sprielac24be62012-10-22 10:36:23 -07005959 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005960 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005961 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005962 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005963 goto dongle_scantime_out;
5964 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005965 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005966 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005967 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005968 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005969 goto dongle_scantime_out;
5970 }
5971
Arend van Sprielac24be62012-10-22 10:36:23 -07005972 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005973 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005974 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005975 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005976 goto dongle_scantime_out;
5977 }
5978
5979dongle_scantime_out:
5980 return err;
5981}
5982
Arend van Sprielb48d8912014-07-12 08:49:41 +02005983static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5984 struct brcmu_chan *ch)
5985{
5986 u32 ht40_flag;
5987
5988 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5989 if (ch->sb == BRCMU_CHAN_SB_U) {
5990 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5991 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5992 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5993 } else {
5994 /* It should be one of
5995 * IEEE80211_CHAN_NO_HT40 or
5996 * IEEE80211_CHAN_NO_HT40PLUS
5997 */
5998 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5999 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
6000 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
6001 }
6002}
6003
6004static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
6005 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02006006{
6007 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006008 struct ieee80211_supported_band *band;
6009 struct ieee80211_channel *channel;
6010 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02006011 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02006012 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006013 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006014 u8 *pbuf;
6015 u32 i, j;
6016 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006017 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02006018
6019 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6020
6021 if (pbuf == NULL)
6022 return -ENOMEM;
6023
6024 list = (struct brcmf_chanspec_list *)pbuf;
6025
6026 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6027 BRCMF_DCMD_MEDLEN);
6028 if (err) {
6029 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006030 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02006031 }
6032
Arend van Sprielb48d8912014-07-12 08:49:41 +02006033 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006034 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006035 if (band)
6036 for (i = 0; i < band->n_channels; i++)
6037 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006038 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006039 if (band)
6040 for (i = 0; i < band->n_channels; i++)
6041 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02006042
6043 total = le32_to_cpu(list->count);
6044 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02006045 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6046 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02006047
Franky Lin83cf17a2013-04-11 13:28:50 +02006048 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006049 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02006050 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006051 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02006052 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006053 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02006054 continue;
6055 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02006056 if (!band)
6057 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006058 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01006059 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02006060 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006061 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02006062 ch.bw == BRCMU_CHAN_BW_80)
6063 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006064
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006065 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006066 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006067 if (band->channels[j].hw_value == ch.control_ch_num) {
6068 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02006069 break;
6070 }
6071 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006072 if (!channel) {
6073 /* It seems firmware supports some channel we never
6074 * considered. Something new in IEEE standard?
6075 */
6076 brcmf_err("Ignoring unexpected firmware channel %d\n",
6077 ch.control_ch_num);
6078 continue;
6079 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006080
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006081 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
6082 continue;
6083
Arend van Sprielb48d8912014-07-12 08:49:41 +02006084 /* assuming the chanspecs order is HT20,
6085 * HT40 upper, HT40 lower, and VHT80.
6086 */
6087 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006088 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006089 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006090 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006091 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02006092 /* enable the channel and disable other bandwidths
6093 * for now as mentioned order assure they are enabled
6094 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02006095 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006096 channel->flags = IEEE80211_CHAN_NO_HT40 |
6097 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006098 ch.bw = BRCMU_CHAN_BW_20;
6099 cfg->d11inf.encchspec(&ch);
6100 chaninfo = ch.chspec;
6101 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
6102 &chaninfo);
6103 if (!err) {
6104 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006105 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006106 (IEEE80211_CHAN_RADAR |
6107 IEEE80211_CHAN_NO_IR);
6108 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006109 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006110 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006111 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006112 }
6113 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006114
Arend van Sprielb48d8912014-07-12 08:49:41 +02006115fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006116 kfree(pbuf);
6117 return err;
6118}
6119
Arend van Sprielb48d8912014-07-12 08:49:41 +02006120static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006121{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006122 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6123 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006124 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006125 struct brcmf_chanspec_list *list;
6126 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006127 u32 val;
6128 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006129 struct brcmu_chan ch;
6130 u32 num_chan;
6131 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006132
6133 /* verify support for bw_cap command */
6134 val = WLC_BAND_5G;
6135 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6136
6137 if (!err) {
6138 /* only set 2G bandwidth using bw_cap command */
6139 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6140 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6141 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6142 sizeof(band_bwcap));
6143 } else {
6144 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6145 val = WLC_N_BW_40ALL;
6146 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6147 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006148
6149 if (!err) {
6150 /* update channel info in 2G band */
6151 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6152
6153 if (pbuf == NULL)
6154 return -ENOMEM;
6155
6156 ch.band = BRCMU_CHAN_BAND_2G;
6157 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006158 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006159 ch.chnum = 0;
6160 cfg->d11inf.encchspec(&ch);
6161
6162 /* pass encoded chanspec in query */
6163 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6164
6165 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6166 BRCMF_DCMD_MEDLEN);
6167 if (err) {
6168 brcmf_err("get chanspecs error (%d)\n", err);
6169 kfree(pbuf);
6170 return err;
6171 }
6172
Johannes Berg57fbcce2016-04-12 15:56:15 +02006173 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006174 list = (struct brcmf_chanspec_list *)pbuf;
6175 num_chan = le32_to_cpu(list->count);
6176 for (i = 0; i < num_chan; i++) {
6177 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6178 cfg->d11inf.decchspec(&ch);
6179 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6180 continue;
6181 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6182 continue;
6183 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006184 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006185 break;
6186 }
6187 if (WARN_ON(j == band->n_channels))
6188 continue;
6189
6190 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6191 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006192 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006193 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006194 return err;
6195}
6196
Arend van Spriel2375d972014-01-06 12:40:41 +01006197static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6198{
6199 u32 band, mimo_bwcap;
6200 int err;
6201
6202 band = WLC_BAND_2G;
6203 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6204 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006205 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006206 band = WLC_BAND_5G;
6207 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6208 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006209 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006210 return;
6211 }
6212 WARN_ON(1);
6213 return;
6214 }
6215 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6216 mimo_bwcap = 0;
6217 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6218 if (err)
6219 /* assume 20MHz if firmware does not give a clue */
6220 mimo_bwcap = WLC_N_BW_20ALL;
6221
6222 switch (mimo_bwcap) {
6223 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006224 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006225 /* fall-thru */
6226 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006227 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006228 /* fall-thru */
6229 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006230 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6231 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006232 break;
6233 default:
6234 brcmf_err("invalid mimo_bw_cap value\n");
6235 }
6236}
Hante Meulemand48200b2013-04-03 12:40:29 +02006237
Arend van Spriel18d6c532014-05-12 10:47:35 +02006238static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6239 u32 bw_cap[2], u32 nchain)
6240{
6241 band->ht_cap.ht_supported = true;
6242 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6243 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6244 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6245 }
6246 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6247 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6248 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6249 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6250 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6251 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6252}
6253
6254static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6255{
6256 u16 mcs_map;
6257 int i;
6258
6259 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6260 mcs_map = (mcs_map << 2) | supp;
6261
6262 return cpu_to_le16(mcs_map);
6263}
6264
6265static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006266 u32 bw_cap[2], u32 nchain, u32 txstreams,
6267 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006268{
6269 __le16 mcs_map;
6270
6271 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006272 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006273 return;
6274
6275 band->vht_cap.vht_supported = true;
6276 /* 80MHz is mandatory */
6277 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6278 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6279 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6280 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6281 }
6282 /* all support 256-QAM */
6283 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6284 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6285 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006286
6287 /* Beamforming support information */
6288 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6289 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6290 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6291 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6292 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6293 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6294 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6295 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6296
6297 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6298 band->vht_cap.cap |=
6299 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6300 band->vht_cap.cap |= ((txstreams - 1) <<
6301 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6302 band->vht_cap.cap |=
6303 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6304 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006305}
6306
Arend van Sprielb48d8912014-07-12 08:49:41 +02006307static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006308{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006309 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006310 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006311 u32 nmode = 0;
6312 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006313 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006314 u32 rxchain;
6315 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006316 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006317 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006318 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006319 u32 txstreams = 0;
6320 u32 txbf_bfe_cap = 0;
6321 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006322
Arend van Spriel18d6c532014-05-12 10:47:35 +02006323 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006324 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6325 if (err) {
6326 brcmf_err("nmode error (%d)\n", err);
6327 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006328 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006329 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006330 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006331 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6332 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006333
Daniel Kim4aca7a12014-02-25 20:30:36 +01006334 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6335 if (err) {
6336 brcmf_err("rxchain error (%d)\n", err);
6337 nchain = 1;
6338 } else {
6339 for (nchain = 0; rxchain; nchain++)
6340 rxchain = rxchain & (rxchain - 1);
6341 }
6342 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6343
Arend van Sprielb48d8912014-07-12 08:49:41 +02006344 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006345 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006346 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006347 return err;
6348 }
6349
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006350 if (vhtmode) {
6351 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6352 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6353 &txbf_bfe_cap);
6354 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6355 &txbf_bfr_cap);
6356 }
6357
Arend van Sprielb48d8912014-07-12 08:49:41 +02006358 wiphy = cfg_to_wiphy(cfg);
6359 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6360 band = wiphy->bands[i];
6361 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006362 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006363
Arend van Spriel18d6c532014-05-12 10:47:35 +02006364 if (nmode)
6365 brcmf_update_ht_cap(band, bw_cap, nchain);
6366 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006367 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6368 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006369 }
6370
Arend van Sprielb48d8912014-07-12 08:49:41 +02006371 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006372}
6373
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006374static const struct ieee80211_txrx_stypes
6375brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6376 [NL80211_IFTYPE_STATION] = {
6377 .tx = 0xffff,
6378 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6379 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6380 },
6381 [NL80211_IFTYPE_P2P_CLIENT] = {
6382 .tx = 0xffff,
6383 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6384 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6385 },
6386 [NL80211_IFTYPE_P2P_GO] = {
6387 .tx = 0xffff,
6388 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6389 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6390 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6391 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6392 BIT(IEEE80211_STYPE_AUTH >> 4) |
6393 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6394 BIT(IEEE80211_STYPE_ACTION >> 4)
6395 },
6396 [NL80211_IFTYPE_P2P_DEVICE] = {
6397 .tx = 0xffff,
6398 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6399 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6400 }
6401};
6402
Arend van Spriel0882dda2015-08-20 22:06:03 +02006403/**
6404 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6405 *
6406 * @wiphy: wiphy object.
6407 * @ifp: interface object needed for feat module api.
6408 *
6409 * The interface modes and combinations are determined dynamically here
6410 * based on firmware functionality.
6411 *
6412 * no p2p and no mbss:
6413 *
6414 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6415 *
6416 * no p2p and mbss:
6417 *
6418 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6419 * #AP <= 4, matching BI, channels = 1, 4 total
6420 *
6421 * p2p, no mchan, and mbss:
6422 *
6423 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6424 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6425 * #AP <= 4, matching BI, channels = 1, 4 total
6426 *
6427 * p2p, mchan, and mbss:
6428 *
6429 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6430 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6431 * #AP <= 4, matching BI, channels = 1, 4 total
6432 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006433static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6434{
6435 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006436 struct ieee80211_iface_limit *c0_limits = NULL;
6437 struct ieee80211_iface_limit *p2p_limits = NULL;
6438 struct ieee80211_iface_limit *mbss_limits = NULL;
6439 bool mbss, p2p;
6440 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006441
Arend van Spriel0882dda2015-08-20 22:06:03 +02006442 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6443 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6444
6445 n_combos = 1 + !!p2p + !!mbss;
6446 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006447 if (!combo)
6448 goto err;
6449
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006450 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6451 BIT(NL80211_IFTYPE_ADHOC) |
6452 BIT(NL80211_IFTYPE_AP);
6453
Arend van Spriel0882dda2015-08-20 22:06:03 +02006454 c = 0;
6455 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006456 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6457 if (!c0_limits)
6458 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006459 c0_limits[i].max = 1;
6460 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6461 if (p2p) {
6462 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6463 combo[c].num_different_channels = 2;
Wright Feng99976fc2017-08-03 17:37:59 +08006464 else
6465 combo[c].num_different_channels = 1;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006466 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6467 BIT(NL80211_IFTYPE_P2P_GO) |
6468 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006469 c0_limits[i].max = 1;
6470 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6471 c0_limits[i].max = 1;
6472 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6473 BIT(NL80211_IFTYPE_P2P_GO);
6474 } else {
Wright Feng99976fc2017-08-03 17:37:59 +08006475 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006476 c0_limits[i].max = 1;
6477 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006478 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006479 combo[c].max_interfaces = i;
6480 combo[c].n_limits = i;
6481 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006482
Arend van Spriel0882dda2015-08-20 22:06:03 +02006483 if (p2p) {
6484 c++;
6485 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006486 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6487 if (!p2p_limits)
6488 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006489 p2p_limits[i].max = 1;
6490 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6491 p2p_limits[i].max = 1;
6492 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6493 p2p_limits[i].max = 1;
6494 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6495 p2p_limits[i].max = 1;
6496 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006497 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006498 combo[c].max_interfaces = i;
6499 combo[c].n_limits = i;
6500 combo[c].limits = p2p_limits;
6501 }
6502
6503 if (mbss) {
6504 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006505 i = 0;
6506 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6507 if (!mbss_limits)
6508 goto err;
6509 mbss_limits[i].max = 4;
6510 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006511 combo[c].beacon_int_infra_match = true;
6512 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006513 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006514 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006515 combo[c].limits = mbss_limits;
6516 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006517
Arend van Spriel0882dda2015-08-20 22:06:03 +02006518 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006519 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006520 return 0;
6521
6522err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006523 kfree(c0_limits);
6524 kfree(p2p_limits);
6525 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006526 kfree(combo);
6527 return -ENOMEM;
6528}
6529
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006530#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006531static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006532 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006533 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6534 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6535 .pattern_min_len = 1,
6536 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006537};
6538#endif
6539
Hante Meuleman3021ad92016-01-05 11:05:45 +01006540static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006541{
6542#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006543 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006544 struct wiphy_wowlan_support *wowl;
6545
6546 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6547 GFP_KERNEL);
6548 if (!wowl) {
6549 brcmf_err("only support basic wowlan features\n");
6550 wiphy->wowlan = &brcmf_wowlan_support;
6551 return;
6552 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006553
6554 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006555 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006556 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6557 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006558 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006559 }
6560 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006561 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006562 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6563 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006564 }
6565
Arend Van Spriel0b570102017-01-27 12:27:47 +00006566 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006567#endif
6568}
6569
Arend van Sprielb48d8912014-07-12 08:49:41 +02006570static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006571{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006572 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006573 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006574 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006575 u16 max_interfaces = 0;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006576 bool gscan;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006577 __le32 bandlist[3];
6578 u32 n_bands;
6579 int err, i;
6580
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006581 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6582 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006583 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006584
6585 err = brcmf_setup_ifmodes(wiphy, ifp);
6586 if (err)
6587 return err;
6588
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006589 for (i = 0, combo = wiphy->iface_combinations;
6590 i < wiphy->n_iface_combinations; i++, combo++) {
6591 max_interfaces = max(max_interfaces, combo->max_interfaces);
6592 }
6593
6594 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6595 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006596 u8 *addr = drvr->addresses[i].addr;
6597
6598 memcpy(addr, drvr->mac, ETH_ALEN);
6599 if (i) {
6600 addr[0] |= BIT(1);
6601 addr[ETH_ALEN - 1] ^= i;
6602 }
6603 }
6604 wiphy->addresses = drvr->addresses;
6605 wiphy->n_addresses = i;
6606
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006607 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006608 wiphy->cipher_suites = brcmf_cipher_suites;
6609 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6610 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6611 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006612 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6613 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6614 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6615
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006616 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6617 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006618 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006619 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6620 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6621 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006622 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006623 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
Arend van Spriel2526ff22017-06-09 13:08:48 +01006624 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01006625 wiphy_ext_feature_set(wiphy,
6626 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
Arend van Spriel2526ff22017-06-09 13:08:48 +01006627 wiphy_ext_feature_set(wiphy,
6628 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
6629 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006630 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6631 wiphy->max_remain_on_channel_duration = 5000;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006632 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
6633 gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
6634 brcmf_pno_wiphy_params(wiphy, gscan);
6635 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006636 /* vendor commands/events support */
6637 wiphy->vendor_commands = brcmf_vendor_cmds;
6638 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6639
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006640 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006641 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006642 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6643 sizeof(bandlist));
6644 if (err) {
6645 brcmf_err("could not obtain band info: err=%d\n", err);
6646 return err;
6647 }
6648 /* first entry in bandlist is number of bands */
6649 n_bands = le32_to_cpu(bandlist[0]);
6650 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6651 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6652 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6653 GFP_KERNEL);
6654 if (!band)
6655 return -ENOMEM;
6656
6657 band->channels = kmemdup(&__wl_2ghz_channels,
6658 sizeof(__wl_2ghz_channels),
6659 GFP_KERNEL);
6660 if (!band->channels) {
6661 kfree(band);
6662 return -ENOMEM;
6663 }
6664
6665 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006666 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006667 }
6668 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6669 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6670 GFP_KERNEL);
6671 if (!band)
6672 return -ENOMEM;
6673
6674 band->channels = kmemdup(&__wl_5ghz_channels,
6675 sizeof(__wl_5ghz_channels),
6676 GFP_KERNEL);
6677 if (!band->channels) {
6678 kfree(band);
6679 return -ENOMEM;
6680 }
6681
6682 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006683 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006684 }
6685 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006686
6687 wiphy_read_of_freq_limits(wiphy);
6688
Rafał Miłeckiab990632017-01-07 21:36:05 +01006689 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006690}
6691
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006692static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006693{
6694 struct net_device *ndev;
6695 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006696 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006697 s32 power_mode;
6698 s32 err = 0;
6699
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006700 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006701 return err;
6702
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006703 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006704 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006705 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006706
Hante Meuleman40a23292013-01-02 15:22:51 +01006707 /* make sure RF is ready for work */
6708 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6709
Hante Meuleman1678ba82015-12-10 13:43:00 +01006710 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006711
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006712 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006713 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006714 if (err)
6715 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006716 brcmf_dbg(INFO, "power save set to %s\n",
6717 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006718
Hante Meuleman1119e232015-11-25 11:32:42 +01006719 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006720 if (err)
6721 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006722 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006723 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006724 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006725 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006726
Franky Lin52f22fb2016-02-17 11:26:55 +01006727 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006728
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006729 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006730default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006731
6732 return err;
6733
6734}
6735
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006736static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006737{
Arend van Sprielc1179032012-10-22 13:55:33 -07006738 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006739
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006740 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006741}
6742
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006743static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006744{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006745 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006746
Arend van Spriel5b435de2011-10-05 13:19:03 +02006747 /*
6748 * While going down, if associated with AP disassociate
6749 * from AP to save power
6750 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006751 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006752 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006753
6754 /* Make sure WPA_Supplicant receives all the event
6755 generated due to DISASSOC call to the fw to keep
6756 the state fw and WPA_Supplicant state consistent
6757 */
6758 brcmf_delay(500);
6759 }
6760
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006761 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006762 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006763
Arend van Spriel5b435de2011-10-05 13:19:03 +02006764 return 0;
6765}
6766
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006767s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006768{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006769 struct brcmf_if *ifp = netdev_priv(ndev);
6770 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006771 s32 err = 0;
6772
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006773 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006774 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006775 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006776
6777 return err;
6778}
6779
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006780s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006781{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006782 struct brcmf_if *ifp = netdev_priv(ndev);
6783 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006784 s32 err = 0;
6785
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006786 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006787 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006788 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006789
6790 return err;
6791}
6792
Arend van Spriela7965fb2013-04-11 17:08:37 +02006793enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6794{
6795 struct wireless_dev *wdev = &ifp->vif->wdev;
6796
6797 return wdev->iftype;
6798}
6799
Hante Meulemanbfe81972014-10-28 14:56:16 +01006800bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6801 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006802{
6803 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006804
6805 list_for_each_entry(vif, &cfg->vif_list, list) {
6806 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006807 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006808 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006809 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006810}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006811
6812static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6813 u8 action)
6814{
6815 u8 evt_action;
6816
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006817 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006818 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006819 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006820 return evt_action == action;
6821}
6822
6823void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6824 struct brcmf_cfg80211_vif *vif)
6825{
6826 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6827
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006828 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006829 event->vif = vif;
6830 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006831 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006832}
6833
6834bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6835{
6836 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6837 bool armed;
6838
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006839 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006840 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006841 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006842
6843 return armed;
6844}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006845
6846int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6847 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006848{
6849 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6850
6851 return wait_event_timeout(event->vif_wq,
6852 vif_event_equals(event, action), timeout);
6853}
6854
Hante Meuleman73345fd2016-02-17 11:26:53 +01006855static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6856 struct brcmf_fil_country_le *ccreq)
6857{
Hante Meuleman4d792892016-02-17 11:27:07 +01006858 struct brcmfmac_pd_cc *country_codes;
6859 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006860 s32 found_index;
6861 int i;
6862
6863 country_codes = drvr->settings->country_codes;
6864 if (!country_codes) {
6865 brcmf_dbg(TRACE, "No country codes configured for device\n");
6866 return -EINVAL;
6867 }
6868
6869 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6870 (alpha2[1] == ccreq->country_abbrev[1])) {
6871 brcmf_dbg(TRACE, "Country code already set\n");
6872 return -EAGAIN;
6873 }
6874
6875 found_index = -1;
6876 for (i = 0; i < country_codes->table_size; i++) {
6877 cc = &country_codes->table[i];
6878 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6879 found_index = i;
6880 if ((cc->iso3166[0] == alpha2[0]) &&
6881 (cc->iso3166[1] == alpha2[1])) {
6882 found_index = i;
6883 break;
6884 }
6885 }
6886 if (found_index == -1) {
6887 brcmf_dbg(TRACE, "No country code match found\n");
6888 return -EINVAL;
6889 }
6890 memset(ccreq, 0, sizeof(*ccreq));
6891 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6892 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6893 BRCMF_COUNTRY_BUF_SZ);
6894 ccreq->country_abbrev[0] = alpha2[0];
6895 ccreq->country_abbrev[1] = alpha2[1];
6896 ccreq->country_abbrev[2] = 0;
6897
6898 return 0;
6899}
6900
Arend van Spriel63db1a42014-12-21 12:43:51 +01006901static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6902 struct regulatory_request *req)
6903{
6904 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6905 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6906 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006907 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006908 int i;
6909
Hans de Goede26e537882017-03-08 14:50:16 +01006910 /* The country code gets set to "00" by default at boot, ignore */
6911 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6912 return;
6913
Arend van Spriel63db1a42014-12-21 12:43:51 +01006914 /* ignore non-ISO3166 country codes */
6915 for (i = 0; i < sizeof(req->alpha2); i++)
6916 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Martin Michlmayra9507d52017-06-10 11:40:04 +02006917 brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
Hante Meuleman73345fd2016-02-17 11:26:53 +01006918 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006919 return;
6920 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006921
6922 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6923 req->alpha2[0], req->alpha2[1]);
6924
6925 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6926 if (err) {
6927 brcmf_err("Country code iovar returned err = %d\n", err);
6928 return;
6929 }
6930
6931 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6932 if (err)
6933 return;
6934
6935 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6936 if (err) {
6937 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006938 return;
6939 }
6940 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006941}
6942
Arend van Sprielb48d8912014-07-12 08:49:41 +02006943static void brcmf_free_wiphy(struct wiphy *wiphy)
6944{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006945 int i;
6946
Arend van Spriel58de92d2015-04-14 20:10:24 +02006947 if (!wiphy)
6948 return;
6949
Arend van Spriel0882dda2015-08-20 22:06:03 +02006950 if (wiphy->iface_combinations) {
6951 for (i = 0; i < wiphy->n_iface_combinations; i++)
6952 kfree(wiphy->iface_combinations[i].limits);
6953 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006954 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006955 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6956 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6957 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006958 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006959 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6960 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6961 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006962 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006963#if IS_ENABLED(CONFIG_PM)
6964 if (wiphy->wowlan != &brcmf_wowlan_support)
6965 kfree(wiphy->wowlan);
6966#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006967 wiphy_free(wiphy);
6968}
6969
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006970struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006971 struct device *busdev,
6972 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006973{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006974 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006975 struct brcmf_cfg80211_info *cfg;
6976 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006977 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006978 struct brcmf_cfg80211_vif *vif;
6979 struct brcmf_if *ifp;
6980 s32 err = 0;
6981 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006982 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006983
6984 if (!ndev) {
6985 brcmf_err("ndev is invalid\n");
6986 return NULL;
6987 }
6988
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306989 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006990 if (!ops)
6991 return NULL;
6992
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006993 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006994#ifdef CONFIG_PM
6995 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6996 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6997#endif
6998 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006999 if (!wiphy) {
7000 brcmf_err("Could not allocate wiphy device\n");
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007001 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007002 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02007003 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007004 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007005
7006 cfg = wiphy_priv(wiphy);
7007 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007008 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007009 cfg->pub = drvr;
7010 init_vif_event(&cfg->vif_event);
7011 INIT_LIST_HEAD(&cfg->vif_list);
7012
Rafał Miłecki26072332016-06-06 23:03:55 +02007013 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007014 if (IS_ERR(vif))
7015 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007016
7017 vif->ifp = ifp;
7018 vif->wdev.netdev = ndev;
7019 ndev->ieee80211_ptr = &vif->wdev;
7020 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
7021
7022 err = wl_init_priv(cfg);
7023 if (err) {
7024 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007025 brcmf_free_vif(vif);
7026 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007027 }
7028 ifp->vif = vif;
7029
Arend van Sprielb48d8912014-07-12 08:49:41 +02007030 /* determine d11 io type before wiphy setup */
7031 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007032 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02007033 brcmf_err("Failed to get D11 version (%d)\n", err);
7034 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007035 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007036 cfg->d11inf.io_type = (u8)io_type;
7037 brcmu_d11_attach(&cfg->d11inf);
7038
7039 err = brcmf_setup_wiphy(wiphy, ifp);
7040 if (err < 0)
7041 goto priv_out;
7042
7043 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01007044 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007045 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
7046 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
7047
7048 /* firmware defaults to 40MHz disabled in 2G band. We signal
7049 * cfg80211 here that we do and have it decide we can enable
7050 * it. But first check if device does support 2G operation.
7051 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007052 if (wiphy->bands[NL80211_BAND_2GHZ]) {
7053 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007054 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
7055 }
7056 err = wiphy_register(wiphy);
7057 if (err < 0) {
7058 brcmf_err("Could not register wiphy device (%d)\n", err);
7059 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007060 }
7061
Rafał Miłeckiab990632017-01-07 21:36:05 +01007062 err = brcmf_setup_wiphybands(wiphy);
7063 if (err) {
7064 brcmf_err("Setting wiphy bands failed (%d)\n", err);
7065 goto wiphy_unreg_out;
7066 }
7067
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007068 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
7069 * setup 40MHz in 2GHz band and enable OBSS scanning.
7070 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02007071 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
7072 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007073 if (!err)
7074 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
7075 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007076 else
7077 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007078 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007079 /* p2p might require that "if-events" get processed by fweh. So
7080 * activate the already registered event handlers now and activate
7081 * the rest when initialization has completed. drvr->config needs to
7082 * be assigned before activating events.
7083 */
7084 drvr->config = cfg;
7085 err = brcmf_fweh_activate_events(ifp);
7086 if (err) {
7087 brcmf_err("FWEH activation failed (%d)\n", err);
7088 goto wiphy_unreg_out;
7089 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007090
Hante Meulemanae7c03f2015-09-18 22:08:08 +02007091 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007092 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007093 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007094 goto wiphy_unreg_out;
7095 }
7096 err = brcmf_btcoex_attach(cfg);
7097 if (err) {
7098 brcmf_err("BT-coex initialisation failed (%d)\n", err);
7099 brcmf_p2p_detach(&cfg->p2p);
7100 goto wiphy_unreg_out;
7101 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007102 err = brcmf_pno_attach(cfg);
7103 if (err) {
7104 brcmf_err("PNO initialisation failed (%d)\n", err);
7105 brcmf_btcoex_detach(cfg);
7106 brcmf_p2p_detach(&cfg->p2p);
7107 goto wiphy_unreg_out;
7108 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007109
Hante Meulemana7b82d42015-12-10 13:43:04 +01007110 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
7111 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
7112 if (err) {
7113 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
7114 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
7115 } else {
7116 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
7117 brcmf_notify_tdls_peer_event);
7118 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007119 }
7120
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007121 /* (re-) activate FWEH event handling */
7122 err = brcmf_fweh_activate_events(ifp);
7123 if (err) {
7124 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007125 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007126 }
7127
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007128 /* Fill in some of the advertised nl80211 supported features */
7129 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7130 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7131#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007132 if (wiphy->wowlan &&
7133 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007134 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7135#endif
7136 }
7137
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007138 return cfg;
7139
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007140detach:
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007141 brcmf_pno_detach(cfg);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007142 brcmf_btcoex_detach(cfg);
7143 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007144wiphy_unreg_out:
7145 wiphy_unregister(cfg->wiphy);
7146priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007147 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007148 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007149 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007150wiphy_out:
7151 brcmf_free_wiphy(wiphy);
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007152ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007153 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007154 return NULL;
7155}
7156
7157void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7158{
7159 if (!cfg)
7160 return;
7161
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007162 brcmf_pno_detach(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007163 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007164 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007165 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007166 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007167 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007168}