blob: dcde596c9eb9c3fa875c2675318f0298e118549a [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;
3943
3944 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003945 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003946 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003947 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 return err;
3949 }
3950 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003951 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003952 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003953 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003954 return err;
3955 }
3956 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003957 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003958 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003959 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003960 return err;
3961 }
3962
3963 return 0;
3964}
3965
3966static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3967{
3968 if (is_rsn_ie)
3969 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3970
3971 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3972}
3973
3974static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003975brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003976 const struct brcmf_vs_tlv *wpa_ie,
3977 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003978{
3979 u32 auth = 0; /* d11 open authentication */
3980 u16 count;
3981 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003982 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003983 u32 i;
3984 u32 wsec;
3985 u32 pval = 0;
3986 u32 gval = 0;
3987 u32 wpa_auth = 0;
3988 u32 offset;
3989 u8 *data;
3990 u16 rsn_cap;
3991 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003992 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003993
Arend van Sprield96b8012012-12-05 15:26:02 +01003994 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003995 if (wpa_ie == NULL)
3996 goto exit;
3997
3998 len = wpa_ie->len + TLV_HDR_LEN;
3999 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004000 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004001 if (!is_rsn_ie)
4002 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004003 else
4004 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004005
4006 /* check for multicast cipher suite */
4007 if (offset + WPA_IE_MIN_OUI_LEN > len) {
4008 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004009 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004010 goto exit;
4011 }
4012
4013 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4014 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004015 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004016 goto exit;
4017 }
4018 offset += TLV_OUI_LEN;
4019
4020 /* pick up multicast cipher */
4021 switch (data[offset]) {
4022 case WPA_CIPHER_NONE:
4023 gval = 0;
4024 break;
4025 case WPA_CIPHER_WEP_40:
4026 case WPA_CIPHER_WEP_104:
4027 gval = WEP_ENABLED;
4028 break;
4029 case WPA_CIPHER_TKIP:
4030 gval = TKIP_ENABLED;
4031 break;
4032 case WPA_CIPHER_AES_CCM:
4033 gval = AES_ENABLED;
4034 break;
4035 default:
4036 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004037 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004038 goto exit;
4039 }
4040
4041 offset++;
4042 /* walk thru unicast cipher list and pick up what we recognize */
4043 count = data[offset] + (data[offset + 1] << 8);
4044 offset += WPA_IE_SUITE_COUNT_LEN;
4045 /* Check for unicast suite(s) */
4046 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4047 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004048 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004049 goto exit;
4050 }
4051 for (i = 0; i < count; i++) {
4052 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4053 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004054 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004055 goto exit;
4056 }
4057 offset += TLV_OUI_LEN;
4058 switch (data[offset]) {
4059 case WPA_CIPHER_NONE:
4060 break;
4061 case WPA_CIPHER_WEP_40:
4062 case WPA_CIPHER_WEP_104:
4063 pval |= WEP_ENABLED;
4064 break;
4065 case WPA_CIPHER_TKIP:
4066 pval |= TKIP_ENABLED;
4067 break;
4068 case WPA_CIPHER_AES_CCM:
4069 pval |= AES_ENABLED;
4070 break;
4071 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004072 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004073 }
4074 offset++;
4075 }
4076 /* walk thru auth management suite list and pick up what we recognize */
4077 count = data[offset] + (data[offset + 1] << 8);
4078 offset += WPA_IE_SUITE_COUNT_LEN;
4079 /* Check for auth key management suite(s) */
4080 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4081 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004082 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004083 goto exit;
4084 }
4085 for (i = 0; i < count; i++) {
4086 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4087 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004088 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004089 goto exit;
4090 }
4091 offset += TLV_OUI_LEN;
4092 switch (data[offset]) {
4093 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004094 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004095 wpa_auth |= WPA_AUTH_NONE;
4096 break;
4097 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004098 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004099 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4100 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4101 break;
4102 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004103 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004104 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4105 (wpa_auth |= WPA_AUTH_PSK);
4106 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004107 case RSN_AKM_SHA256_PSK:
4108 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4109 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4110 break;
4111 case RSN_AKM_SHA256_1X:
4112 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4113 wpa_auth |= WPA2_AUTH_1X_SHA256;
4114 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004115 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004116 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004117 }
4118 offset++;
4119 }
4120
Hante Meuleman240d61a2016-02-17 11:27:10 +01004121 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004122 if (is_rsn_ie) {
4123 wme_bss_disable = 1;
4124 if ((offset + RSN_CAP_LEN) <= len) {
4125 rsn_cap = data[offset] + (data[offset + 1] << 8);
4126 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4127 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004128 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4129 brcmf_dbg(TRACE, "MFP Required\n");
4130 mfp = BRCMF_MFP_REQUIRED;
4131 /* Firmware only supports mfp required in
4132 * combination with WPA2_AUTH_PSK_SHA256 or
4133 * WPA2_AUTH_1X_SHA256.
4134 */
4135 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4136 WPA2_AUTH_1X_SHA256))) {
4137 err = -EINVAL;
4138 goto exit;
4139 }
4140 /* Firmware has requirement that WPA2_AUTH_PSK/
4141 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4142 * is to be included in the rsn ie.
4143 */
4144 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4145 wpa_auth |= WPA2_AUTH_PSK;
4146 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4147 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4148 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4149 brcmf_dbg(TRACE, "MFP Capable\n");
4150 mfp = BRCMF_MFP_CAPABLE;
4151 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004152 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004153 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004154 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004155 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004156 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004157 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004158 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004159 goto exit;
4160 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004161
4162 /* Skip PMKID cnt as it is know to be 0 for AP. */
4163 offset += RSN_PMKID_COUNT_LEN;
4164
4165 /* See if there is BIP wpa suite left for MFP */
4166 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4167 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4168 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4169 &data[offset],
4170 WPA_IE_MIN_OUI_LEN);
4171 if (err < 0) {
4172 brcmf_err("bip error %d\n", err);
4173 goto exit;
4174 }
4175 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004176 }
4177 /* FOR WPS , set SES_OW_ENABLED */
4178 wsec = (pval | gval | SES_OW_ENABLED);
4179
4180 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004181 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004182 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004183 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004184 goto exit;
4185 }
4186 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004187 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004188 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004189 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004190 goto exit;
4191 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004192 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4193 * will overwrite the values set by MFP
4194 */
4195 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4196 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4197 if (err < 0) {
4198 brcmf_err("mfp error %d\n", err);
4199 goto exit;
4200 }
4201 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004202 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004203 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004204 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004205 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004206 goto exit;
4207 }
4208
4209exit:
4210 return err;
4211}
4212
4213static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004214brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004215 struct parsed_vndr_ies *vndr_ies)
4216{
Hante Meuleman1a873342012-09-27 14:17:54 +02004217 struct brcmf_vs_tlv *vndrie;
4218 struct brcmf_tlv *ie;
4219 struct parsed_vndr_ie_info *parsed_info;
4220 s32 remaining_len;
4221
4222 remaining_len = (s32)vndr_ie_len;
4223 memset(vndr_ies, 0, sizeof(*vndr_ies));
4224
4225 ie = (struct brcmf_tlv *)vndr_ie_buf;
4226 while (ie) {
4227 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4228 goto next;
4229 vndrie = (struct brcmf_vs_tlv *)ie;
4230 /* len should be bigger than OUI length + one */
4231 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004232 brcmf_err("invalid vndr ie. length is too small %d\n",
4233 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004234 goto next;
4235 }
4236 /* if wpa or wme ie, do not add ie */
4237 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4238 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4239 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004240 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004241 goto next;
4242 }
4243
4244 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4245
4246 /* save vndr ie information */
4247 parsed_info->ie_ptr = (char *)vndrie;
4248 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4249 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4250
4251 vndr_ies->count++;
4252
Arend van Sprield96b8012012-12-05 15:26:02 +01004253 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4254 parsed_info->vndrie.oui[0],
4255 parsed_info->vndrie.oui[1],
4256 parsed_info->vndrie.oui[2],
4257 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004258
Arend van Spriel9f440b72013-02-08 15:53:36 +01004259 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004260 break;
4261next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004262 remaining_len -= (ie->len + TLV_HDR_LEN);
4263 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004264 ie = NULL;
4265 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004266 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4267 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004268 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004269 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004270}
4271
4272static u32
4273brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4274{
4275
Hante Meuleman1a873342012-09-27 14:17:54 +02004276 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4277 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4278
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304279 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004280
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304281 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004282
4283 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4284
4285 return ie_len + VNDR_IE_HDR_SIZE;
4286}
4287
Arend van Spriel1332e262012-11-05 16:22:18 -08004288s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4289 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004290{
Arend van Spriel1332e262012-11-05 16:22:18 -08004291 struct brcmf_if *ifp;
4292 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004293 s32 err = 0;
4294 u8 *iovar_ie_buf;
4295 u8 *curr_ie_buf;
4296 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004297 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004298 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004299 u32 del_add_ie_buf_len = 0;
4300 u32 total_ie_buf_len = 0;
4301 u32 parsed_ie_buf_len = 0;
4302 struct parsed_vndr_ies old_vndr_ies;
4303 struct parsed_vndr_ies new_vndr_ies;
4304 struct parsed_vndr_ie_info *vndrie_info;
4305 s32 i;
4306 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004307 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004308
Arend van Spriel1332e262012-11-05 16:22:18 -08004309 if (!vif)
4310 return -ENODEV;
4311 ifp = vif->ifp;
4312 saved_ie = &vif->saved_ie;
4313
Hante Meuleman37a869e2015-10-29 20:33:17 +01004314 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4315 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004316 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4317 if (!iovar_ie_buf)
4318 return -ENOMEM;
4319 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004320 switch (pktflag) {
4321 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4322 mgmt_ie_buf = saved_ie->probe_req_ie;
4323 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4324 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4325 break;
4326 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4327 mgmt_ie_buf = saved_ie->probe_res_ie;
4328 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4329 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4330 break;
4331 case BRCMF_VNDR_IE_BEACON_FLAG:
4332 mgmt_ie_buf = saved_ie->beacon_ie;
4333 mgmt_ie_len = &saved_ie->beacon_ie_len;
4334 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4335 break;
4336 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4337 mgmt_ie_buf = saved_ie->assoc_req_ie;
4338 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4339 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4340 break;
4341 default:
4342 err = -EPERM;
4343 brcmf_err("not suitable type\n");
4344 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004345 }
4346
4347 if (vndr_ie_len > mgmt_ie_buf_len) {
4348 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004349 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004350 goto exit;
4351 }
4352
4353 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4354 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4355 ptr = curr_ie_buf;
4356 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4357 for (i = 0; i < new_vndr_ies.count; i++) {
4358 vndrie_info = &new_vndr_ies.ie_info[i];
4359 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4360 vndrie_info->ie_len);
4361 parsed_ie_buf_len += vndrie_info->ie_len;
4362 }
4363 }
4364
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004365 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004366 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4367 (memcmp(mgmt_ie_buf, curr_ie_buf,
4368 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004369 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004370 goto exit;
4371 }
4372
4373 /* parse old vndr_ie */
4374 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4375
4376 /* make a command to delete old ie */
4377 for (i = 0; i < old_vndr_ies.count; i++) {
4378 vndrie_info = &old_vndr_ies.ie_info[i];
4379
Arend van Sprield96b8012012-12-05 15:26:02 +01004380 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4381 vndrie_info->vndrie.id,
4382 vndrie_info->vndrie.len,
4383 vndrie_info->vndrie.oui[0],
4384 vndrie_info->vndrie.oui[1],
4385 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004386
4387 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4388 vndrie_info->ie_ptr,
4389 vndrie_info->ie_len,
4390 "del");
4391 curr_ie_buf += del_add_ie_buf_len;
4392 total_ie_buf_len += del_add_ie_buf_len;
4393 }
4394 }
4395
4396 *mgmt_ie_len = 0;
4397 /* Add if there is any extra IE */
4398 if (mgmt_ie_buf && parsed_ie_buf_len) {
4399 ptr = mgmt_ie_buf;
4400
4401 remained_buf_len = mgmt_ie_buf_len;
4402
4403 /* make a command to add new ie */
4404 for (i = 0; i < new_vndr_ies.count; i++) {
4405 vndrie_info = &new_vndr_ies.ie_info[i];
4406
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004407 /* verify remained buf size before copy data */
4408 if (remained_buf_len < (vndrie_info->vndrie.len +
4409 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004410 brcmf_err("no space in mgmt_ie_buf: len left %d",
4411 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004412 break;
4413 }
4414 remained_buf_len -= (vndrie_info->ie_len +
4415 VNDR_IE_VSIE_OFFSET);
4416
Arend van Sprield96b8012012-12-05 15:26:02 +01004417 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4418 vndrie_info->vndrie.id,
4419 vndrie_info->vndrie.len,
4420 vndrie_info->vndrie.oui[0],
4421 vndrie_info->vndrie.oui[1],
4422 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004423
4424 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4425 vndrie_info->ie_ptr,
4426 vndrie_info->ie_len,
4427 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004428
4429 /* save the parsed IE in wl struct */
4430 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4431 vndrie_info->ie_len);
4432 *mgmt_ie_len += vndrie_info->ie_len;
4433
4434 curr_ie_buf += del_add_ie_buf_len;
4435 total_ie_buf_len += del_add_ie_buf_len;
4436 }
4437 }
4438 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004439 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004440 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004441 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004442 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004443 }
4444
4445exit:
4446 kfree(iovar_ie_buf);
4447 return err;
4448}
4449
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004450s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4451{
4452 s32 pktflags[] = {
4453 BRCMF_VNDR_IE_PRBREQ_FLAG,
4454 BRCMF_VNDR_IE_PRBRSP_FLAG,
4455 BRCMF_VNDR_IE_BEACON_FLAG
4456 };
4457 int i;
4458
4459 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4460 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4461
4462 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4463 return 0;
4464}
4465
Hante Meuleman1a873342012-09-27 14:17:54 +02004466static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004467brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4468 struct cfg80211_beacon_data *beacon)
4469{
4470 s32 err;
4471
4472 /* Set Beacon IEs to FW */
4473 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4474 beacon->tail, beacon->tail_len);
4475 if (err) {
4476 brcmf_err("Set Beacon IE Failed\n");
4477 return err;
4478 }
4479 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4480
4481 /* Set Probe Response IEs to FW */
4482 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4483 beacon->proberesp_ies,
4484 beacon->proberesp_ies_len);
4485 if (err)
4486 brcmf_err("Set Probe Resp IE Failed\n");
4487 else
4488 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4489
4490 return err;
4491}
4492
4493static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004494brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4495 struct cfg80211_ap_settings *settings)
4496{
4497 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004498 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004499 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004500 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004501 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004502 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004503 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004504 const struct brcmf_tlv *rsn_ie;
4505 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004506 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004507 enum nl80211_iftype dev_role;
4508 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004509 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004510 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004511 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004512 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004513
Arend van Spriel06c01582014-05-12 10:47:37 +02004514 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4515 settings->chandef.chan->hw_value,
4516 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004517 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004518 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4519 settings->ssid, settings->ssid_len, settings->auth_type,
4520 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004521 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004522 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004523
Arend van Spriel98027762014-12-21 12:43:53 +01004524 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004525 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4526 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004527 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004528 } else {
4529 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4530 settings->beacon.tail_len,
4531 WLAN_EID_COUNTRY);
4532 is_11d = country_ie ? 1 : 0;
4533 supports_11d = true;
4534 }
Arend van Spriel98027762014-12-21 12:43:53 +01004535
Hante Meuleman1a873342012-09-27 14:17:54 +02004536 memset(&ssid_le, 0, sizeof(ssid_le));
4537 if (settings->ssid == NULL || settings->ssid_len == 0) {
4538 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4539 ssid_ie = brcmf_parse_tlvs(
4540 (u8 *)&settings->beacon.head[ie_offset],
4541 settings->beacon.head_len - ie_offset,
4542 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004543 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004544 return -EINVAL;
4545
4546 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4547 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004548 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004549 } else {
4550 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4551 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4552 }
4553
Hante Meulemana44aa402014-12-03 21:05:33 +01004554 if (!mbss) {
4555 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004556 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004557 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004558
4559 /* find the RSN_IE */
4560 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4561 settings->beacon.tail_len, WLAN_EID_RSN);
4562
4563 /* find the WPA_IE */
4564 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4565 settings->beacon.tail_len);
4566
Hante Meuleman1a873342012-09-27 14:17:54 +02004567 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004568 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004569 if (wpa_ie != NULL) {
4570 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004571 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004572 if (err < 0)
4573 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004575 struct brcmf_vs_tlv *tmp_ie;
4576
4577 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4578
Hante Meuleman1a873342012-09-27 14:17:54 +02004579 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004580 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004581 if (err < 0)
4582 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004583 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004584 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004585 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004586 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004587 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004588
Rafał Miłecki8707e082016-05-27 21:07:19 +02004589 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004590 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004591 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004592 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4593 is_11d);
4594 if (err < 0) {
4595 brcmf_err("Regulatory Set Error, %d\n", err);
4596 goto exit;
4597 }
4598 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004599 if (settings->beacon_interval) {
4600 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4601 settings->beacon_interval);
4602 if (err < 0) {
4603 brcmf_err("Beacon Interval Set Error, %d\n",
4604 err);
4605 goto exit;
4606 }
4607 }
4608 if (settings->dtim_period) {
4609 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4610 settings->dtim_period);
4611 if (err < 0) {
4612 brcmf_err("DTIM Interval Set Error, %d\n", err);
4613 goto exit;
4614 }
4615 }
4616
Hante Meuleman8abffd82015-10-29 20:33:16 +01004617 if ((dev_role == NL80211_IFTYPE_AP) &&
4618 ((ifp->ifidx == 0) ||
4619 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004620 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4621 if (err < 0) {
4622 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4623 goto exit;
4624 }
4625 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4626 }
4627
4628 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004629 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004630 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004631 goto exit;
4632 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004633 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004634 /* Multiple-BSS should use same 11d configuration */
4635 err = -EINVAL;
4636 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004637 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004638
4639 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004640 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004641 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4642 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4643
Hante Meulemana0f07952013-02-08 15:53:47 +01004644 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4645 if (err < 0) {
4646 brcmf_err("setting AP mode failed %d\n", err);
4647 goto exit;
4648 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004649 if (!mbss) {
4650 /* Firmware 10.x requires setting channel after enabling
4651 * AP and before bringing interface up.
4652 */
4653 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4654 if (err < 0) {
4655 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4656 chanspec, err);
4657 goto exit;
4658 }
4659 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004660 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4661 if (err < 0) {
4662 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4663 goto exit;
4664 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004665 /* On DOWN the firmware removes the WEP keys, reconfigure
4666 * them if they were set.
4667 */
4668 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004669
4670 memset(&join_params, 0, sizeof(join_params));
4671 /* join parameters starts with ssid */
4672 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4673 /* create softap */
4674 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4675 &join_params, sizeof(join_params));
4676 if (err < 0) {
4677 brcmf_err("SET SSID error (%d)\n", err);
4678 goto exit;
4679 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004680
4681 if (settings->hidden_ssid) {
4682 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4683 if (err) {
4684 brcmf_err("closednet error (%d)\n", err);
4685 goto exit;
4686 }
4687 }
4688
Hante Meulemana0f07952013-02-08 15:53:47 +01004689 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004690 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4691 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4692 if (err < 0) {
4693 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4694 chanspec, err);
4695 goto exit;
4696 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004697 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4698 sizeof(ssid_le));
4699 if (err < 0) {
4700 brcmf_err("setting ssid failed %d\n", err);
4701 goto exit;
4702 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004703 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004704 bss_enable.enable = cpu_to_le32(1);
4705 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4706 sizeof(bss_enable));
4707 if (err < 0) {
4708 brcmf_err("bss_enable config failed %d\n", err);
4709 goto exit;
4710 }
4711
4712 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004713 } else {
4714 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004715 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004716
Wright Fengf25ba692016-11-18 09:59:52 +08004717 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004718 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004719 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004720
4721exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004722 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004723 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004724 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004725 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004726 return err;
4727}
4728
4729static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4730{
Arend van Sprielc1179032012-10-22 13:55:33 -07004731 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004732 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004733 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004734 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004735
Arend van Sprield96b8012012-12-05 15:26:02 +01004736 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004737
Hante Meuleman426d0a52013-02-08 15:53:53 +01004738 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004739 /* Due to most likely deauths outstanding we sleep */
4740 /* first to make sure they get processed by fw. */
4741 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004742
Hante Meulemana44aa402014-12-03 21:05:33 +01004743 if (ifp->vif->mbss) {
4744 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4745 return err;
4746 }
4747
Rafał Miłeckic940de12016-07-06 12:22:54 +02004748 /* First BSS doesn't get a full reset */
4749 if (ifp->bsscfgidx == 0)
4750 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4751
Hante Meuleman5c33a942013-04-02 21:06:18 +02004752 memset(&join_params, 0, sizeof(join_params));
4753 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4754 &join_params, sizeof(join_params));
4755 if (err < 0)
4756 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004757 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004758 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004759 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004760 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4761 if (err < 0)
4762 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004763 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4764 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004765 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4766 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004767 /* Bring device back up so it can be used again */
4768 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4769 if (err < 0)
4770 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004771
4772 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004773 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004774 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004775 bss_enable.enable = cpu_to_le32(0);
4776 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4777 sizeof(bss_enable));
4778 if (err < 0)
4779 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004780 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004781 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004782 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004783 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004784 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004785
Hante Meuleman1a873342012-09-27 14:17:54 +02004786 return err;
4787}
4788
Hante Meulemana0f07952013-02-08 15:53:47 +01004789static s32
4790brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4791 struct cfg80211_beacon_data *info)
4792{
Hante Meulemana0f07952013-02-08 15:53:47 +01004793 struct brcmf_if *ifp = netdev_priv(ndev);
4794 s32 err;
4795
4796 brcmf_dbg(TRACE, "Enter\n");
4797
Hante Meulemana0f07952013-02-08 15:53:47 +01004798 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4799
4800 return err;
4801}
4802
Hante Meuleman1a873342012-09-27 14:17:54 +02004803static int
4804brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004805 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004806{
Hante Meulemana0f07952013-02-08 15:53:47 +01004807 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004808 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004809 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004810 s32 err;
4811
Jouni Malinen89c771e2014-10-10 20:52:40 +03004812 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004813 return -EFAULT;
4814
Jouni Malinen89c771e2014-10-10 20:52:40 +03004815 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004816
Hante Meulemana0f07952013-02-08 15:53:47 +01004817 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4818 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004819 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004820 return -EIO;
4821
Jouni Malinen89c771e2014-10-10 20:52:40 +03004822 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004823 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004824 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004825 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004826 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004827 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004828
Arend van Sprield96b8012012-12-05 15:26:02 +01004829 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004830 return err;
4831}
4832
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004833static int
4834brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4835 const u8 *mac, struct station_parameters *params)
4836{
4837 struct brcmf_if *ifp = netdev_priv(ndev);
4838 s32 err;
4839
4840 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4841 params->sta_flags_mask, params->sta_flags_set);
4842
4843 /* Ignore all 00 MAC */
4844 if (is_zero_ether_addr(mac))
4845 return 0;
4846
4847 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4848 return 0;
4849
4850 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4852 (void *)mac, ETH_ALEN);
4853 else
4854 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4855 (void *)mac, ETH_ALEN);
4856 if (err < 0)
4857 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4858
4859 return err;
4860}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004861
4862static void
4863brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4864 struct wireless_dev *wdev,
4865 u16 frame_type, bool reg)
4866{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004867 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004868 u16 mgmt_type;
4869
4870 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4871
4872 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004873 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004874 if (reg)
4875 vif->mgmt_rx_reg |= BIT(mgmt_type);
4876 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004877 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004878}
4879
4880
4881static int
4882brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004883 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004884{
4885 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004886 struct ieee80211_channel *chan = params->chan;
4887 const u8 *buf = params->buf;
4888 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004889 const struct ieee80211_mgmt *mgmt;
4890 struct brcmf_cfg80211_vif *vif;
4891 s32 err = 0;
4892 s32 ie_offset;
4893 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004894 struct brcmf_fil_action_frame_le *action_frame;
4895 struct brcmf_fil_af_params_le *af_params;
4896 bool ack;
4897 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004898 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004899
4900 brcmf_dbg(TRACE, "Enter\n");
4901
4902 *cookie = 0;
4903
4904 mgmt = (const struct ieee80211_mgmt *)buf;
4905
Hante Meulemana0f07952013-02-08 15:53:47 +01004906 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4907 brcmf_err("Driver only allows MGMT packet type\n");
4908 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004909 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004910
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004911 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4912
Hante Meulemana0f07952013-02-08 15:53:47 +01004913 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4914 /* Right now the only reason to get a probe response */
4915 /* is for p2p listen response or for p2p GO from */
4916 /* wpa_supplicant. Unfortunately the probe is send */
4917 /* on primary ndev, while dongle wants it on the p2p */
4918 /* vif. Since this is only reason for a probe */
4919 /* response to be sent, the vif is taken from cfg. */
4920 /* If ever desired to send proberesp for non p2p */
4921 /* response then data should be checked for */
4922 /* "DIRECT-". Note in future supplicant will take */
4923 /* dedicated p2p wdev to do this and then this 'hack'*/
4924 /* is not needed anymore. */
4925 ie_offset = DOT11_MGMT_HDR_LEN +
4926 DOT11_BCN_PRB_FIXED_LEN;
4927 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004928 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4929 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4930 err = brcmf_vif_set_mgmt_ie(vif,
4931 BRCMF_VNDR_IE_PRBRSP_FLAG,
4932 &buf[ie_offset],
4933 ie_len);
4934 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4935 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004936 } else if (ieee80211_is_action(mgmt->frame_control)) {
4937 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4938 if (af_params == NULL) {
4939 brcmf_err("unable to allocate frame\n");
4940 err = -ENOMEM;
4941 goto exit;
4942 }
4943 action_frame = &af_params->action_frame;
4944 /* Add the packet Id */
4945 action_frame->packet_id = cpu_to_le32(*cookie);
4946 /* Add BSSID */
4947 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4948 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4949 /* Add the length exepted for 802.11 header */
4950 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004951 /* Add the channel. Use the one specified as parameter if any or
4952 * the current one (got from the firmware) otherwise
4953 */
4954 if (chan)
4955 freq = chan->center_freq;
4956 else
4957 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4958 &freq);
4959 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004960 af_params->channel = cpu_to_le32(chan_nr);
4961
4962 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4963 le16_to_cpu(action_frame->len));
4964
4965 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004966 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004967
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004968 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004969 af_params);
4970
4971 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4972 GFP_KERNEL);
4973 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004974 } else {
4975 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004976 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004977 }
4978
Hante Meuleman18e2f612013-02-08 15:53:49 +01004979exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004980 return err;
4981}
4982
4983
4984static int
4985brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4986 struct wireless_dev *wdev,
4987 u64 cookie)
4988{
4989 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4990 struct brcmf_cfg80211_vif *vif;
4991 int err = 0;
4992
4993 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4994
4995 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4996 if (vif == NULL) {
4997 brcmf_err("No p2p device available for probe response\n");
4998 err = -ENODEV;
4999 goto exit;
5000 }
5001 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
5002exit:
5003 return err;
5004}
5005
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005006static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
5007 struct wireless_dev *wdev,
5008 struct cfg80211_chan_def *chandef)
5009{
5010 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5011 struct net_device *ndev = wdev->netdev;
5012 struct brcmf_if *ifp;
5013 struct brcmu_chan ch;
5014 enum nl80211_band band = 0;
5015 enum nl80211_chan_width width = 0;
5016 u32 chanspec;
5017 int freq, err;
5018
5019 if (!ndev)
5020 return -ENODEV;
5021 ifp = netdev_priv(ndev);
5022
5023 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
5024 if (err) {
5025 brcmf_err("chanspec failed (%d)\n", err);
5026 return err;
5027 }
5028
5029 ch.chspec = chanspec;
5030 cfg->d11inf.decchspec(&ch);
5031
5032 switch (ch.band) {
5033 case BRCMU_CHAN_BAND_2G:
5034 band = NL80211_BAND_2GHZ;
5035 break;
5036 case BRCMU_CHAN_BAND_5G:
5037 band = NL80211_BAND_5GHZ;
5038 break;
5039 }
5040
5041 switch (ch.bw) {
5042 case BRCMU_CHAN_BW_80:
5043 width = NL80211_CHAN_WIDTH_80;
5044 break;
5045 case BRCMU_CHAN_BW_40:
5046 width = NL80211_CHAN_WIDTH_40;
5047 break;
5048 case BRCMU_CHAN_BW_20:
5049 width = NL80211_CHAN_WIDTH_20;
5050 break;
5051 case BRCMU_CHAN_BW_80P80:
5052 width = NL80211_CHAN_WIDTH_80P80;
5053 break;
5054 case BRCMU_CHAN_BW_160:
5055 width = NL80211_CHAN_WIDTH_160;
5056 break;
5057 }
5058
5059 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
5060 chandef->chan = ieee80211_get_channel(wiphy, freq);
5061 chandef->width = width;
5062 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
5063 chandef->center_freq2 = 0;
5064
5065 return 0;
5066}
5067
Piotr Haber61730d42013-04-23 12:53:12 +02005068static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
5069 struct wireless_dev *wdev,
5070 enum nl80211_crit_proto_id proto,
5071 u16 duration)
5072{
5073 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5074 struct brcmf_cfg80211_vif *vif;
5075
5076 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5077
5078 /* only DHCP support for now */
5079 if (proto != NL80211_CRIT_PROTO_DHCP)
5080 return -EINVAL;
5081
5082 /* suppress and abort scanning */
5083 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5084 brcmf_abort_scanning(cfg);
5085
5086 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5087}
5088
5089static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5090 struct wireless_dev *wdev)
5091{
5092 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5093 struct brcmf_cfg80211_vif *vif;
5094
5095 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5096
5097 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5098 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5099}
5100
Hante Meuleman70b7d942014-07-30 13:20:07 +02005101static s32
5102brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5103 const struct brcmf_event_msg *e, void *data)
5104{
5105 switch (e->reason) {
5106 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5107 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5108 break;
5109 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5110 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5111 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5112 break;
5113 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5114 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5115 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5116 break;
5117 }
5118
5119 return 0;
5120}
5121
Arend van Spriel89c2f382013-08-10 12:27:25 +02005122static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5123{
5124 int ret;
5125
5126 switch (oper) {
5127 case NL80211_TDLS_DISCOVERY_REQ:
5128 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5129 break;
5130 case NL80211_TDLS_SETUP:
5131 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5132 break;
5133 case NL80211_TDLS_TEARDOWN:
5134 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5135 break;
5136 default:
5137 brcmf_err("unsupported operation: %d\n", oper);
5138 ret = -EOPNOTSUPP;
5139 }
5140 return ret;
5141}
5142
5143static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005144 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005145 enum nl80211_tdls_operation oper)
5146{
5147 struct brcmf_if *ifp;
5148 struct brcmf_tdls_iovar_le info;
5149 int ret = 0;
5150
5151 ret = brcmf_convert_nl80211_tdls_oper(oper);
5152 if (ret < 0)
5153 return ret;
5154
5155 ifp = netdev_priv(ndev);
5156 memset(&info, 0, sizeof(info));
5157 info.mode = (u8)ret;
5158 if (peer)
5159 memcpy(info.ea, peer, ETH_ALEN);
5160
5161 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5162 &info, sizeof(info));
5163 if (ret < 0)
5164 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5165
5166 return ret;
5167}
5168
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005169static int
5170brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5171 struct net_device *ndev,
5172 struct cfg80211_connect_params *sme,
5173 u32 changed)
5174{
5175 struct brcmf_if *ifp;
5176 int err;
5177
5178 if (!(changed & UPDATE_ASSOC_IES))
5179 return 0;
5180
5181 ifp = netdev_priv(ndev);
5182 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5183 sme->ie, sme->ie_len);
5184 if (err)
5185 brcmf_err("Set Assoc REQ IE Failed\n");
5186 else
5187 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5188
5189 return err;
5190}
5191
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005192#ifdef CONFIG_PM
5193static int
5194brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5195 struct cfg80211_gtk_rekey_data *gtk)
5196{
5197 struct brcmf_if *ifp = netdev_priv(ndev);
5198 struct brcmf_gtk_keyinfo_le gtk_le;
5199 int ret;
5200
5201 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5202
5203 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5204 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5205 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5206 sizeof(gtk_le.replay_counter));
5207
5208 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5209 sizeof(gtk_le));
5210 if (ret < 0)
5211 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5212
5213 return ret;
5214}
5215#endif
5216
Arend van Spriel2526ff22017-06-09 13:08:48 +01005217static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
5218 const struct cfg80211_pmk_conf *conf)
5219{
5220 struct brcmf_if *ifp;
5221
5222 brcmf_dbg(TRACE, "enter\n");
5223
5224 /* expect using firmware supplicant for 1X */
5225 ifp = netdev_priv(dev);
5226 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5227 return -EINVAL;
5228
5229 return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
5230}
5231
5232static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
5233 const u8 *aa)
5234{
5235 struct brcmf_if *ifp;
5236
5237 brcmf_dbg(TRACE, "enter\n");
5238 ifp = netdev_priv(dev);
5239 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5240 return -EINVAL;
5241
5242 return brcmf_set_pmk(ifp, NULL, 0);
5243}
5244
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005245static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005246 .add_virtual_intf = brcmf_cfg80211_add_iface,
5247 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005248 .change_virtual_intf = brcmf_cfg80211_change_iface,
5249 .scan = brcmf_cfg80211_scan,
5250 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5251 .join_ibss = brcmf_cfg80211_join_ibss,
5252 .leave_ibss = brcmf_cfg80211_leave_ibss,
5253 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005254 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005255 .set_tx_power = brcmf_cfg80211_set_tx_power,
5256 .get_tx_power = brcmf_cfg80211_get_tx_power,
5257 .add_key = brcmf_cfg80211_add_key,
5258 .del_key = brcmf_cfg80211_del_key,
5259 .get_key = brcmf_cfg80211_get_key,
5260 .set_default_key = brcmf_cfg80211_config_default_key,
5261 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5262 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263 .connect = brcmf_cfg80211_connect,
5264 .disconnect = brcmf_cfg80211_disconnect,
5265 .suspend = brcmf_cfg80211_suspend,
5266 .resume = brcmf_cfg80211_resume,
5267 .set_pmksa = brcmf_cfg80211_set_pmksa,
5268 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005269 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005270 .start_ap = brcmf_cfg80211_start_ap,
5271 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005272 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005273 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005274 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005275 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5276 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005277 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5278 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5279 .remain_on_channel = brcmf_p2p_remain_on_channel,
5280 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005281 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005282 .start_p2p_device = brcmf_p2p_start_device,
5283 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005284 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5285 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005286 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005287 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel2526ff22017-06-09 13:08:48 +01005288 .set_pmk = brcmf_cfg80211_set_pmk,
5289 .del_pmk = brcmf_cfg80211_del_pmk,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005290};
5291
Arend van Spriel3eacf862012-10-22 13:55:30 -07005292struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005293 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005294{
Hante Meulemana44aa402014-12-03 21:05:33 +01005295 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005296 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005297 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005298
Arend van Spriel33a6b152013-02-08 15:53:39 +01005299 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005300 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005301 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5302 if (!vif)
5303 return ERR_PTR(-ENOMEM);
5304
5305 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005306 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005307
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005308 brcmf_init_prof(&vif->profile);
5309
Hante Meulemana44aa402014-12-03 21:05:33 +01005310 if (type == NL80211_IFTYPE_AP) {
5311 mbss = false;
5312 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5313 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5314 mbss = true;
5315 break;
5316 }
5317 }
5318 vif->mbss = mbss;
5319 }
5320
Arend van Spriel3eacf862012-10-22 13:55:30 -07005321 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005322 return vif;
5323}
5324
Arend van Spriel427dec52014-01-06 12:40:47 +01005325void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005326{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005327 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005328 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005329}
5330
Arend van Spriel9df4d542014-01-06 12:40:49 +01005331void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5332{
5333 struct brcmf_cfg80211_vif *vif;
5334 struct brcmf_if *ifp;
5335
5336 ifp = netdev_priv(ndev);
5337 vif = ifp->vif;
5338
Arend van Spriel95ef1232015-08-26 22:15:04 +02005339 if (vif)
5340 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005341}
5342
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005343static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
5344 const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005345{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005346 u32 event = e->event_code;
5347 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348
Arend van Spriel2526ff22017-06-09 13:08:48 +01005349 if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
5350 event == BRCMF_E_PSK_SUP &&
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005351 status == BRCMF_E_STATUS_FWSUP_COMPLETED)
5352 set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005353 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005354 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005355 memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
5356 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
5357 return true;
5358
5359 set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005360 }
5361
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005362 if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
5363 test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
5364 clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
5365 clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
5366 return true;
5367 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368 return false;
5369}
5370
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005371static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005372{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005373 u32 event = e->event_code;
5374 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005375
Hante Meuleman68ca3952014-02-25 20:30:26 +01005376 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5377 (event == BRCMF_E_DISASSOC_IND) ||
5378 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005379 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005380 return true;
5381 }
5382 return false;
5383}
5384
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005385static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005386 const struct brcmf_event_msg *e)
5387{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005388 u32 event = e->event_code;
5389 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390
5391 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005392 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5393 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005394 return true;
5395 }
5396
5397 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005398 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005399 return true;
5400 }
5401
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005402 if (event == BRCMF_E_PSK_SUP &&
5403 status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
5404 brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
5405 status);
5406 return true;
5407 }
5408
Arend van Spriel5b435de2011-10-05 13:19:03 +02005409 return false;
5410}
5411
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005412static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005413{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005414 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415
5416 kfree(conn_info->req_ie);
5417 conn_info->req_ie = NULL;
5418 conn_info->req_ie_len = 0;
5419 kfree(conn_info->resp_ie);
5420 conn_info->resp_ie = NULL;
5421 conn_info->resp_ie_len = 0;
5422}
5423
Hante Meuleman89286dc2013-02-08 15:53:46 +01005424static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5425 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005426{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005427 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005428 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005429 u32 req_len;
5430 u32 resp_len;
5431 s32 err = 0;
5432
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005433 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434
Arend van Sprielac24be62012-10-22 10:36:23 -07005435 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5436 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005437 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005438 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 return err;
5440 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005441 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005442 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005443 req_len = le32_to_cpu(assoc_info->req_len);
5444 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005445 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005446 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005447 cfg->extra_buf,
5448 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005450 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451 return err;
5452 }
5453 conn_info->req_ie_len = req_len;
5454 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005455 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005456 GFP_KERNEL);
5457 } else {
5458 conn_info->req_ie_len = 0;
5459 conn_info->req_ie = NULL;
5460 }
5461 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005462 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005463 cfg->extra_buf,
5464 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005465 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005466 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005467 return err;
5468 }
5469 conn_info->resp_ie_len = resp_len;
5470 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005471 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005472 GFP_KERNEL);
5473 } else {
5474 conn_info->resp_ie_len = 0;
5475 conn_info->resp_ie = NULL;
5476 }
Arend van Spriel16886732012-12-05 15:26:04 +01005477 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5478 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005479
5480 return err;
5481}
5482
5483static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005484brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005485 struct net_device *ndev,
5486 const struct brcmf_event_msg *e)
5487{
Arend van Sprielc1179032012-10-22 13:55:33 -07005488 struct brcmf_if *ifp = netdev_priv(ndev);
5489 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005490 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5491 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005492 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005493 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005494 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005495 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005496 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005497 u32 freq;
5498 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005499 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005500
Arend van Sprield96b8012012-12-05 15:26:02 +01005501 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005502
Hante Meuleman89286dc2013-02-08 15:53:46 +01005503 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005504 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005505 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005506
Franky Lina180b832012-10-10 11:13:09 -07005507 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5508 if (buf == NULL) {
5509 err = -ENOMEM;
5510 goto done;
5511 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005512
Franky Lina180b832012-10-10 11:13:09 -07005513 /* data sent to dongle has to be little endian */
5514 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005515 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005516 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005517
5518 if (err)
5519 goto done;
5520
5521 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005522 ch.chspec = le16_to_cpu(bi->chanspec);
5523 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005524
Franky Lin83cf17a2013-04-11 13:28:50 +02005525 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005526 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005527 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005528 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005529
Rafał Miłecki4712d882016-05-20 13:38:57 +02005530 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005531 notify_channel = ieee80211_get_channel(wiphy, freq);
5532
Franky Lina180b832012-10-10 11:13:09 -07005533done:
5534 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005535
5536 roam_info.channel = notify_channel;
5537 roam_info.bssid = profile->bssid;
5538 roam_info.req_ie = conn_info->req_ie;
5539 roam_info.req_ie_len = conn_info->req_ie_len;
5540 roam_info.resp_ie = conn_info->resp_ie;
5541 roam_info.resp_ie_len = conn_info->resp_ie_len;
5542
5543 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005544 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005545
Arend van Sprielc1179032012-10-22 13:55:33 -07005546 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005547 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005548 return err;
5549}
5550
5551static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005552brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005553 struct net_device *ndev, const struct brcmf_event_msg *e,
5554 bool completed)
5555{
Arend van Sprielc1179032012-10-22 13:55:33 -07005556 struct brcmf_if *ifp = netdev_priv(ndev);
5557 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005558 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel123fef32017-06-09 13:08:49 +01005559 struct cfg80211_connect_resp_params conn_params;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005560
Arend van Sprield96b8012012-12-05 15:26:02 +01005561 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005562
Arend van Sprielc1179032012-10-22 13:55:33 -07005563 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5564 &ifp->vif->sme_state)) {
Arend van Spriel123fef32017-06-09 13:08:49 +01005565 memset(&conn_params, 0, sizeof(conn_params));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005566 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005567 brcmf_get_assoc_ies(cfg, ifp);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005568 brcmf_update_bss_info(cfg, ifp);
5569 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5570 &ifp->vif->sme_state);
Arend van Spriel123fef32017-06-09 13:08:49 +01005571 conn_params.status = WLAN_STATUS_SUCCESS;
5572 } else {
5573 conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005574 }
Arend van Spriel123fef32017-06-09 13:08:49 +01005575 conn_params.bssid = profile->bssid;
5576 conn_params.req_ie = conn_info->req_ie;
5577 conn_params.req_ie_len = conn_info->req_ie_len;
5578 conn_params.resp_ie = conn_info->resp_ie;
5579 conn_params.resp_ie_len = conn_info->resp_ie_len;
5580 cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005581 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5582 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005583 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005584 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005585 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005586}
5587
5588static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005589brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005590 struct net_device *ndev,
5591 const struct brcmf_event_msg *e, void *data)
5592{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005593 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005594 u32 event = e->event_code;
5595 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005596 struct station_info sinfo;
5597
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005598 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5599 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005600 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5601 ndev != cfg_to_ndev(cfg)) {
5602 brcmf_dbg(CONN, "AP mode link down\n");
5603 complete(&cfg->vif_disabled);
5604 return 0;
5605 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005606
Hante Meuleman1a873342012-09-27 14:17:54 +02005607 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005608 (reason == BRCMF_E_STATUS_SUCCESS)) {
5609 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005610 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005611 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005612 return -EINVAL;
5613 }
5614 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005615 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005616 generation++;
5617 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005618 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005619 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5620 (event == BRCMF_E_DEAUTH_IND) ||
5621 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005622 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005623 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005624 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005625}
5626
5627static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005628brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005629 const struct brcmf_event_msg *e, void *data)
5630{
Arend van Spriel19937322012-11-05 16:22:32 -08005631 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5632 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005633 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005634 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005635 s32 err = 0;
5636
Hante Meuleman8851cce2014-07-30 13:20:02 +02005637 if ((e->event_code == BRCMF_E_DEAUTH) ||
5638 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5639 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5640 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5641 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5642 }
5643
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005644 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005645 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005646 } else if (brcmf_is_linkup(ifp->vif, e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005647 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005648 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005649 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005650 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005651 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005652 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005653 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5654 &ifp->vif->sme_state);
5655 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5656 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005657 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005658 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005659 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005660 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005661 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005662 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005663 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005664 brcmf_link_down(ifp->vif,
5665 brcmf_map_fw_linkdown_reason(e));
5666 brcmf_init_prof(ndev_to_prof(ndev));
5667 if (ndev != cfg_to_ndev(cfg))
5668 complete(&cfg->vif_disabled);
5669 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005670 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005671 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005672 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005673 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5674 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005675 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005676 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005677 }
5678
5679 return err;
5680}
5681
5682static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005683brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005684 const struct brcmf_event_msg *e, void *data)
5685{
Arend van Spriel19937322012-11-05 16:22:32 -08005686 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005687 u32 event = e->event_code;
5688 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005689
5690 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005691 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005692 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005693 else
Arend van Spriel19937322012-11-05 16:22:32 -08005694 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005695 }
5696
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005697 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005698}
5699
5700static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005701brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005702 const struct brcmf_event_msg *e, void *data)
5703{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005704 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005705 enum nl80211_key_type key_type;
5706
5707 if (flags & BRCMF_EVENT_MSG_GROUP)
5708 key_type = NL80211_KEYTYPE_GROUP;
5709 else
5710 key_type = NL80211_KEYTYPE_PAIRWISE;
5711
Arend van Spriel19937322012-11-05 16:22:32 -08005712 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005713 NULL, GFP_KERNEL);
5714
5715 return 0;
5716}
5717
Arend van Sprield3c0b632013-02-08 15:53:37 +01005718static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5719 const struct brcmf_event_msg *e, void *data)
5720{
5721 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5722 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5723 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5724 struct brcmf_cfg80211_vif *vif;
5725
Hante Meuleman37a869e2015-10-29 20:33:17 +01005726 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005727 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005728 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005729
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005730 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005731 event->action = ifevent->action;
5732 vif = event->vif;
5733
5734 switch (ifevent->action) {
5735 case BRCMF_E_IF_ADD:
5736 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005737 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005738 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005739 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005740 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005741
5742 ifp->vif = vif;
5743 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005744 if (ifp->ndev) {
5745 vif->wdev.netdev = ifp->ndev;
5746 ifp->ndev->ieee80211_ptr = &vif->wdev;
5747 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5748 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005749 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005750 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005751 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005752
5753 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005754 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005755 /* event may not be upon user request */
5756 if (brcmf_cfg80211_vif_event_armed(cfg))
5757 wake_up(&event->vif_wq);
5758 return 0;
5759
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005760 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005761 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005762 wake_up(&event->vif_wq);
5763 return 0;
5764
Arend van Sprield3c0b632013-02-08 15:53:37 +01005765 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005766 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005767 break;
5768 }
5769 return -EINVAL;
5770}
5771
Arend van Spriel5b435de2011-10-05 13:19:03 +02005772static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5773{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005774 conf->frag_threshold = (u32)-1;
5775 conf->rts_threshold = (u32)-1;
5776 conf->retry_short = (u32)-1;
5777 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005778}
5779
Arend van Spriel5c36b992012-11-14 18:46:05 -08005780static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005781{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005782 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5783 brcmf_notify_connect_status);
5784 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5785 brcmf_notify_connect_status);
5786 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5787 brcmf_notify_connect_status);
5788 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5789 brcmf_notify_connect_status);
5790 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5791 brcmf_notify_connect_status);
5792 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5793 brcmf_notify_connect_status);
5794 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5795 brcmf_notify_roaming_status);
5796 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5797 brcmf_notify_mic_status);
5798 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5799 brcmf_notify_connect_status);
5800 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5801 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005802 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5803 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005804 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005805 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005806 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5807 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005808 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5809 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005810 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5811 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005812 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5813 brcmf_p2p_notify_action_tx_complete);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005814 brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
5815 brcmf_notify_connect_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005816}
5817
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005818static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005819{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005820 kfree(cfg->conf);
5821 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005822 kfree(cfg->extra_buf);
5823 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005824 kfree(cfg->wowl.nd);
5825 cfg->wowl.nd = NULL;
5826 kfree(cfg->wowl.nd_info);
5827 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005828 kfree(cfg->escan_info.escan_buf);
5829 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005830}
5831
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005832static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005833{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005834 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5835 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005836 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005837 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5838 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005839 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005840 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5841 if (!cfg->wowl.nd)
5842 goto init_priv_mem_out;
5843 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5844 sizeof(struct cfg80211_wowlan_nd_match *),
5845 GFP_KERNEL);
5846 if (!cfg->wowl.nd_info)
5847 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005848 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5849 if (!cfg->escan_info.escan_buf)
5850 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005851
5852 return 0;
5853
5854init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005855 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005856
5857 return -ENOMEM;
5858}
5859
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005860static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005861{
5862 s32 err = 0;
5863
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005864 cfg->scan_request = NULL;
5865 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005866 cfg->active_scan = true; /* we do active scan per default */
5867 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005868 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005869 if (err)
5870 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005871 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005872 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005873 brcmf_init_escan(cfg);
5874 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005875 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005876 return err;
5877}
5878
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005879static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005880{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005881 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005882 brcmf_abort_scanning(cfg);
5883 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005884}
5885
Arend van Sprield3c0b632013-02-08 15:53:37 +01005886static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5887{
5888 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005889 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005890}
5891
Hante Meuleman1119e232015-11-25 11:32:42 +01005892static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005893{
Hante Meuleman1119e232015-11-25 11:32:42 +01005894 s32 err;
5895 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005896 __le32 roamtrigger[2];
5897 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005898
Hante Meuleman1119e232015-11-25 11:32:42 +01005899 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005900 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005901 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5902 else
5903 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5904 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5905 if (err) {
5906 brcmf_err("bcn_timeout error (%d)\n", err);
5907 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005908 }
5909
Hante Meuleman1119e232015-11-25 11:32:42 +01005910 /* Enable/Disable built-in roaming to allow supplicant to take care of
5911 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005912 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005913 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005914 ifp->drvr->settings->roamoff ? "Off" : "On");
5915 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5916 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005917 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005918 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005919 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005920 }
5921
Arend van Sprielf588bc02011-10-12 20:51:22 +02005922 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5923 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005924 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005925 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005926 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005927 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005928 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005929 }
5930
Arend van Sprielf588bc02011-10-12 20:51:22 +02005931 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5932 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005933 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005934 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005935 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005936 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005937 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005938 }
5939
Hante Meuleman1119e232015-11-25 11:32:42 +01005940roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005941 return err;
5942}
5943
5944static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005945brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005946{
5947 s32 err = 0;
5948
Arend van Sprielac24be62012-10-22 10:36:23 -07005949 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005950 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005951 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005952 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005953 goto dongle_scantime_out;
5954 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005955 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005956 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005957 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005958 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005959 goto dongle_scantime_out;
5960 }
5961
Arend van Sprielac24be62012-10-22 10:36:23 -07005962 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005963 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005964 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005965 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005966 goto dongle_scantime_out;
5967 }
5968
5969dongle_scantime_out:
5970 return err;
5971}
5972
Arend van Sprielb48d8912014-07-12 08:49:41 +02005973static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5974 struct brcmu_chan *ch)
5975{
5976 u32 ht40_flag;
5977
5978 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5979 if (ch->sb == BRCMU_CHAN_SB_U) {
5980 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5981 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5982 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5983 } else {
5984 /* It should be one of
5985 * IEEE80211_CHAN_NO_HT40 or
5986 * IEEE80211_CHAN_NO_HT40PLUS
5987 */
5988 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5989 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5990 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5991 }
5992}
5993
5994static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5995 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005996{
5997 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005998 struct ieee80211_supported_band *band;
5999 struct ieee80211_channel *channel;
6000 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02006001 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02006002 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006003 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006004 u8 *pbuf;
6005 u32 i, j;
6006 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006007 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02006008
6009 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6010
6011 if (pbuf == NULL)
6012 return -ENOMEM;
6013
6014 list = (struct brcmf_chanspec_list *)pbuf;
6015
6016 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6017 BRCMF_DCMD_MEDLEN);
6018 if (err) {
6019 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006020 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02006021 }
6022
Arend van Sprielb48d8912014-07-12 08:49:41 +02006023 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006024 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006025 if (band)
6026 for (i = 0; i < band->n_channels; i++)
6027 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006028 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006029 if (band)
6030 for (i = 0; i < band->n_channels; i++)
6031 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02006032
6033 total = le32_to_cpu(list->count);
6034 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02006035 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6036 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02006037
Franky Lin83cf17a2013-04-11 13:28:50 +02006038 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006039 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02006040 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006041 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02006042 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006043 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02006044 continue;
6045 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02006046 if (!band)
6047 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006048 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01006049 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02006050 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006051 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02006052 ch.bw == BRCMU_CHAN_BW_80)
6053 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006054
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006055 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006056 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006057 if (band->channels[j].hw_value == ch.control_ch_num) {
6058 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02006059 break;
6060 }
6061 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006062 if (!channel) {
6063 /* It seems firmware supports some channel we never
6064 * considered. Something new in IEEE standard?
6065 */
6066 brcmf_err("Ignoring unexpected firmware channel %d\n",
6067 ch.control_ch_num);
6068 continue;
6069 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006070
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006071 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
6072 continue;
6073
Arend van Sprielb48d8912014-07-12 08:49:41 +02006074 /* assuming the chanspecs order is HT20,
6075 * HT40 upper, HT40 lower, and VHT80.
6076 */
6077 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006078 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006079 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006080 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006081 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02006082 /* enable the channel and disable other bandwidths
6083 * for now as mentioned order assure they are enabled
6084 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02006085 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006086 channel->flags = IEEE80211_CHAN_NO_HT40 |
6087 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006088 ch.bw = BRCMU_CHAN_BW_20;
6089 cfg->d11inf.encchspec(&ch);
6090 chaninfo = ch.chspec;
6091 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
6092 &chaninfo);
6093 if (!err) {
6094 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006095 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006096 (IEEE80211_CHAN_RADAR |
6097 IEEE80211_CHAN_NO_IR);
6098 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006099 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006100 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006101 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006102 }
6103 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006104
Arend van Sprielb48d8912014-07-12 08:49:41 +02006105fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006106 kfree(pbuf);
6107 return err;
6108}
6109
Arend van Sprielb48d8912014-07-12 08:49:41 +02006110static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006111{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006112 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6113 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006114 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006115 struct brcmf_chanspec_list *list;
6116 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006117 u32 val;
6118 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006119 struct brcmu_chan ch;
6120 u32 num_chan;
6121 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006122
6123 /* verify support for bw_cap command */
6124 val = WLC_BAND_5G;
6125 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6126
6127 if (!err) {
6128 /* only set 2G bandwidth using bw_cap command */
6129 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6130 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6131 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6132 sizeof(band_bwcap));
6133 } else {
6134 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6135 val = WLC_N_BW_40ALL;
6136 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6137 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006138
6139 if (!err) {
6140 /* update channel info in 2G band */
6141 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6142
6143 if (pbuf == NULL)
6144 return -ENOMEM;
6145
6146 ch.band = BRCMU_CHAN_BAND_2G;
6147 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006148 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006149 ch.chnum = 0;
6150 cfg->d11inf.encchspec(&ch);
6151
6152 /* pass encoded chanspec in query */
6153 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6154
6155 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6156 BRCMF_DCMD_MEDLEN);
6157 if (err) {
6158 brcmf_err("get chanspecs error (%d)\n", err);
6159 kfree(pbuf);
6160 return err;
6161 }
6162
Johannes Berg57fbcce2016-04-12 15:56:15 +02006163 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006164 list = (struct brcmf_chanspec_list *)pbuf;
6165 num_chan = le32_to_cpu(list->count);
6166 for (i = 0; i < num_chan; i++) {
6167 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6168 cfg->d11inf.decchspec(&ch);
6169 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6170 continue;
6171 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6172 continue;
6173 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006174 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006175 break;
6176 }
6177 if (WARN_ON(j == band->n_channels))
6178 continue;
6179
6180 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6181 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006182 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006183 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006184 return err;
6185}
6186
Arend van Spriel2375d972014-01-06 12:40:41 +01006187static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6188{
6189 u32 band, mimo_bwcap;
6190 int err;
6191
6192 band = WLC_BAND_2G;
6193 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6194 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006195 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006196 band = WLC_BAND_5G;
6197 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6198 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006199 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006200 return;
6201 }
6202 WARN_ON(1);
6203 return;
6204 }
6205 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6206 mimo_bwcap = 0;
6207 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6208 if (err)
6209 /* assume 20MHz if firmware does not give a clue */
6210 mimo_bwcap = WLC_N_BW_20ALL;
6211
6212 switch (mimo_bwcap) {
6213 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006214 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006215 /* fall-thru */
6216 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006217 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006218 /* fall-thru */
6219 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006220 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6221 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006222 break;
6223 default:
6224 brcmf_err("invalid mimo_bw_cap value\n");
6225 }
6226}
Hante Meulemand48200b2013-04-03 12:40:29 +02006227
Arend van Spriel18d6c532014-05-12 10:47:35 +02006228static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6229 u32 bw_cap[2], u32 nchain)
6230{
6231 band->ht_cap.ht_supported = true;
6232 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6233 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6234 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6235 }
6236 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6237 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6238 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6239 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6240 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6241 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6242}
6243
6244static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6245{
6246 u16 mcs_map;
6247 int i;
6248
6249 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6250 mcs_map = (mcs_map << 2) | supp;
6251
6252 return cpu_to_le16(mcs_map);
6253}
6254
6255static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006256 u32 bw_cap[2], u32 nchain, u32 txstreams,
6257 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006258{
6259 __le16 mcs_map;
6260
6261 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006262 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006263 return;
6264
6265 band->vht_cap.vht_supported = true;
6266 /* 80MHz is mandatory */
6267 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6268 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6269 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6270 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6271 }
6272 /* all support 256-QAM */
6273 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6274 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6275 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006276
6277 /* Beamforming support information */
6278 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6279 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6280 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6281 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6282 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6283 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6284 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6285 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6286
6287 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6288 band->vht_cap.cap |=
6289 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6290 band->vht_cap.cap |= ((txstreams - 1) <<
6291 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6292 band->vht_cap.cap |=
6293 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6294 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006295}
6296
Arend van Sprielb48d8912014-07-12 08:49:41 +02006297static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006298{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006299 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006300 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006301 u32 nmode = 0;
6302 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006303 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006304 u32 rxchain;
6305 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006306 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006307 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006308 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006309 u32 txstreams = 0;
6310 u32 txbf_bfe_cap = 0;
6311 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006312
Arend van Spriel18d6c532014-05-12 10:47:35 +02006313 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006314 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6315 if (err) {
6316 brcmf_err("nmode error (%d)\n", err);
6317 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006318 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006319 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006320 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006321 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6322 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006323
Daniel Kim4aca7a12014-02-25 20:30:36 +01006324 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6325 if (err) {
6326 brcmf_err("rxchain error (%d)\n", err);
6327 nchain = 1;
6328 } else {
6329 for (nchain = 0; rxchain; nchain++)
6330 rxchain = rxchain & (rxchain - 1);
6331 }
6332 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6333
Arend van Sprielb48d8912014-07-12 08:49:41 +02006334 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006335 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006336 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006337 return err;
6338 }
6339
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006340 if (vhtmode) {
6341 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6342 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6343 &txbf_bfe_cap);
6344 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6345 &txbf_bfr_cap);
6346 }
6347
Arend van Sprielb48d8912014-07-12 08:49:41 +02006348 wiphy = cfg_to_wiphy(cfg);
6349 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6350 band = wiphy->bands[i];
6351 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006352 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006353
Arend van Spriel18d6c532014-05-12 10:47:35 +02006354 if (nmode)
6355 brcmf_update_ht_cap(band, bw_cap, nchain);
6356 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006357 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6358 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006359 }
6360
Arend van Sprielb48d8912014-07-12 08:49:41 +02006361 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006362}
6363
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006364static const struct ieee80211_txrx_stypes
6365brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6366 [NL80211_IFTYPE_STATION] = {
6367 .tx = 0xffff,
6368 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6369 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6370 },
6371 [NL80211_IFTYPE_P2P_CLIENT] = {
6372 .tx = 0xffff,
6373 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6374 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6375 },
6376 [NL80211_IFTYPE_P2P_GO] = {
6377 .tx = 0xffff,
6378 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6379 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6380 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6381 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6382 BIT(IEEE80211_STYPE_AUTH >> 4) |
6383 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6384 BIT(IEEE80211_STYPE_ACTION >> 4)
6385 },
6386 [NL80211_IFTYPE_P2P_DEVICE] = {
6387 .tx = 0xffff,
6388 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6389 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6390 }
6391};
6392
Arend van Spriel0882dda2015-08-20 22:06:03 +02006393/**
6394 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6395 *
6396 * @wiphy: wiphy object.
6397 * @ifp: interface object needed for feat module api.
6398 *
6399 * The interface modes and combinations are determined dynamically here
6400 * based on firmware functionality.
6401 *
6402 * no p2p and no mbss:
6403 *
6404 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6405 *
6406 * no p2p and mbss:
6407 *
6408 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6409 * #AP <= 4, matching BI, channels = 1, 4 total
6410 *
6411 * p2p, no mchan, and mbss:
6412 *
6413 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6414 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6415 * #AP <= 4, matching BI, channels = 1, 4 total
6416 *
6417 * p2p, mchan, and mbss:
6418 *
6419 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6420 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6421 * #AP <= 4, matching BI, channels = 1, 4 total
6422 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006423static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6424{
6425 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006426 struct ieee80211_iface_limit *c0_limits = NULL;
6427 struct ieee80211_iface_limit *p2p_limits = NULL;
6428 struct ieee80211_iface_limit *mbss_limits = NULL;
6429 bool mbss, p2p;
6430 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006431
Arend van Spriel0882dda2015-08-20 22:06:03 +02006432 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6433 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6434
6435 n_combos = 1 + !!p2p + !!mbss;
6436 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006437 if (!combo)
6438 goto err;
6439
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006440 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6441 BIT(NL80211_IFTYPE_ADHOC) |
6442 BIT(NL80211_IFTYPE_AP);
6443
Arend van Spriel0882dda2015-08-20 22:06:03 +02006444 c = 0;
6445 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006446 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6447 if (!c0_limits)
6448 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006449 c0_limits[i].max = 1;
6450 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6451 if (p2p) {
6452 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6453 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006454 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6455 BIT(NL80211_IFTYPE_P2P_GO) |
6456 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006457 c0_limits[i].max = 1;
6458 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6459 c0_limits[i].max = 1;
6460 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6461 BIT(NL80211_IFTYPE_P2P_GO);
6462 } else {
6463 c0_limits[i].max = 1;
6464 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006465 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006466 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006467 combo[c].max_interfaces = i;
6468 combo[c].n_limits = i;
6469 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006470
Arend van Spriel0882dda2015-08-20 22:06:03 +02006471 if (p2p) {
6472 c++;
6473 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006474 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6475 if (!p2p_limits)
6476 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006477 p2p_limits[i].max = 1;
6478 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6479 p2p_limits[i].max = 1;
6480 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6481 p2p_limits[i].max = 1;
6482 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6483 p2p_limits[i].max = 1;
6484 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006485 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006486 combo[c].max_interfaces = i;
6487 combo[c].n_limits = i;
6488 combo[c].limits = p2p_limits;
6489 }
6490
6491 if (mbss) {
6492 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006493 i = 0;
6494 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6495 if (!mbss_limits)
6496 goto err;
6497 mbss_limits[i].max = 4;
6498 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006499 combo[c].beacon_int_infra_match = true;
6500 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006501 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006502 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006503 combo[c].limits = mbss_limits;
6504 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006505
Arend van Spriel0882dda2015-08-20 22:06:03 +02006506 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006507 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006508 return 0;
6509
6510err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006511 kfree(c0_limits);
6512 kfree(p2p_limits);
6513 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006514 kfree(combo);
6515 return -ENOMEM;
6516}
6517
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006518#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006519static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006520 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006521 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6522 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6523 .pattern_min_len = 1,
6524 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006525};
6526#endif
6527
Hante Meuleman3021ad92016-01-05 11:05:45 +01006528static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006529{
6530#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006531 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006532 struct wiphy_wowlan_support *wowl;
6533
6534 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6535 GFP_KERNEL);
6536 if (!wowl) {
6537 brcmf_err("only support basic wowlan features\n");
6538 wiphy->wowlan = &brcmf_wowlan_support;
6539 return;
6540 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006541
6542 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006543 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006544 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6545 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006546 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006547 }
6548 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006549 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006550 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6551 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006552 }
6553
Arend Van Spriel0b570102017-01-27 12:27:47 +00006554 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006555#endif
6556}
6557
Arend van Sprielb48d8912014-07-12 08:49:41 +02006558static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006559{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006560 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006561 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006562 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006563 u16 max_interfaces = 0;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006564 bool gscan;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006565 __le32 bandlist[3];
6566 u32 n_bands;
6567 int err, i;
6568
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006569 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6570 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006571 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006572
6573 err = brcmf_setup_ifmodes(wiphy, ifp);
6574 if (err)
6575 return err;
6576
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006577 for (i = 0, combo = wiphy->iface_combinations;
6578 i < wiphy->n_iface_combinations; i++, combo++) {
6579 max_interfaces = max(max_interfaces, combo->max_interfaces);
6580 }
6581
6582 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6583 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006584 u8 *addr = drvr->addresses[i].addr;
6585
6586 memcpy(addr, drvr->mac, ETH_ALEN);
6587 if (i) {
6588 addr[0] |= BIT(1);
6589 addr[ETH_ALEN - 1] ^= i;
6590 }
6591 }
6592 wiphy->addresses = drvr->addresses;
6593 wiphy->n_addresses = i;
6594
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006595 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006596 wiphy->cipher_suites = brcmf_cipher_suites;
6597 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6598 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6599 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006600 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6601 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6602 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6603
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006604 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6605 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006606 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006607 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6608 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6609 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006610 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006611 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
Arend van Spriel2526ff22017-06-09 13:08:48 +01006612 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01006613 wiphy_ext_feature_set(wiphy,
6614 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
Arend van Spriel2526ff22017-06-09 13:08:48 +01006615 wiphy_ext_feature_set(wiphy,
6616 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
6617 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006618 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6619 wiphy->max_remain_on_channel_duration = 5000;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006620 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
6621 gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
6622 brcmf_pno_wiphy_params(wiphy, gscan);
6623 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006624 /* vendor commands/events support */
6625 wiphy->vendor_commands = brcmf_vendor_cmds;
6626 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6627
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006628 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006629 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006630 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6631 sizeof(bandlist));
6632 if (err) {
6633 brcmf_err("could not obtain band info: err=%d\n", err);
6634 return err;
6635 }
6636 /* first entry in bandlist is number of bands */
6637 n_bands = le32_to_cpu(bandlist[0]);
6638 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6639 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6640 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6641 GFP_KERNEL);
6642 if (!band)
6643 return -ENOMEM;
6644
6645 band->channels = kmemdup(&__wl_2ghz_channels,
6646 sizeof(__wl_2ghz_channels),
6647 GFP_KERNEL);
6648 if (!band->channels) {
6649 kfree(band);
6650 return -ENOMEM;
6651 }
6652
6653 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006654 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006655 }
6656 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6657 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6658 GFP_KERNEL);
6659 if (!band)
6660 return -ENOMEM;
6661
6662 band->channels = kmemdup(&__wl_5ghz_channels,
6663 sizeof(__wl_5ghz_channels),
6664 GFP_KERNEL);
6665 if (!band->channels) {
6666 kfree(band);
6667 return -ENOMEM;
6668 }
6669
6670 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006671 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006672 }
6673 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006674
6675 wiphy_read_of_freq_limits(wiphy);
6676
Rafał Miłeckiab990632017-01-07 21:36:05 +01006677 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006678}
6679
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006680static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006681{
6682 struct net_device *ndev;
6683 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006684 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006685 s32 power_mode;
6686 s32 err = 0;
6687
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006688 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006689 return err;
6690
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006691 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006692 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006693 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006694
Hante Meuleman40a23292013-01-02 15:22:51 +01006695 /* make sure RF is ready for work */
6696 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6697
Hante Meuleman1678ba82015-12-10 13:43:00 +01006698 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006699
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006700 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006701 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006702 if (err)
6703 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006704 brcmf_dbg(INFO, "power save set to %s\n",
6705 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006706
Hante Meuleman1119e232015-11-25 11:32:42 +01006707 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006708 if (err)
6709 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006710 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006711 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006712 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006713 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006714
Franky Lin52f22fb2016-02-17 11:26:55 +01006715 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006716
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006717 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006718default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006719
6720 return err;
6721
6722}
6723
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006724static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006725{
Arend van Sprielc1179032012-10-22 13:55:33 -07006726 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006727
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006728 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006729}
6730
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006731static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006732{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006733 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006734
Arend van Spriel5b435de2011-10-05 13:19:03 +02006735 /*
6736 * While going down, if associated with AP disassociate
6737 * from AP to save power
6738 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006739 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006740 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006741
6742 /* Make sure WPA_Supplicant receives all the event
6743 generated due to DISASSOC call to the fw to keep
6744 the state fw and WPA_Supplicant state consistent
6745 */
6746 brcmf_delay(500);
6747 }
6748
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006749 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006750 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006751
Arend van Spriel5b435de2011-10-05 13:19:03 +02006752 return 0;
6753}
6754
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006755s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006756{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006757 struct brcmf_if *ifp = netdev_priv(ndev);
6758 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006759 s32 err = 0;
6760
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006761 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006762 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006763 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006764
6765 return err;
6766}
6767
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006768s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006769{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006770 struct brcmf_if *ifp = netdev_priv(ndev);
6771 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006772 s32 err = 0;
6773
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006774 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006775 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006776 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006777
6778 return err;
6779}
6780
Arend van Spriela7965fb2013-04-11 17:08:37 +02006781enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6782{
6783 struct wireless_dev *wdev = &ifp->vif->wdev;
6784
6785 return wdev->iftype;
6786}
6787
Hante Meulemanbfe81972014-10-28 14:56:16 +01006788bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6789 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006790{
6791 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006792
6793 list_for_each_entry(vif, &cfg->vif_list, list) {
6794 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006795 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006796 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006797 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006798}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006799
6800static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6801 u8 action)
6802{
6803 u8 evt_action;
6804
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006805 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006806 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006807 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006808 return evt_action == action;
6809}
6810
6811void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6812 struct brcmf_cfg80211_vif *vif)
6813{
6814 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6815
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006816 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006817 event->vif = vif;
6818 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006819 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006820}
6821
6822bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6823{
6824 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6825 bool armed;
6826
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006827 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006828 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006829 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006830
6831 return armed;
6832}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006833
6834int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6835 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006836{
6837 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6838
6839 return wait_event_timeout(event->vif_wq,
6840 vif_event_equals(event, action), timeout);
6841}
6842
Hante Meuleman73345fd2016-02-17 11:26:53 +01006843static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6844 struct brcmf_fil_country_le *ccreq)
6845{
Hante Meuleman4d792892016-02-17 11:27:07 +01006846 struct brcmfmac_pd_cc *country_codes;
6847 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006848 s32 found_index;
6849 int i;
6850
6851 country_codes = drvr->settings->country_codes;
6852 if (!country_codes) {
6853 brcmf_dbg(TRACE, "No country codes configured for device\n");
6854 return -EINVAL;
6855 }
6856
6857 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6858 (alpha2[1] == ccreq->country_abbrev[1])) {
6859 brcmf_dbg(TRACE, "Country code already set\n");
6860 return -EAGAIN;
6861 }
6862
6863 found_index = -1;
6864 for (i = 0; i < country_codes->table_size; i++) {
6865 cc = &country_codes->table[i];
6866 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6867 found_index = i;
6868 if ((cc->iso3166[0] == alpha2[0]) &&
6869 (cc->iso3166[1] == alpha2[1])) {
6870 found_index = i;
6871 break;
6872 }
6873 }
6874 if (found_index == -1) {
6875 brcmf_dbg(TRACE, "No country code match found\n");
6876 return -EINVAL;
6877 }
6878 memset(ccreq, 0, sizeof(*ccreq));
6879 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6880 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6881 BRCMF_COUNTRY_BUF_SZ);
6882 ccreq->country_abbrev[0] = alpha2[0];
6883 ccreq->country_abbrev[1] = alpha2[1];
6884 ccreq->country_abbrev[2] = 0;
6885
6886 return 0;
6887}
6888
Arend van Spriel63db1a42014-12-21 12:43:51 +01006889static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6890 struct regulatory_request *req)
6891{
6892 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6893 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6894 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006895 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006896 int i;
6897
Hans de Goede26e537882017-03-08 14:50:16 +01006898 /* The country code gets set to "00" by default at boot, ignore */
6899 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6900 return;
6901
Arend van Spriel63db1a42014-12-21 12:43:51 +01006902 /* ignore non-ISO3166 country codes */
6903 for (i = 0; i < sizeof(req->alpha2); i++)
6904 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Martin Michlmayra9507d52017-06-10 11:40:04 +02006905 brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
Hante Meuleman73345fd2016-02-17 11:26:53 +01006906 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006907 return;
6908 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006909
6910 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6911 req->alpha2[0], req->alpha2[1]);
6912
6913 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6914 if (err) {
6915 brcmf_err("Country code iovar returned err = %d\n", err);
6916 return;
6917 }
6918
6919 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6920 if (err)
6921 return;
6922
6923 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6924 if (err) {
6925 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006926 return;
6927 }
6928 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006929}
6930
Arend van Sprielb48d8912014-07-12 08:49:41 +02006931static void brcmf_free_wiphy(struct wiphy *wiphy)
6932{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006933 int i;
6934
Arend van Spriel58de92d2015-04-14 20:10:24 +02006935 if (!wiphy)
6936 return;
6937
Arend van Spriel0882dda2015-08-20 22:06:03 +02006938 if (wiphy->iface_combinations) {
6939 for (i = 0; i < wiphy->n_iface_combinations; i++)
6940 kfree(wiphy->iface_combinations[i].limits);
6941 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006942 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006943 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6944 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6945 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006946 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006947 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6948 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6949 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006950 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006951#if IS_ENABLED(CONFIG_PM)
6952 if (wiphy->wowlan != &brcmf_wowlan_support)
6953 kfree(wiphy->wowlan);
6954#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006955 wiphy_free(wiphy);
6956}
6957
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006958struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006959 struct device *busdev,
6960 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006961{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006962 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006963 struct brcmf_cfg80211_info *cfg;
6964 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006965 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006966 struct brcmf_cfg80211_vif *vif;
6967 struct brcmf_if *ifp;
6968 s32 err = 0;
6969 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006970 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006971
6972 if (!ndev) {
6973 brcmf_err("ndev is invalid\n");
6974 return NULL;
6975 }
6976
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306977 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006978 if (!ops)
6979 return NULL;
6980
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006981 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006982#ifdef CONFIG_PM
6983 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6984 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6985#endif
6986 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006987 if (!wiphy) {
6988 brcmf_err("Could not allocate wiphy device\n");
Christophe Jaillet57c00f22017-06-21 07:45:53 +02006989 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006990 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006991 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006992 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006993
6994 cfg = wiphy_priv(wiphy);
6995 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006996 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006997 cfg->pub = drvr;
6998 init_vif_event(&cfg->vif_event);
6999 INIT_LIST_HEAD(&cfg->vif_list);
7000
Rafał Miłecki26072332016-06-06 23:03:55 +02007001 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007002 if (IS_ERR(vif))
7003 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007004
7005 vif->ifp = ifp;
7006 vif->wdev.netdev = ndev;
7007 ndev->ieee80211_ptr = &vif->wdev;
7008 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
7009
7010 err = wl_init_priv(cfg);
7011 if (err) {
7012 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007013 brcmf_free_vif(vif);
7014 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007015 }
7016 ifp->vif = vif;
7017
Arend van Sprielb48d8912014-07-12 08:49:41 +02007018 /* determine d11 io type before wiphy setup */
7019 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007020 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02007021 brcmf_err("Failed to get D11 version (%d)\n", err);
7022 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007023 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007024 cfg->d11inf.io_type = (u8)io_type;
7025 brcmu_d11_attach(&cfg->d11inf);
7026
7027 err = brcmf_setup_wiphy(wiphy, ifp);
7028 if (err < 0)
7029 goto priv_out;
7030
7031 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01007032 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007033 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
7034 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
7035
7036 /* firmware defaults to 40MHz disabled in 2G band. We signal
7037 * cfg80211 here that we do and have it decide we can enable
7038 * it. But first check if device does support 2G operation.
7039 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007040 if (wiphy->bands[NL80211_BAND_2GHZ]) {
7041 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007042 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
7043 }
7044 err = wiphy_register(wiphy);
7045 if (err < 0) {
7046 brcmf_err("Could not register wiphy device (%d)\n", err);
7047 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007048 }
7049
Rafał Miłeckiab990632017-01-07 21:36:05 +01007050 err = brcmf_setup_wiphybands(wiphy);
7051 if (err) {
7052 brcmf_err("Setting wiphy bands failed (%d)\n", err);
7053 goto wiphy_unreg_out;
7054 }
7055
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007056 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
7057 * setup 40MHz in 2GHz band and enable OBSS scanning.
7058 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02007059 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
7060 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007061 if (!err)
7062 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
7063 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007064 else
7065 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007066 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007067 /* p2p might require that "if-events" get processed by fweh. So
7068 * activate the already registered event handlers now and activate
7069 * the rest when initialization has completed. drvr->config needs to
7070 * be assigned before activating events.
7071 */
7072 drvr->config = cfg;
7073 err = brcmf_fweh_activate_events(ifp);
7074 if (err) {
7075 brcmf_err("FWEH activation failed (%d)\n", err);
7076 goto wiphy_unreg_out;
7077 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007078
Hante Meulemanae7c03f2015-09-18 22:08:08 +02007079 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007080 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007081 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007082 goto wiphy_unreg_out;
7083 }
7084 err = brcmf_btcoex_attach(cfg);
7085 if (err) {
7086 brcmf_err("BT-coex initialisation failed (%d)\n", err);
7087 brcmf_p2p_detach(&cfg->p2p);
7088 goto wiphy_unreg_out;
7089 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007090 err = brcmf_pno_attach(cfg);
7091 if (err) {
7092 brcmf_err("PNO initialisation failed (%d)\n", err);
7093 brcmf_btcoex_detach(cfg);
7094 brcmf_p2p_detach(&cfg->p2p);
7095 goto wiphy_unreg_out;
7096 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007097
Hante Meulemana7b82d42015-12-10 13:43:04 +01007098 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
7099 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
7100 if (err) {
7101 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
7102 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
7103 } else {
7104 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
7105 brcmf_notify_tdls_peer_event);
7106 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007107 }
7108
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007109 /* (re-) activate FWEH event handling */
7110 err = brcmf_fweh_activate_events(ifp);
7111 if (err) {
7112 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007113 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007114 }
7115
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007116 /* Fill in some of the advertised nl80211 supported features */
7117 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7118 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7119#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007120 if (wiphy->wowlan &&
7121 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007122 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7123#endif
7124 }
7125
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007126 return cfg;
7127
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007128detach:
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007129 brcmf_pno_detach(cfg);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007130 brcmf_btcoex_detach(cfg);
7131 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007132wiphy_unreg_out:
7133 wiphy_unregister(cfg->wiphy);
7134priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007135 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007136 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007137 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007138wiphy_out:
7139 brcmf_free_wiphy(wiphy);
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007140ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007141 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007142 return NULL;
7143}
7144
7145void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7146{
7147 if (!cfg)
7148 return;
7149
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007150 brcmf_pno_detach(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007151 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007152 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007153 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007154 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007155 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007156}