blob: 1ad97a40940de6ebdc2648aaab0093f5d5d19579 [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 Meuleman8851cce2014-07-30 13:20:02 +0200475static void
476brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
477{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200478 struct brcmf_cfg80211_vif *vif;
479 struct brcmf_if *ifp;
480
481 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
482 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200483
484 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
485 (wdev->iftype == NL80211_IFTYPE_AP) ||
486 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
487 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
488 ADDR_DIRECT);
489 else
490 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
491 ADDR_INDIRECT);
492}
493
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200494static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
495{
496 int bsscfgidx;
497
498 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
499 /* bsscfgidx 1 is reserved for legacy P2P */
500 if (bsscfgidx == 1)
501 continue;
502 if (!drvr->iflist[bsscfgidx])
503 return bsscfgidx;
504 }
505
506 return -ENOMEM;
507}
508
Hante Meulemana44aa402014-12-03 21:05:33 +0100509static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
510{
511 struct brcmf_mbss_ssid_le mbss_ssid_le;
512 int bsscfgidx;
513 int err;
514
515 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200516 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100517 if (bsscfgidx < 0)
518 return bsscfgidx;
519
520 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
521 mbss_ssid_le.SSID_len = cpu_to_le32(5);
522 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
523
524 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
525 sizeof(mbss_ssid_le));
526 if (err < 0)
527 brcmf_err("setting ssid failed %d\n", err);
528
529 return err;
530}
531
532/**
533 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
534 *
535 * @wiphy: wiphy device of new interface.
536 * @name: name of the new interface.
Hante Meulemana44aa402014-12-03 21:05:33 +0100537 * @params: contains mac address for AP device.
538 */
539static
540struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
Johannes Berg818a9862017-04-12 11:23:28 +0200541 struct vif_params *params)
Hante Meulemana44aa402014-12-03 21:05:33 +0100542{
543 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
544 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
545 struct brcmf_cfg80211_vif *vif;
546 int err;
547
548 if (brcmf_cfg80211_vif_event_armed(cfg))
549 return ERR_PTR(-EBUSY);
550
551 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
552
Rafał Miłecki26072332016-06-06 23:03:55 +0200553 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100554 if (IS_ERR(vif))
555 return (struct wireless_dev *)vif;
556
557 brcmf_cfg80211_arm_vif_event(cfg, vif);
558
559 err = brcmf_cfg80211_request_ap_if(ifp);
560 if (err) {
561 brcmf_cfg80211_arm_vif_event(cfg, NULL);
562 goto fail;
563 }
564
565 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100566 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
567 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100568 brcmf_cfg80211_arm_vif_event(cfg, NULL);
569 if (!err) {
570 brcmf_err("timeout occurred\n");
571 err = -EIO;
572 goto fail;
573 }
574
575 /* interface created in firmware */
576 ifp = vif->ifp;
577 if (!ifp) {
578 brcmf_err("no if pointer provided\n");
579 err = -ENOENT;
580 goto fail;
581 }
582
583 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
584 err = brcmf_net_attach(ifp, true);
585 if (err) {
586 brcmf_err("Registering netdevice failed\n");
Arend Van Sprieldca23072017-06-24 22:08:27 +0100587 free_netdev(ifp->ndev);
Hante Meulemana44aa402014-12-03 21:05:33 +0100588 goto fail;
589 }
590
591 return &ifp->vif->wdev;
592
593fail:
594 brcmf_free_vif(vif);
595 return ERR_PTR(err);
596}
597
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100598static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
599{
600 enum nl80211_iftype iftype;
601
602 iftype = vif->wdev.iftype;
603 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
604}
605
606static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
607{
608 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
609}
610
Arend van Spriel9f440b72013-02-08 15:53:36 +0100611static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
612 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100613 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100614 enum nl80211_iftype type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100615 struct vif_params *params)
616{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200617 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200618 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200619
Arend van Spriel9f440b72013-02-08 15:53:36 +0100620 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200621 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
622 if (err) {
623 brcmf_err("iface validation failed: err=%d\n", err);
624 return ERR_PTR(err);
625 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100626 switch (type) {
627 case NL80211_IFTYPE_ADHOC:
628 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100629 case NL80211_IFTYPE_AP_VLAN:
630 case NL80211_IFTYPE_WDS:
631 case NL80211_IFTYPE_MONITOR:
632 case NL80211_IFTYPE_MESH_POINT:
633 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100634 case NL80211_IFTYPE_AP:
Johannes Berg818a9862017-04-12 11:23:28 +0200635 wdev = brcmf_ap_add_vif(wiphy, name, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200636 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100637 case NL80211_IFTYPE_P2P_CLIENT:
638 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200639 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg818a9862017-04-12 11:23:28 +0200640 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200641 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100642 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100643 default:
644 return ERR_PTR(-EINVAL);
645 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200646
647 if (IS_ERR(wdev))
648 brcmf_err("add iface %s type %d failed: err=%d\n",
649 name, type, (int)PTR_ERR(wdev));
650 else
651 brcmf_cfg80211_update_proto_addr_mode(wdev);
652
653 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100654}
655
Daniel Kim5e787f72014-06-21 12:11:18 +0200656static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
657{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200658 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200659 brcmf_set_mpc(ifp, mpc);
660}
661
Arend van Sprielf96aa072013-04-05 10:57:48 +0200662void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100663{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100664 s32 err = 0;
665
666 if (check_vif_up(ifp->vif)) {
667 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
668 if (err) {
669 brcmf_err("fail to set mpc\n");
670 return;
671 }
672 brcmf_dbg(INFO, "MPC : %d\n", mpc);
673 }
674}
675
Arend van Spriela0f472a2013-04-05 10:57:49 +0200676s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
677 struct brcmf_if *ifp, bool aborted,
678 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100679{
680 struct brcmf_scan_params_le params_le;
681 struct cfg80211_scan_request *scan_request;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100682 u64 reqid;
683 u32 bucket;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100684 s32 err = 0;
685
686 brcmf_dbg(SCAN, "Enter\n");
687
688 /* clear scan request, because the FW abort can cause a second call */
689 /* to this functon and might cause a double cfg80211_scan_done */
690 scan_request = cfg->scan_request;
691 cfg->scan_request = NULL;
692
693 if (timer_pending(&cfg->escan_timeout))
694 del_timer_sync(&cfg->escan_timeout);
695
696 if (fw_abort) {
697 /* Do a scan abort to stop the driver's scan engine */
698 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
699 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800700 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100701 params_le.bss_type = DOT11_BSSTYPE_ANY;
702 params_le.scan_type = 0;
703 params_le.channel_num = cpu_to_le32(1);
704 params_le.nprobes = cpu_to_le32(1);
705 params_le.active_time = cpu_to_le32(-1);
706 params_le.passive_time = cpu_to_le32(-1);
707 params_le.home_time = cpu_to_le32(-1);
708 /* Scan is aborted by setting channel_list[0] to -1 */
709 params_le.channel_list[0] = cpu_to_le16(-1);
710 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200711 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100712 &params_le, sizeof(params_le));
713 if (err)
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100714 brcmf_err("Scan abort failed\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100715 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200716
Daniel Kim5e787f72014-06-21 12:11:18 +0200717 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200718
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100719 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000720 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100721 * which takes precedence.
722 */
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100723 if (cfg->int_escan_map) {
724 brcmf_dbg(SCAN, "scheduled scan completed (%x)\n",
725 cfg->int_escan_map);
726 while (cfg->int_escan_map) {
727 bucket = __ffs(cfg->int_escan_map);
728 cfg->int_escan_map &= ~BIT(bucket);
729 reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno,
730 bucket);
731 if (!aborted) {
732 brcmf_dbg(SCAN, "report results: reqid=%llu\n",
733 reqid);
734 cfg80211_sched_scan_results(cfg_to_wiphy(cfg),
735 reqid);
736 }
737 }
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100738 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300739 struct cfg80211_scan_info info = {
740 .aborted = aborted,
741 };
742
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100743 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
744 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300745 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100746 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100747 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
748 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100749
750 return err;
751}
752
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200753static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
754 struct wireless_dev *wdev)
755{
756 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
757 struct net_device *ndev = wdev->netdev;
758 struct brcmf_if *ifp = netdev_priv(ndev);
759 int ret;
760 int err;
761
762 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
763
764 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
765 if (err) {
766 brcmf_err("interface_remove failed %d\n", err);
767 goto err_unarm;
768 }
769
770 /* wait for firmware event */
771 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
772 BRCMF_VIF_EVENT_TIMEOUT);
773 if (!ret) {
774 brcmf_err("timeout occurred\n");
775 err = -EIO;
776 goto err_unarm;
777 }
778
779 brcmf_remove_interface(ifp, true);
780
781err_unarm:
782 brcmf_cfg80211_arm_vif_event(cfg, NULL);
783 return err;
784}
785
Arend van Spriel9f440b72013-02-08 15:53:36 +0100786static
787int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
788{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100789 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
790 struct net_device *ndev = wdev->netdev;
791
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200792 if (ndev && ndev == cfg_to_ndev(cfg))
793 return -ENOTSUPP;
794
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100795 /* vif event pending in firmware */
796 if (brcmf_cfg80211_vif_event_armed(cfg))
797 return -EBUSY;
798
799 if (ndev) {
800 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200801 cfg->escan_info.ifp == netdev_priv(ndev))
802 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
803 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100804
805 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
806 }
807
Arend van Spriel9f440b72013-02-08 15:53:36 +0100808 switch (wdev->iftype) {
809 case NL80211_IFTYPE_ADHOC:
810 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100811 case NL80211_IFTYPE_AP_VLAN:
812 case NL80211_IFTYPE_WDS:
813 case NL80211_IFTYPE_MONITOR:
814 case NL80211_IFTYPE_MESH_POINT:
815 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200816 case NL80211_IFTYPE_AP:
817 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100818 case NL80211_IFTYPE_P2P_CLIENT:
819 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200820 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100821 return brcmf_p2p_del_vif(wiphy, wdev);
822 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100823 default:
824 return -EINVAL;
825 }
826 return -EOPNOTSUPP;
827}
828
Arend van Spriel5b435de2011-10-05 13:19:03 +0200829static s32
830brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +0200831 enum nl80211_iftype type,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200832 struct vif_params *params)
833{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100834 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700835 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100836 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200837 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200838 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200839 s32 err = 0;
840
Hante Meuleman37a869e2015-10-29 20:33:17 +0100841 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
842 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200843
844 /* WAR: There are a number of p2p interface related problems which
845 * need to be handled initially (before doing the validate).
846 * wpa_supplicant tends to do iface changes on p2p device/client/go
847 * which are not always possible/allowed. However we need to return
848 * OK otherwise the wpa_supplicant wont start. The situation differs
849 * on configuration and setup (p2pon=1 module param). The first check
850 * is to see if the request is a change to station for p2p iface.
851 */
852 if ((type == NL80211_IFTYPE_STATION) &&
853 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
854 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
855 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
856 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
857 /* Now depending on whether module param p2pon=1 was used the
858 * response needs to be either 0 or EOPNOTSUPP. The reason is
859 * that if p2pon=1 is used, but a newer supplicant is used then
860 * we should return an error, as this combination wont work.
861 * In other situations 0 is returned and supplicant will start
862 * normally. It will give a trace in cfg80211, but it is the
863 * only way to get it working. Unfortunately this will result
864 * in situation where we wont support new supplicant in
865 * combination with module param p2pon=1, but that is the way
866 * it is. If the user tries this then unloading of driver might
867 * fail/lock.
868 */
869 if (cfg->p2p.p2pdev_dynamically)
870 return -EOPNOTSUPP;
871 else
872 return 0;
873 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200874 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
875 if (err) {
876 brcmf_err("iface validation failed: err=%d\n", err);
877 return err;
878 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200879 switch (type) {
880 case NL80211_IFTYPE_MONITOR:
881 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100882 brcmf_err("type (%d) : currently we do not support this type\n",
883 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200884 return -EOPNOTSUPP;
885 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200886 infra = 0;
887 break;
888 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200889 infra = 1;
890 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200891 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100892 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200893 ap = 1;
894 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200895 default:
896 err = -EINVAL;
897 goto done;
898 }
899
Hante Meuleman1a873342012-09-27 14:17:54 +0200900 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100901 if (type == NL80211_IFTYPE_P2P_GO) {
902 brcmf_dbg(INFO, "IF Type = P2P GO\n");
903 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
904 }
905 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100906 brcmf_dbg(INFO, "IF Type = AP\n");
907 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200908 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100909 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200910 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100911 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200912 err = -EAGAIN;
913 goto done;
914 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100915 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100916 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200917 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200918 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200919
Hante Meuleman8851cce2014-07-30 13:20:02 +0200920 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
921
Arend van Spriel5b435de2011-10-05 13:19:03 +0200922done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100923 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200924
925 return err;
926}
927
Franky Lin83cf17a2013-04-11 13:28:50 +0200928static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
929 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200930 struct cfg80211_scan_request *request)
931{
932 u32 n_ssids;
933 u32 n_channels;
934 s32 i;
935 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200936 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200937 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200938 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200939
Joe Perches93803b32015-03-02 19:54:49 -0800940 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200941 params_le->bss_type = DOT11_BSSTYPE_ANY;
Arend Van Spriel35f62722017-09-12 10:47:54 +0200942 params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
Hante Meulemane756af52012-09-11 21:18:52 +0200943 params_le->channel_num = 0;
944 params_le->nprobes = cpu_to_le32(-1);
945 params_le->active_time = cpu_to_le32(-1);
946 params_le->passive_time = cpu_to_le32(-1);
947 params_le->home_time = cpu_to_le32(-1);
948 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
949
Hante Meulemane756af52012-09-11 21:18:52 +0200950 n_ssids = request->n_ssids;
951 n_channels = request->n_channels;
Arend Van Spriel35f62722017-09-12 10:47:54 +0200952
Hante Meulemane756af52012-09-11 21:18:52 +0200953 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100954 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
955 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200956 if (n_channels > 0) {
957 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200958 chanspec = channel_to_chanspec(&cfg->d11inf,
959 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100960 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
961 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200962 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200963 }
964 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100965 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200966 }
967 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100968 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200969 if (n_ssids > 0) {
970 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
971 n_channels * sizeof(u16);
972 offset = roundup(offset, sizeof(u32));
973 ptr = (char *)params_le + offset;
974 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200975 memset(&ssid_le, 0, sizeof(ssid_le));
976 ssid_le.SSID_len =
977 cpu_to_le32(request->ssids[i].ssid_len);
978 memcpy(ssid_le.SSID, request->ssids[i].ssid,
979 request->ssids[i].ssid_len);
980 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100981 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200982 else
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100983 brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100984 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200985 memcpy(ptr, &ssid_le, sizeof(ssid_le));
986 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200987 }
988 } else {
Arend Van Spriel35f62722017-09-12 10:47:54 +0200989 brcmf_dbg(SCAN, "Performing passive scan\n");
990 params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
Hante Meulemane756af52012-09-11 21:18:52 +0200991 }
992 /* Adding mask to channel numbers */
993 params_le->channel_num =
994 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
995 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
996}
997
998static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200999brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001000 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001001{
1002 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1003 offsetof(struct brcmf_escan_params_le, params_le);
1004 struct brcmf_escan_params_le *params;
1005 s32 err = 0;
1006
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001007 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001008
1009 if (request != NULL) {
1010 /* Allocate space for populating ssids in struct */
1011 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1012
1013 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001014 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001015 }
1016
1017 params = kzalloc(params_size, GFP_KERNEL);
1018 if (!params) {
1019 err = -ENOMEM;
1020 goto exit;
1021 }
1022 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001023 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001024 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001025 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001026 params->sync_id = cpu_to_le16(0x1234);
1027
Arend van Spriela0f472a2013-04-05 10:57:49 +02001028 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001029 if (err) {
1030 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001031 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001032 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001033 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001034 }
1035
1036 kfree(params);
1037exit:
1038 return err;
1039}
1040
1041static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001042brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001043{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001044 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001045 s32 err;
Hante Meulemane756af52012-09-11 21:18:52 +02001046 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001047 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001048
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001049 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001050 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001051 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001052 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Arend Van Sprielbbf35412017-11-08 14:36:36 +01001053
Daniel Kim5e787f72014-06-21 12:11:18 +02001054 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001055 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001056 results->version = 0;
1057 results->count = 0;
1058 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1059
Hante Meulemanc4958102015-11-25 11:32:41 +01001060 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001061 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001062 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001063 return err;
1064}
1065
1066static s32
Arend Van Spriel588378f2017-11-08 14:36:35 +01001067brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001068{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001069 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel588378f2017-11-08 14:36:35 +01001070 struct brcmf_cfg80211_vif *vif;
1071 s32 err = 0;
Hante Meulemane756af52012-09-11 21:18:52 +02001072
Arend Van Spriel588378f2017-11-08 14:36:35 +01001073 brcmf_dbg(TRACE, "Enter\n");
1074 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1075 if (!check_vif_up(vif))
1076 return -EIO;
Hante Meulemane756af52012-09-11 21:18:52 +02001077
Arend van Sprielc1179032012-10-22 13:55:33 -07001078 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001079 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001080 return -EAGAIN;
1081 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001082 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001083 brcmf_err("Scanning being aborted: status (%lu)\n",
1084 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001085 return -EAGAIN;
1086 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001087 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1088 brcmf_err("Scanning suppressed: status (%lu)\n",
1089 cfg->scan_status);
1090 return -EAGAIN;
1091 }
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001092 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
1093 brcmf_err("Connecting: status (%lu)\n", vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001094 return -EAGAIN;
1095 }
1096
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001097 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001098 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1099 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001100
Arend Van Spriel588378f2017-11-08 14:36:35 +01001101 brcmf_dbg(SCAN, "START ESCAN\n");
1102
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001103 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001104 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001105
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001106 cfg->escan_info.run = brcmf_run_escan;
1107 err = brcmf_p2p_scan_prep(wiphy, request, vif);
1108 if (err)
1109 goto scan_out;
Hante Meulemane756af52012-09-11 21:18:52 +02001110
Arend Van Sprielbd99a302017-11-08 14:36:37 +01001111 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
1112 request->ie, request->ie_len);
1113 if (err)
1114 goto scan_out;
1115
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001116 err = brcmf_do_escan(vif->ifp, request);
1117 if (err)
1118 goto scan_out;
Hante Meulemane756af52012-09-11 21:18:52 +02001119
Hante Meuleman661fa952015-02-06 18:36:47 +01001120 /* Arm scan timeout timer */
Arend Van Sprieldf2d8382017-11-08 14:36:34 +01001121 mod_timer(&cfg->escan_timeout,
1122 jiffies + msecs_to_jiffies(BRCMF_ESCAN_TIMER_INTERVAL_MS));
Hante Meuleman661fa952015-02-06 18:36:47 +01001123
Hante Meulemane756af52012-09-11 21:18:52 +02001124 return 0;
1125
1126scan_out:
Arend Van Spriel588378f2017-11-08 14:36:35 +01001127 brcmf_err("scan error (%d)\n", err);
Arend van Sprielc1179032012-10-22 13:55:33 -07001128 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001129 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001130 return err;
1131}
1132
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1134{
1135 s32 err = 0;
1136
Arend van Sprielac24be62012-10-22 10:36:23 -07001137 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1138 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001139 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001140 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001141
1142 return err;
1143}
1144
1145static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1146{
1147 s32 err = 0;
1148
Arend van Sprielac24be62012-10-22 10:36:23 -07001149 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1150 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001151 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001152 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001153
1154 return err;
1155}
1156
1157static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1158{
1159 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001160 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001161
Arend van Sprielac24be62012-10-22 10:36:23 -07001162 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001164 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165 return err;
1166 }
1167 return err;
1168}
1169
1170static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1171{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001172 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1173 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001174 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001175 s32 err = 0;
1176
Arend van Sprield96b8012012-12-05 15:26:02 +01001177 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001178 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179 return -EIO;
1180
1181 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001182 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1183 cfg->conf->rts_threshold = wiphy->rts_threshold;
1184 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001185 if (!err)
1186 goto done;
1187 }
1188 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001189 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1190 cfg->conf->frag_threshold = wiphy->frag_threshold;
1191 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001192 if (!err)
1193 goto done;
1194 }
1195 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001196 && (cfg->conf->retry_long != wiphy->retry_long)) {
1197 cfg->conf->retry_long = wiphy->retry_long;
1198 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 if (!err)
1200 goto done;
1201 }
1202 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001203 && (cfg->conf->retry_short != wiphy->retry_short)) {
1204 cfg->conf->retry_short = wiphy->retry_short;
1205 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001206 if (!err)
1207 goto done;
1208 }
1209
1210done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001211 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001212 return err;
1213}
1214
Arend van Spriel5b435de2011-10-05 13:19:03 +02001215static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1216{
1217 memset(prof, 0, sizeof(*prof));
1218}
1219
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001220static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1221{
1222 u16 reason;
1223
1224 switch (e->event_code) {
1225 case BRCMF_E_DEAUTH:
1226 case BRCMF_E_DEAUTH_IND:
1227 case BRCMF_E_DISASSOC_IND:
1228 reason = e->reason;
1229 break;
1230 case BRCMF_E_LINK:
1231 default:
1232 reason = 0;
1233 break;
1234 }
1235 return reason;
1236}
1237
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001238static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
1239{
1240 struct brcmf_wsec_pmk_le pmk;
1241 int i, err;
1242
1243 /* convert to firmware key format */
1244 pmk.key_len = cpu_to_le16(pmk_len << 1);
1245 pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
1246 for (i = 0; i < pmk_len; i++)
1247 snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
1248
1249 /* store psk in firmware */
1250 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
1251 &pmk, sizeof(pmk));
1252 if (err < 0)
1253 brcmf_err("failed to change PSK in firmware (len=%u)\n",
1254 pmk_len);
1255
1256 return err;
1257}
1258
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001259static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001260{
Piotr Haber61730d42013-04-23 12:53:12 +02001261 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262 s32 err = 0;
1263
Arend van Sprield96b8012012-12-05 15:26:02 +01001264 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001265
Hante Meulemanb0a79082015-12-10 13:43:07 +01001266 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001267 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001268 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001269 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001270 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001271 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001272 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001273 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1274 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1275 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1276 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001277 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001278 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001279 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1280 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001281 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
1282 brcmf_set_pmk(vif->ifp, NULL, 0);
1283 vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1284 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001285 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001286}
1287
1288static s32
1289brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1290 struct cfg80211_ibss_params *params)
1291{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001292 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001293 struct brcmf_if *ifp = netdev_priv(ndev);
1294 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295 struct brcmf_join_params join_params;
1296 size_t join_params_size = 0;
1297 s32 err = 0;
1298 s32 wsec = 0;
1299 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001300 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001301 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001302
Arend van Sprield96b8012012-12-05 15:26:02 +01001303 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001304 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 return -EIO;
1306
1307 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001308 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001309 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001310 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001311 return -EOPNOTSUPP;
1312 }
1313
Arend van Sprielc1179032012-10-22 13:55:33 -07001314 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001315
1316 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001317 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318 else
Arend van Spriel16886732012-12-05 15:26:04 +01001319 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001320
Johannes Berg683b6d32012-11-08 21:25:48 +01001321 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001322 brcmf_dbg(CONN, "channel: %d\n",
1323 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324 else
Arend van Spriel16886732012-12-05 15:26:04 +01001325 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326
1327 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001328 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329 else
Arend van Spriel16886732012-12-05 15:26:04 +01001330 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001331
1332 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001333 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334 else
Arend van Spriel16886732012-12-05 15:26:04 +01001335 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001336
1337 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001338 brcmf_dbg(CONN, "beacon interval: %d\n",
1339 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001340 else
Arend van Spriel16886732012-12-05 15:26:04 +01001341 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001342
1343 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001344 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001345 else
Arend van Spriel16886732012-12-05 15:26:04 +01001346 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001347
1348 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001349 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350 else
Arend van Spriel16886732012-12-05 15:26:04 +01001351 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001352
1353 /* Configure Privacy for starter */
1354 if (params->privacy)
1355 wsec |= WEP_ENABLED;
1356
Arend van Sprielc1179032012-10-22 13:55:33 -07001357 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001358 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001359 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001360 goto done;
1361 }
1362
1363 /* Configure Beacon Interval for starter */
1364 if (params->beacon_interval)
1365 bcnprd = params->beacon_interval;
1366 else
1367 bcnprd = 100;
1368
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001369 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001370 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001371 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001372 goto done;
1373 }
1374
1375 /* Configure required join parameter */
1376 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1377
1378 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001379 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1380 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1381 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001382 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001383
1384 /* BSSID */
1385 if (params->bssid) {
1386 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001387 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001388 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001389 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001390 eth_broadcast_addr(join_params.params_le.bssid);
1391 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001392 }
1393
Arend van Spriel5b435de2011-10-05 13:19:03 +02001394 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001395 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001396 u32 target_channel;
1397
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001398 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001400 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001401 if (params->channel_fixed) {
1402 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001403 chanspec = chandef_to_chanspec(&cfg->d11inf,
1404 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001405 join_params.params_le.chanspec_list[0] =
1406 cpu_to_le16(chanspec);
1407 join_params.params_le.chanspec_num = cpu_to_le32(1);
1408 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001409 }
1410
1411 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001412 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001413 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001414 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001416 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 goto done;
1418 }
1419 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001420 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001421
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001422 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001423
1424
Arend van Sprielc1179032012-10-22 13:55:33 -07001425 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001426 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001428 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 goto done;
1430 }
1431
1432done:
1433 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001434 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001435 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436 return err;
1437}
1438
1439static s32
1440brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1441{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001442 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001443
Arend van Sprield96b8012012-12-05 15:26:02 +01001444 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001445 if (!check_vif_up(ifp->vif)) {
1446 /* When driver is being unloaded, it can end up here. If an
1447 * error is returned then later on a debug trace in the wireless
1448 * core module will be printed. To avoid this 0 is returned.
1449 */
1450 return 0;
1451 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001453 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001454 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001455
Arend van Sprield96b8012012-12-05 15:26:02 +01001456 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001457
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001458 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001459}
1460
1461static s32 brcmf_set_wpa_version(struct net_device *ndev,
1462 struct cfg80211_connect_params *sme)
1463{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001464 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001465 struct brcmf_cfg80211_security *sec;
1466 s32 val = 0;
1467 s32 err = 0;
1468
1469 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1470 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1471 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1472 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1473 else
1474 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001475 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001476 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001477 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001478 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479 return err;
1480 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001481 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 sec->wpa_versions = sme->crypto.wpa_versions;
1483 return err;
1484}
1485
1486static s32 brcmf_set_auth_type(struct net_device *ndev,
1487 struct cfg80211_connect_params *sme)
1488{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001489 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001490 struct brcmf_cfg80211_security *sec;
1491 s32 val = 0;
1492 s32 err = 0;
1493
1494 switch (sme->auth_type) {
1495 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1496 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001497 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001498 break;
1499 case NL80211_AUTHTYPE_SHARED_KEY:
1500 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001501 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001502 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001503 default:
1504 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001505 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001506 break;
1507 }
1508
Hante Meuleman89286dc2013-02-08 15:53:46 +01001509 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001511 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512 return err;
1513 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001514 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001515 sec->auth_type = sme->auth_type;
1516 return err;
1517}
1518
1519static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001520brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001521 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001522{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001523 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524 struct brcmf_cfg80211_security *sec;
1525 s32 pval = 0;
1526 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001527 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001528 s32 err = 0;
1529
1530 if (sme->crypto.n_ciphers_pairwise) {
1531 switch (sme->crypto.ciphers_pairwise[0]) {
1532 case WLAN_CIPHER_SUITE_WEP40:
1533 case WLAN_CIPHER_SUITE_WEP104:
1534 pval = WEP_ENABLED;
1535 break;
1536 case WLAN_CIPHER_SUITE_TKIP:
1537 pval = TKIP_ENABLED;
1538 break;
1539 case WLAN_CIPHER_SUITE_CCMP:
1540 pval = AES_ENABLED;
1541 break;
1542 case WLAN_CIPHER_SUITE_AES_CMAC:
1543 pval = AES_ENABLED;
1544 break;
1545 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001546 brcmf_err("invalid cipher pairwise (%d)\n",
1547 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001548 return -EINVAL;
1549 }
1550 }
1551 if (sme->crypto.cipher_group) {
1552 switch (sme->crypto.cipher_group) {
1553 case WLAN_CIPHER_SUITE_WEP40:
1554 case WLAN_CIPHER_SUITE_WEP104:
1555 gval = WEP_ENABLED;
1556 break;
1557 case WLAN_CIPHER_SUITE_TKIP:
1558 gval = TKIP_ENABLED;
1559 break;
1560 case WLAN_CIPHER_SUITE_CCMP:
1561 gval = AES_ENABLED;
1562 break;
1563 case WLAN_CIPHER_SUITE_AES_CMAC:
1564 gval = AES_ENABLED;
1565 break;
1566 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001567 brcmf_err("invalid cipher group (%d)\n",
1568 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569 return -EINVAL;
1570 }
1571 }
1572
Arend van Spriel16886732012-12-05 15:26:04 +01001573 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001574 /* In case of privacy, but no security and WPS then simulate */
1575 /* setting AES. WPS-2.0 allows no security */
1576 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1577 sme->privacy)
1578 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001579
Hante Meuleman240d61a2016-02-17 11:27:10 +01001580 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001581 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001583 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001584 return err;
1585 }
1586
Arend van Spriel06bb1232012-09-27 14:17:56 +02001587 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001588 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1589 sec->cipher_group = sme->crypto.cipher_group;
1590
1591 return err;
1592}
1593
1594static s32
1595brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1596{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001597 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001598 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001599 s32 val;
1600 s32 err;
1601 const struct brcmf_tlv *rsn_ie;
1602 const u8 *ie;
1603 u32 ie_len;
1604 u32 offset;
1605 u16 rsn_cap;
1606 u32 mfp;
1607 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001608
Arend van Spriel2526ff22017-06-09 13:08:48 +01001609 profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1610
Hante Meuleman240d61a2016-02-17 11:27:10 +01001611 if (!sme->crypto.n_akm_suites)
1612 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001613
Hante Meuleman240d61a2016-02-17 11:27:10 +01001614 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1615 if (err) {
1616 brcmf_err("could not get wpa_auth (%d)\n", err);
1617 return err;
1618 }
1619 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1620 switch (sme->crypto.akm_suites[0]) {
1621 case WLAN_AKM_SUITE_8021X:
1622 val = WPA_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001623 if (sme->want_1x)
1624 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001625 break;
1626 case WLAN_AKM_SUITE_PSK:
1627 val = WPA_AUTH_PSK;
1628 break;
1629 default:
1630 brcmf_err("invalid cipher group (%d)\n",
1631 sme->crypto.cipher_group);
1632 return -EINVAL;
1633 }
1634 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1635 switch (sme->crypto.akm_suites[0]) {
1636 case WLAN_AKM_SUITE_8021X:
1637 val = WPA2_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001638 if (sme->want_1x)
1639 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001640 break;
1641 case WLAN_AKM_SUITE_8021X_SHA256:
1642 val = WPA2_AUTH_1X_SHA256;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001643 if (sme->want_1x)
1644 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001645 break;
1646 case WLAN_AKM_SUITE_PSK_SHA256:
1647 val = WPA2_AUTH_PSK_SHA256;
1648 break;
1649 case WLAN_AKM_SUITE_PSK:
1650 val = WPA2_AUTH_PSK;
1651 break;
1652 default:
1653 brcmf_err("invalid cipher group (%d)\n",
1654 sme->crypto.cipher_group);
1655 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001656 }
1657 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001658
Arend van Spriel2526ff22017-06-09 13:08:48 +01001659 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
1660 brcmf_dbg(INFO, "using 1X offload\n");
1661
Hante Meuleman240d61a2016-02-17 11:27:10 +01001662 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1663 goto skip_mfp_config;
1664 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1665 * IE will not be verified, just a quick search for MFP config
1666 */
1667 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1668 WLAN_EID_RSN);
1669 if (!rsn_ie)
1670 goto skip_mfp_config;
1671 ie = (const u8 *)rsn_ie;
1672 ie_len = rsn_ie->len + TLV_HDR_LEN;
1673 /* Skip unicast suite */
1674 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1675 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1676 goto skip_mfp_config;
1677 /* Skip multicast suite */
1678 count = ie[offset] + (ie[offset + 1] << 8);
1679 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1680 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1681 goto skip_mfp_config;
1682 /* Skip auth key management suite(s) */
1683 count = ie[offset] + (ie[offset + 1] << 8);
1684 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1685 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1686 goto skip_mfp_config;
1687 /* Ready to read capabilities */
1688 mfp = BRCMF_MFP_NONE;
1689 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1690 if (rsn_cap & RSN_CAP_MFPR_MASK)
1691 mfp = BRCMF_MFP_REQUIRED;
1692 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1693 mfp = BRCMF_MFP_CAPABLE;
1694 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1695
1696skip_mfp_config:
1697 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1698 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1699 if (err) {
1700 brcmf_err("could not set wpa_auth (%d)\n", err);
1701 return err;
1702 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001703
1704 return err;
1705}
1706
1707static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001708brcmf_set_sharedkey(struct net_device *ndev,
1709 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001710{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001711 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001712 struct brcmf_cfg80211_security *sec;
1713 struct brcmf_wsec_key key;
1714 s32 val;
1715 s32 err = 0;
1716
Arend van Spriel16886732012-12-05 15:26:04 +01001717 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001718
Roland Vossena718e2f2011-10-12 20:51:24 +02001719 if (sme->key_len == 0)
1720 return 0;
1721
Arend van Spriel06bb1232012-09-27 14:17:56 +02001722 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001723 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1724 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001725
1726 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1727 return 0;
1728
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001729 if (!(sec->cipher_pairwise &
1730 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1731 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001732
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001733 memset(&key, 0, sizeof(key));
1734 key.len = (u32) sme->key_len;
1735 key.index = (u32) sme->key_idx;
1736 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001737 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001738 return -EINVAL;
1739 }
1740 memcpy(key.data, sme->key, key.len);
1741 key.flags = BRCMF_PRIMARY_KEY;
1742 switch (sec->cipher_pairwise) {
1743 case WLAN_CIPHER_SUITE_WEP40:
1744 key.algo = CRYPTO_ALGO_WEP1;
1745 break;
1746 case WLAN_CIPHER_SUITE_WEP104:
1747 key.algo = CRYPTO_ALGO_WEP128;
1748 break;
1749 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001750 brcmf_err("Invalid algorithm (%d)\n",
1751 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001752 return -EINVAL;
1753 }
1754 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001755 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1756 key.len, key.index, key.algo);
1757 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001758 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001759 if (err)
1760 return err;
1761
1762 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001763 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001764 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001765 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001766 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001767 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001768 }
1769 return err;
1770}
1771
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001772static
1773enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1774 enum nl80211_auth_type type)
1775{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001776 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1777 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1778 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1779 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001780 }
1781 return type;
1782}
1783
Arend van Spriel7705ba62016-04-17 16:44:58 +02001784static void brcmf_set_join_pref(struct brcmf_if *ifp,
1785 struct cfg80211_bss_selection *bss_select)
1786{
1787 struct brcmf_join_pref_params join_pref_params[2];
1788 enum nl80211_band band;
1789 int err, i = 0;
1790
1791 join_pref_params[i].len = 2;
1792 join_pref_params[i].rssi_gain = 0;
1793
1794 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1795 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1796
1797 switch (bss_select->behaviour) {
1798 case __NL80211_BSS_SELECT_ATTR_INVALID:
1799 brcmf_c_set_joinpref_default(ifp);
1800 return;
1801 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1802 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1803 band = bss_select->param.band_pref;
1804 join_pref_params[i].band = nl80211_band_to_fwil(band);
1805 i++;
1806 break;
1807 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1808 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1809 band = bss_select->param.adjust.band;
1810 join_pref_params[i].band = nl80211_band_to_fwil(band);
1811 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1812 i++;
1813 break;
1814 case NL80211_BSS_SELECT_ATTR_RSSI:
1815 default:
1816 break;
1817 }
1818 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1819 join_pref_params[i].len = 2;
1820 join_pref_params[i].rssi_gain = 0;
1821 join_pref_params[i].band = 0;
1822 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1823 sizeof(join_pref_params));
1824 if (err)
1825 brcmf_err("Set join_pref error (%d)\n", err);
1826}
1827
Arend van Spriel5b435de2011-10-05 13:19:03 +02001828static s32
1829brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001830 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001831{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001832 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001833 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001834 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001835 struct ieee80211_channel *chan = sme->channel;
1836 struct brcmf_join_params join_params;
1837 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001838 const struct brcmf_tlv *rsn_ie;
1839 const struct brcmf_vs_tlv *wpa_ie;
1840 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001841 u32 ie_len;
1842 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001843 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001845 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846
Arend van Sprield96b8012012-12-05 15:26:02 +01001847 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001848 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001849 return -EIO;
1850
1851 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001852 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001853 return -EOPNOTSUPP;
1854 }
1855
Hante Meuleman89286dc2013-02-08 15:53:46 +01001856 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1857 /* A normal (non P2P) connection request setup. */
1858 ie = NULL;
1859 ie_len = 0;
1860 /* find the WPA_IE */
1861 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1862 if (wpa_ie) {
1863 ie = wpa_ie;
1864 ie_len = wpa_ie->len + TLV_HDR_LEN;
1865 } else {
1866 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001867 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1868 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001869 WLAN_EID_RSN);
1870 if (rsn_ie) {
1871 ie = rsn_ie;
1872 ie_len = rsn_ie->len + TLV_HDR_LEN;
1873 }
1874 }
1875 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1876 }
1877
1878 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1879 sme->ie, sme->ie_len);
1880 if (err)
1881 brcmf_err("Set Assoc REQ IE Failed\n");
1882 else
1883 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1884
Arend van Sprielc1179032012-10-22 13:55:33 -07001885 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001886
1887 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001888 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001890 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001891 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1892 cfg->channel, chan->center_freq, chanspec);
1893 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001894 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001895 chanspec = 0;
1896 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001897
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001898 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001899
1900 err = brcmf_set_wpa_version(ndev, sme);
1901 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001902 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903 goto done;
1904 }
1905
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001906 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001907 err = brcmf_set_auth_type(ndev, sme);
1908 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001909 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 goto done;
1911 }
1912
Hante Meuleman240d61a2016-02-17 11:27:10 +01001913 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001914 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001915 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001916 goto done;
1917 }
1918
1919 err = brcmf_set_key_mgmt(ndev, sme);
1920 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001921 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001922 goto done;
1923 }
1924
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001925 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001926 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001927 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001928 goto done;
1929 }
1930
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001931 if (sme->crypto.psk) {
Arend van Spriel2526ff22017-06-09 13:08:48 +01001932 if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
1933 err = -EINVAL;
1934 goto done;
1935 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001936 brcmf_dbg(INFO, "using PSK offload\n");
Arend van Spriel2526ff22017-06-09 13:08:48 +01001937 profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
1938 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001939
Arend van Spriel2526ff22017-06-09 13:08:48 +01001940 if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001941 /* enable firmware supplicant for this interface */
1942 err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
1943 if (err < 0) {
1944 brcmf_err("failed to enable fw supplicant\n");
1945 goto done;
1946 }
Arend van Spriel2526ff22017-06-09 13:08:48 +01001947 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001948
Arend van Spriel2526ff22017-06-09 13:08:48 +01001949 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001950 err = brcmf_set_pmk(ifp, sme->crypto.psk,
1951 BRCMF_WSEC_MAX_PSK_LEN);
1952 if (err)
1953 goto done;
1954 }
1955
Hante Meuleman89286dc2013-02-08 15:53:46 +01001956 /* Join with specific BSSID and cached SSID
1957 * If SSID is zero join based on BSSID only
1958 */
1959 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1960 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1961 if (cfg->channel)
1962 join_params_size += sizeof(u16);
1963 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1964 if (ext_join_params == NULL) {
1965 err = -ENOMEM;
1966 goto done;
1967 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001968 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1969 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1970 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1971 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1972 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1973 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001974
Hante Meuleman89286dc2013-02-08 15:53:46 +01001975 /* Set up join scan parameters */
1976 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001977 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1978
1979 if (sme->bssid)
1980 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1981 else
Joe Perches93803b32015-03-02 19:54:49 -08001982 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001983
1984 if (cfg->channel) {
1985 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1986
1987 ext_join_params->assoc_le.chanspec_list[0] =
1988 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001989 /* Increase dwell time to receive probe response or detect
1990 * beacon from target AP at a noisy air only during connect
1991 * command.
1992 */
1993 ext_join_params->scan_le.active_time =
1994 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1995 ext_join_params->scan_le.passive_time =
1996 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1997 /* To sync with presence period of VSDB GO send probe request
1998 * more frequently. Probe request will be stopped when it gets
1999 * probe response from target AP/GO.
2000 */
2001 ext_join_params->scan_le.nprobes =
2002 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2003 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2004 } else {
2005 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2006 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2007 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002008 }
2009
Arend van Spriel7705ba62016-04-17 16:44:58 +02002010 brcmf_set_join_pref(ifp, &sme->bss_select);
2011
Hante Meuleman89286dc2013-02-08 15:53:46 +01002012 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2013 join_params_size);
2014 kfree(ext_join_params);
2015 if (!err)
2016 /* This is it. join command worked, we are done */
2017 goto done;
2018
2019 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002020 memset(&join_params, 0, sizeof(join_params));
2021 join_params_size = sizeof(join_params.ssid_le);
2022
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002023 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2024 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002025
Hante Meuleman89286dc2013-02-08 15:53:46 +01002026 if (sme->bssid)
2027 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2028 else
Joe Perches93803b32015-03-02 19:54:49 -08002029 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002030
Hante Meuleman17012612013-02-06 18:40:44 +01002031 if (cfg->channel) {
2032 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2033 join_params.params_le.chanspec_num = cpu_to_le32(1);
2034 join_params_size += sizeof(join_params.params_le);
2035 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002036 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002037 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002038 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002039 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002040
2041done:
2042 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002043 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002044 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002045 return err;
2046}
2047
2048static s32
2049brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2050 u16 reason_code)
2051{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002052 struct brcmf_if *ifp = netdev_priv(ndev);
2053 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054 struct brcmf_scb_val_le scbval;
2055 s32 err = 0;
2056
Arend van Sprield96b8012012-12-05 15:26:02 +01002057 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002058 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002059 return -EIO;
2060
Arend van Sprielc1179032012-10-22 13:55:33 -07002061 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002062 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002063 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064
Arend van Spriel06bb1232012-09-27 14:17:56 +02002065 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002067 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002068 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002070 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002071
Arend van Sprield96b8012012-12-05 15:26:02 +01002072 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002073 return err;
2074}
2075
2076static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002077brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002078 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002079{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002080 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002081 struct net_device *ndev = cfg_to_ndev(cfg);
2082 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002083 s32 err;
2084 s32 disable;
2085 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002086
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002087 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002088 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 return -EIO;
2090
2091 switch (type) {
2092 case NL80211_TX_POWER_AUTOMATIC:
2093 break;
2094 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002096 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002097 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002098 err = -EINVAL;
2099 goto done;
2100 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002101 qdbm = MBM_TO_DBM(4 * mbm);
2102 if (qdbm > 127)
2103 qdbm = 127;
2104 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002106 default:
2107 brcmf_err("Unsupported type %d\n", type);
2108 err = -EINVAL;
2109 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002110 }
2111 /* Make sure radio is off or on as far as software is concerned */
2112 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002113 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002115 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002116
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002117 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002118 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002119 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120
2121done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002122 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 return err;
2124}
2125
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002126static s32
2127brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2128 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002130 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002131 struct net_device *ndev = cfg_to_ndev(cfg);
2132 struct brcmf_if *ifp = netdev_priv(ndev);
2133 s32 qdbm = 0;
2134 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135
Arend van Sprield96b8012012-12-05 15:26:02 +01002136 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002137 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002138 return -EIO;
2139
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002140 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002142 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002143 goto done;
2144 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002145 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002146
2147done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002148 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 return err;
2150}
2151
2152static s32
2153brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002154 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002156 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157 u32 index;
2158 u32 wsec;
2159 s32 err = 0;
2160
Arend van Sprield96b8012012-12-05 15:26:02 +01002161 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002162 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002163 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 return -EIO;
2165
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002166 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002168 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 goto done;
2170 }
2171
2172 if (wsec & WEP_ENABLED) {
2173 /* Just select a new current key */
2174 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002175 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002176 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002177 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002178 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002179 }
2180done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002181 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002182 return err;
2183}
2184
2185static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002186brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2187 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002188{
Hante Meuleman992f6062013-04-02 21:06:17 +02002189 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002190 struct brcmf_wsec_key *key;
2191 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002192
2193 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002194 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2195
Hante Meuleman219e0f72016-02-17 11:27:09 +01002196 if (!check_vif_up(ifp->vif))
2197 return -EIO;
2198
2199 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2200 /* we ignore this key index in this case */
2201 return -EINVAL;
2202 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002203
Hante Meuleman240d61a2016-02-17 11:27:10 +01002204 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002205
Hante Meuleman240d61a2016-02-17 11:27:10 +01002206 if (key->algo == CRYPTO_ALGO_OFF) {
2207 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2208 return -EINVAL;
2209 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002210
Hante Meuleman240d61a2016-02-17 11:27:10 +01002211 memset(key, 0, sizeof(*key));
2212 key->index = (u32)key_idx;
2213 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002214
Hante Meuleman240d61a2016-02-17 11:27:10 +01002215 /* Clear the key/index */
2216 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217
Hante Meuleman219e0f72016-02-17 11:27:09 +01002218 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002219 return err;
2220}
2221
2222static s32
2223brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002224 u8 key_idx, bool pairwise, const u8 *mac_addr,
2225 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002226{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002227 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002228 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229 s32 val;
2230 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002231 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002233 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002234
Arend van Sprield96b8012012-12-05 15:26:02 +01002235 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002236 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002237 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238 return -EIO;
2239
Hante Meuleman118eb302014-12-21 12:43:49 +01002240 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2241 /* we ignore this key index in this case */
2242 brcmf_err("invalid key index (%d)\n", key_idx);
2243 return -EINVAL;
2244 }
2245
Hante Meuleman219e0f72016-02-17 11:27:09 +01002246 if (params->key_len == 0)
2247 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2248 mac_addr);
2249
2250 if (params->key_len > sizeof(key->data)) {
2251 brcmf_err("Too long key length (%u)\n", params->key_len);
2252 return -EINVAL;
2253 }
2254
2255 ext_key = false;
2256 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2257 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2258 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2259 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002261
Hante Meuleman118eb302014-12-21 12:43:49 +01002262 key = &ifp->vif->profile.key[key_idx];
2263 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002264 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2265 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002266 key->len = params->key_len;
2267 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002268 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002269 if (!ext_key)
2270 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002271
Arend van Spriel5b435de2011-10-05 13:19:03 +02002272 switch (params->cipher) {
2273 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002274 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002275 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002276 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277 break;
2278 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002279 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002280 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002281 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002282 break;
2283 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002284 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002285 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002286 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2287 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2288 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002289 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002290 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002291 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002292 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002293 break;
2294 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002295 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002296 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002297 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002298 break;
2299 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002300 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002301 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002302 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002303 break;
2304 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002305 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306 err = -EINVAL;
2307 goto done;
2308 }
2309
Hante Meuleman118eb302014-12-21 12:43:49 +01002310 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002311 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002312 goto done;
2313
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002314 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002315 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002316 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002317 goto done;
2318 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002319 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002320 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002321 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002322 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 goto done;
2324 }
2325
Arend van Spriel5b435de2011-10-05 13:19:03 +02002326done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002327 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002328 return err;
2329}
2330
2331static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002332brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2333 bool pairwise, const u8 *mac_addr, void *cookie,
2334 void (*callback)(void *cookie,
2335 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336{
2337 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002338 struct brcmf_if *ifp = netdev_priv(ndev);
2339 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002340 struct brcmf_cfg80211_security *sec;
2341 s32 wsec;
2342 s32 err = 0;
2343
Arend van Sprield96b8012012-12-05 15:26:02 +01002344 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002345 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002346 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002347 return -EIO;
2348
2349 memset(&params, 0, sizeof(params));
2350
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002351 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002353 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002354 /* Ignore this error, may happen during DISASSOC */
2355 err = -EAGAIN;
2356 goto done;
2357 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002358 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002359 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2361 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002362 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2364 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002365 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002367 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002368 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002369 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002370 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002372 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002373 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002374 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002375 err = -EINVAL;
2376 goto done;
2377 }
2378 callback(cookie, &params);
2379
2380done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002381 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 return err;
2383}
2384
2385static s32
2386brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002387 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002388{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002389 struct brcmf_if *ifp = netdev_priv(ndev);
2390
2391 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2392
2393 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2394 return 0;
2395
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002396 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002397
2398 return -EOPNOTSUPP;
2399}
2400
Hante Meuleman118eb302014-12-21 12:43:49 +01002401static void
2402brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2403{
2404 s32 err;
2405 u8 key_idx;
2406 struct brcmf_wsec_key *key;
2407 s32 wsec;
2408
2409 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2410 key = &ifp->vif->profile.key[key_idx];
2411 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2412 (key->algo == CRYPTO_ALGO_WEP128))
2413 break;
2414 }
2415 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2416 return;
2417
2418 err = send_key_to_dongle(ifp, key);
2419 if (err) {
2420 brcmf_err("Setting WEP key failed (%d)\n", err);
2421 return;
2422 }
2423 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2424 if (err) {
2425 brcmf_err("get wsec error (%d)\n", err);
2426 return;
2427 }
2428 wsec |= WEP_ENABLED;
2429 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2430 if (err)
2431 brcmf_err("set wsec error (%d)\n", err);
2432}
2433
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002434static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2435{
2436 struct nl80211_sta_flag_update *sfu;
2437
2438 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2439 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2440 sfu = &si->sta_flags;
2441 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2442 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2443 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2444 BIT(NL80211_STA_FLAG_AUTHORIZED);
2445 if (fw_sta_flags & BRCMF_STA_WME)
2446 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2447 if (fw_sta_flags & BRCMF_STA_AUTHE)
2448 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2449 if (fw_sta_flags & BRCMF_STA_ASSOC)
2450 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2451 if (fw_sta_flags & BRCMF_STA_AUTHO)
2452 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2453}
2454
2455static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2456{
2457 struct {
2458 __le32 len;
2459 struct brcmf_bss_info_le bss_le;
2460 } *buf;
2461 u16 capability;
2462 int err;
2463
2464 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2465 if (!buf)
2466 return;
2467
2468 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2469 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2470 WL_BSS_INFO_MAX);
2471 if (err) {
2472 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002473 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002474 }
2475 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2476 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2477 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2478 capability = le16_to_cpu(buf->bss_le.capability);
2479 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2480 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2481 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2482 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2483 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2484 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002485
2486out_kfree:
2487 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002488}
2489
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002491brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2492 struct station_info *sinfo)
2493{
2494 struct brcmf_scb_val_le scbval;
2495 struct brcmf_pktcnt_le pktcnt;
2496 s32 err;
2497 u32 rate;
2498 u32 rssi;
2499
2500 /* Get the current tx rate */
2501 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2502 if (err < 0) {
2503 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2504 return err;
2505 }
2506 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2507 sinfo->txrate.legacy = rate * 5;
2508
2509 memset(&scbval, 0, sizeof(scbval));
2510 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2511 sizeof(scbval));
2512 if (err) {
2513 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2514 return err;
2515 }
2516 rssi = le32_to_cpu(scbval.val);
2517 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2518 sinfo->signal = rssi;
2519
2520 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2521 sizeof(pktcnt));
2522 if (err) {
2523 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2524 return err;
2525 }
2526 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2527 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2528 BIT(NL80211_STA_INFO_TX_PACKETS) |
2529 BIT(NL80211_STA_INFO_TX_FAILED);
2530 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2531 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2532 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2533 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2534
2535 return 0;
2536}
2537
2538static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002539brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002540 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002541{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002542 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002543 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002544 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002545 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002546 u32 sta_flags;
2547 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002548 s32 total_rssi;
2549 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002550 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002551 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002552
Arend van Sprield96b8012012-12-05 15:26:02 +01002553 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002554 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002555 return -EIO;
2556
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002557 if (brcmf_is_ibssmode(ifp->vif))
2558 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2559
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002560 memset(&sta_info_le, 0, sizeof(sta_info_le));
2561 memcpy(&sta_info_le, mac, ETH_ALEN);
2562 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2563 &sta_info_le,
2564 sizeof(sta_info_le));
2565 is_tdls_peer = !err;
2566 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002567 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002568 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002569 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002570 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002571 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002572 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002573 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002574 }
2575 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2576 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2577 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2578 sta_flags = le32_to_cpu(sta_info_le.flags);
2579 brcmf_convert_sta_flags(sta_flags, sinfo);
2580 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2581 if (is_tdls_peer)
2582 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2583 else
2584 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2585 if (sta_flags & BRCMF_STA_ASSOC) {
2586 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2587 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2588 brcmf_fill_bss_param(ifp, sinfo);
2589 }
2590 if (sta_flags & BRCMF_STA_SCBSTATS) {
2591 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2592 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2593 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2594 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2595 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2596 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2597 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2598 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2599 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002600 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002601 sinfo->txrate.legacy =
2602 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002603 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002604 if (sinfo->rx_packets) {
2605 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002606 sinfo->rxrate.legacy =
2607 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002608 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002609 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2610 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2611 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2612 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2613 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2614 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002615 total_rssi = 0;
2616 count_rssi = 0;
2617 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2618 if (sta_info_le.rssi[i]) {
2619 sinfo->chain_signal_avg[count_rssi] =
2620 sta_info_le.rssi[i];
2621 sinfo->chain_signal[count_rssi] =
2622 sta_info_le.rssi[i];
2623 total_rssi += sta_info_le.rssi[i];
2624 count_rssi++;
2625 }
2626 }
2627 if (count_rssi) {
2628 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2629 sinfo->chains = count_rssi;
2630
2631 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2632 total_rssi /= count_rssi;
2633 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002634 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2635 &ifp->vif->sme_state)) {
2636 memset(&scb_val, 0, sizeof(scb_val));
2637 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2638 &scb_val, sizeof(scb_val));
2639 if (err) {
2640 brcmf_err("Could not get rssi (%d)\n", err);
2641 goto done;
2642 } else {
2643 rssi = le32_to_cpu(scb_val.val);
2644 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2645 sinfo->signal = rssi;
2646 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2647 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002648 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002649 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002651 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002652 return err;
2653}
2654
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002655static int
2656brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2657 int idx, u8 *mac, struct station_info *sinfo)
2658{
2659 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2660 struct brcmf_if *ifp = netdev_priv(ndev);
2661 s32 err;
2662
2663 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2664
2665 if (idx == 0) {
2666 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2667 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2668 &cfg->assoclist,
2669 sizeof(cfg->assoclist));
2670 if (err) {
2671 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2672 err);
2673 cfg->assoclist.count = 0;
2674 return -EOPNOTSUPP;
2675 }
2676 }
2677 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2678 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2679 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2680 }
2681 return -ENOENT;
2682}
2683
Arend van Spriel5b435de2011-10-05 13:19:03 +02002684static s32
2685brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2686 bool enabled, s32 timeout)
2687{
2688 s32 pm;
2689 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002690 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002691 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002692
Arend van Sprield96b8012012-12-05 15:26:02 +01002693 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002694
2695 /*
2696 * Powersave enable/disable request is coming from the
2697 * cfg80211 even before the interface is up. In that
2698 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002699 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700 * FW later while initializing the dongle
2701 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002702 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002703 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002704
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002705 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002706 goto done;
2707 }
2708
2709 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002710 /* Do not enable the power save after assoc if it is a p2p interface */
2711 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2712 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2713 pm = PM_OFF;
2714 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002715 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002716
Arend van Sprielc1179032012-10-22 13:55:33 -07002717 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718 if (err) {
2719 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002720 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002721 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002722 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002723 }
2724done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002725 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002726 return err;
2727}
2728
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002729static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002730 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002731{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002732 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002733 struct ieee80211_channel *notify_channel;
2734 struct cfg80211_bss *bss;
2735 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002736 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002737 u16 channel;
2738 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739 u16 notify_capability;
2740 u16 notify_interval;
2741 u8 *notify_ie;
2742 size_t notify_ielen;
2743 s32 notify_signal;
2744
2745 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002746 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002747 return 0;
2748 }
2749
Franky Lin83cf17a2013-04-11 13:28:50 +02002750 if (!bi->ctl_ch) {
2751 ch.chspec = le16_to_cpu(bi->chanspec);
2752 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002753 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002754 }
2755 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756
2757 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002758 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002759 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002760 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002761
2762 freq = ieee80211_channel_to_frequency(channel, band->band);
2763 notify_channel = ieee80211_get_channel(wiphy, freq);
2764
Arend van Spriel5b435de2011-10-05 13:19:03 +02002765 notify_capability = le16_to_cpu(bi->capability);
2766 notify_interval = le16_to_cpu(bi->beacon_period);
2767 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2768 notify_ielen = le32_to_cpu(bi->ie_length);
2769 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2770
Arend van Spriel16886732012-12-05 15:26:04 +01002771 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2772 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2773 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2774 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2775 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002776
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002777 bss = cfg80211_inform_bss(wiphy, notify_channel,
2778 CFG80211_BSS_FTYPE_UNKNOWN,
2779 (const u8 *)bi->BSSID,
2780 0, notify_capability,
2781 notify_interval, notify_ie,
2782 notify_ielen, notify_signal,
2783 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002784
Franky Line78946e2011-11-10 20:30:34 +01002785 if (!bss)
2786 return -ENOMEM;
2787
Johannes Berg5b112d32013-02-01 01:49:58 +01002788 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002789
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002790 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002791}
2792
Roland Vossen6f09be02011-10-18 14:03:02 +02002793static struct brcmf_bss_info_le *
2794next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2795{
2796 if (bss == NULL)
2797 return list->bss_info_le;
2798 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2799 le32_to_cpu(bss->length));
2800}
2801
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002802static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002803{
2804 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002805 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806 s32 err = 0;
2807 int i;
2808
Hante Meulemanef8596e2014-09-30 10:23:13 +02002809 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002810 if (bss_list->count != 0 &&
2811 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002812 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2813 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814 return -EOPNOTSUPP;
2815 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002816 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002817 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002818 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002819 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002820 if (err)
2821 break;
2822 }
2823 return err;
2824}
2825
Hante Meulemanb0a79082015-12-10 13:43:07 +01002826static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2827 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002828{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002829 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002831 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002832 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002833 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002834 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002835 u8 *buf = NULL;
2836 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002838 u16 notify_capability;
2839 u16 notify_interval;
2840 u8 *notify_ie;
2841 size_t notify_ielen;
2842 s32 notify_signal;
2843
Arend van Sprield96b8012012-12-05 15:26:02 +01002844 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845
2846 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2847 if (buf == NULL) {
2848 err = -ENOMEM;
2849 goto CleanUp;
2850 }
2851
2852 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2853
Arend van Sprielac24be62012-10-22 10:36:23 -07002854 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2855 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002857 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002858 goto CleanUp;
2859 }
2860
Roland Vossend34bf642011-10-18 14:03:01 +02002861 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002862
Franky Lin83cf17a2013-04-11 13:28:50 +02002863 ch.chspec = le16_to_cpu(bi->chanspec);
2864 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002865
Franky Lin83cf17a2013-04-11 13:28:50 +02002866 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002867 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002868 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002869 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002870
Rafał Miłecki4712d882016-05-20 13:38:57 +02002871 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002872 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002873 notify_channel = ieee80211_get_channel(wiphy, freq);
2874
Arend van Spriel5b435de2011-10-05 13:19:03 +02002875 notify_capability = le16_to_cpu(bi->capability);
2876 notify_interval = le16_to_cpu(bi->beacon_period);
2877 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2878 notify_ielen = le32_to_cpu(bi->ie_length);
2879 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2880
Rafał Miłecki4712d882016-05-20 13:38:57 +02002881 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002882 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2883 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2884 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002886 bss = cfg80211_inform_bss(wiphy, notify_channel,
2887 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2888 notify_capability, notify_interval,
2889 notify_ie, notify_ielen, notify_signal,
2890 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891
Franky Line78946e2011-11-10 20:30:34 +01002892 if (!bss) {
2893 err = -ENOMEM;
2894 goto CleanUp;
2895 }
2896
Johannes Berg5b112d32013-02-01 01:49:58 +01002897 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002898
Arend van Spriel5b435de2011-10-05 13:19:03 +02002899CleanUp:
2900
2901 kfree(buf);
2902
Arend van Sprield96b8012012-12-05 15:26:02 +01002903 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002904
2905 return err;
2906}
2907
Hante Meuleman89286dc2013-02-08 15:53:46 +01002908static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2909 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002910{
Roland Vossend34bf642011-10-18 14:03:01 +02002911 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002912 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913 u16 beacon_interval;
2914 u8 dtim_period;
2915 size_t ie_len;
2916 u8 *ie;
2917 s32 err = 0;
2918
Arend van Sprield96b8012012-12-05 15:26:02 +01002919 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002920 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002921 return err;
2922
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002923 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002924 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002925 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002926 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002927 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928 goto update_bss_info_out;
2929 }
2930
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002931 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2932 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002933 if (err)
2934 goto update_bss_info_out;
2935
2936 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2937 ie_len = le32_to_cpu(bi->ie_length);
2938 beacon_interval = le16_to_cpu(bi->beacon_period);
2939
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002940 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002941 if (tim)
2942 dtim_period = tim->data[1];
2943 else {
2944 /*
2945 * active scan was done so we could not get dtim
2946 * information out of probe response.
2947 * so we speficially query dtim information to dongle.
2948 */
2949 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002950 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002951 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002952 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002953 goto update_bss_info_out;
2954 }
2955 dtim_period = (u8)var;
2956 }
2957
Arend van Spriel5b435de2011-10-05 13:19:03 +02002958update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002959 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002960 return err;
2961}
2962
Hante Meuleman18e2f612013-02-08 15:53:49 +01002963void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002964{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002965 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002966
Arend van Sprielc1179032012-10-22 13:55:33 -07002967 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01002968 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002969 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002970 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002971 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002972 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2973 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974}
2975
Hante Meulemane756af52012-09-11 21:18:52 +02002976static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2977{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002978 struct brcmf_cfg80211_info *cfg =
2979 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002980 escan_timeout_work);
2981
Hante Meulemanef8596e2014-09-30 10:23:13 +02002982 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002983 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002984}
2985
Kees Cooke99e88a2017-10-16 14:43:17 -07002986static void brcmf_escan_timeout(struct timer_list *t)
Hante Meulemane756af52012-09-11 21:18:52 +02002987{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002988 struct brcmf_cfg80211_info *cfg =
Kees Cooke99e88a2017-10-16 14:43:17 -07002989 from_timer(cfg, t, escan_timeout);
Hante Meulemane756af52012-09-11 21:18:52 +02002990
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01002991 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002992 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002993 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002994 }
2995}
2996
2997static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002998brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2999 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003000 struct brcmf_bss_info_le *bss_info_le)
3001{
Franky Lin83cf17a2013-04-11 13:28:50 +02003002 struct brcmu_chan ch_bss, ch_bss_info_le;
3003
3004 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3005 cfg->d11inf.decchspec(&ch_bss);
3006 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3007 cfg->d11inf.decchspec(&ch_bss_info_le);
3008
Hante Meulemane756af52012-09-11 21:18:52 +02003009 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003010 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003011 bss_info_le->SSID_len == bss->SSID_len &&
3012 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003013 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3014 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003015 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3016 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3017
Hante Meulemane756af52012-09-11 21:18:52 +02003018 /* preserve max RSSI if the measurements are
3019 * both on-channel or both off-channel
3020 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003021 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003022 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003023 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3024 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003025 /* preserve the on-channel rssi measurement
3026 * if the new measurement is off channel
3027 */
3028 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003029 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003030 }
3031 return 1;
3032 }
3033 return 0;
3034}
3035
3036static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003037brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003038 const struct brcmf_event_msg *e, void *data)
3039{
Arend van Spriel19937322012-11-05 16:22:32 -08003040 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003041 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003042 struct brcmf_escan_result_le *escan_result_le;
Arend Van Spriel17df6452017-09-12 10:47:53 +02003043 u32 escan_buflen;
Hante Meulemane756af52012-09-11 21:18:52 +02003044 struct brcmf_bss_info_le *bss_info_le;
3045 struct brcmf_bss_info_le *bss = NULL;
3046 u32 bi_length;
3047 struct brcmf_scan_results *list;
3048 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003049 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003050
Arend van Spriel5c36b992012-11-14 18:46:05 -08003051 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003052
Hans de Goedeb9472a22017-03-08 14:50:17 +01003053 if (status == BRCMF_E_STATUS_ABORT)
3054 goto exit;
3055
Arend van Spriela0f472a2013-04-05 10:57:49 +02003056 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003057 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003058 return -EPERM;
3059 }
3060
3061 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003062 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Arend Van Spriel17df6452017-09-12 10:47:53 +02003063 if (e->datalen < sizeof(*escan_result_le)) {
3064 brcmf_err("invalid event data length\n");
3065 goto exit;
3066 }
Hante Meulemane756af52012-09-11 21:18:52 +02003067 escan_result_le = (struct brcmf_escan_result_le *) data;
3068 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003069 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003070 goto exit;
3071 }
Arend Van Spriel17df6452017-09-12 10:47:53 +02003072 escan_buflen = le32_to_cpu(escan_result_le->buflen);
3073 if (escan_buflen > BRCMF_ESCAN_BUF_SIZE ||
3074 escan_buflen > e->datalen ||
3075 escan_buflen < sizeof(*escan_result_le)) {
3076 brcmf_err("Invalid escan buffer length: %d\n",
3077 escan_buflen);
3078 goto exit;
3079 }
Hante Meulemane756af52012-09-11 21:18:52 +02003080 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003081 brcmf_err("Invalid bss_count %d: ignoring\n",
3082 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003083 goto exit;
3084 }
3085 bss_info_le = &escan_result_le->bss_info_le;
3086
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003087 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3088 goto exit;
3089
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003090 if (!cfg->int_escan_map && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003091 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3092 goto exit;
3093 }
3094
Hante Meulemane756af52012-09-11 21:18:52 +02003095 bi_length = le32_to_cpu(bss_info_le->length);
Arend Van Spriel17df6452017-09-12 10:47:53 +02003096 if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
3097 brcmf_err("Ignoring invalid bss_info length: %d\n",
Arend van Spriel57d6e912012-12-05 15:26:00 +01003098 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003099 goto exit;
3100 }
3101
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003102 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003103 BIT(NL80211_IFTYPE_ADHOC))) {
3104 if (le16_to_cpu(bss_info_le->capability) &
3105 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003106 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003107 goto exit;
3108 }
3109 }
3110
3111 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003112 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003113 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003115 goto exit;
3116 }
3117
3118 for (i = 0; i < list->count; i++) {
3119 bss = bss ? (struct brcmf_bss_info_le *)
3120 ((unsigned char *)bss +
3121 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003122 if (brcmf_compare_update_same_bss(cfg, bss,
3123 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003124 goto exit;
3125 }
Hante Meulemand5367332016-02-17 11:26:51 +01003126 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3127 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003128 list->version = le32_to_cpu(bss_info_le->version);
3129 list->buflen += bi_length;
3130 list->count++;
3131 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003132 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003133 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3134 goto exit;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003135 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003136 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003137 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003138 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003139 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003140 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3141 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003142 }
3143exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003144 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003145}
3146
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003147static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003148{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003149 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3150 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003151 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3152 /* Init scan_timeout timer */
Kees Cooke99e88a2017-10-16 14:43:17 -07003153 timer_setup(&cfg->escan_timeout, brcmf_escan_timeout, 0);
Hante Meulemanf07998952012-11-05 16:22:13 -08003154 INIT_WORK(&cfg->escan_timeout_work,
3155 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003156}
3157
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003158static struct cfg80211_scan_request *
3159brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3160 struct cfg80211_scan_request *req;
3161 size_t req_size;
3162
3163 req_size = sizeof(*req) +
3164 n_netinfo * sizeof(req->channels[0]) +
3165 n_netinfo * sizeof(*req->ssids);
3166
3167 req = kzalloc(req_size, GFP_KERNEL);
3168 if (req) {
3169 req->wiphy = wiphy;
3170 req->ssids = (void *)(&req->channels[0]) +
3171 n_netinfo * sizeof(req->channels[0]);
3172 }
3173 return req;
3174}
3175
3176static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3177 u8 *ssid, u8 ssid_len, u8 channel)
3178{
3179 struct ieee80211_channel *chan;
3180 enum nl80211_band band;
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003181 int freq, i;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003182
3183 if (channel <= CH_MAX_2G_CHANNEL)
3184 band = NL80211_BAND_2GHZ;
3185 else
3186 band = NL80211_BAND_5GHZ;
3187
3188 freq = ieee80211_channel_to_frequency(channel, band);
3189 if (!freq)
3190 return -EINVAL;
3191
3192 chan = ieee80211_get_channel(req->wiphy, freq);
3193 if (!chan)
3194 return -EINVAL;
3195
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003196 for (i = 0; i < req->n_channels; i++) {
3197 if (req->channels[i] == chan)
3198 break;
3199 }
3200 if (i == req->n_channels)
3201 req->channels[req->n_channels++] = chan;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003202
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003203 for (i = 0; i < req->n_ssids; i++) {
3204 if (req->ssids[i].ssid_len == ssid_len &&
3205 !memcmp(req->ssids[i].ssid, ssid, ssid_len))
3206 break;
3207 }
3208 if (i == req->n_ssids) {
3209 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3210 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3211 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003212 return 0;
3213}
3214
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003215static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003216 struct cfg80211_scan_request *request)
3217{
3218 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3219 int err;
3220
3221 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003222 if (cfg->int_escan_map)
3223 brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
3224 cfg->int_escan_map);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003225 /* Abort any on-going scan */
3226 brcmf_abort_scanning(cfg);
3227 }
3228
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003229 brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003230 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3231 cfg->escan_info.run = brcmf_run_escan;
3232 err = brcmf_do_escan(ifp, request);
3233 if (err) {
3234 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3235 return err;
3236 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003237 cfg->int_escan_map = fwmap;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003238 return 0;
3239}
3240
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003241static struct brcmf_pno_net_info_le *
3242brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3243{
3244 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3245 struct brcmf_pno_net_info_le *netinfo;
3246
3247 switch (pfn_v1->version) {
3248 default:
3249 WARN_ON(1);
3250 /* fall-thru */
3251 case cpu_to_le32(1):
3252 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3253 break;
3254 case cpu_to_le32(2):
3255 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3256 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3257 break;
3258 }
3259
3260 return netinfo;
3261}
3262
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003263/* PFN result doesn't have all the info which are required by the supplicant
3264 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3265 * via wl_inform_single_bss in the required format. Escan does require the
3266 * scan request in the form of cfg80211_scan_request. For timebeing, create
3267 * cfg80211_scan_request one out of the received PNO event.
3268 */
3269static s32
3270brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3271 const struct brcmf_event_msg *e, void *data)
3272{
3273 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3274 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3275 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003276 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003277 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003278 struct brcmf_pno_scanresults_le *pfn_result;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003279 u32 bucket_map;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003280 u32 result_count;
3281 u32 status;
Arend Van Spriel4835f372017-04-06 13:14:40 +01003282 u32 datalen;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003283
3284 brcmf_dbg(SCAN, "Enter\n");
3285
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003286 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3287 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3288 return 0;
3289 }
3290
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003291 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3292 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3293 return 0;
3294 }
3295
3296 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3297 result_count = le32_to_cpu(pfn_result->count);
3298 status = le32_to_cpu(pfn_result->status);
3299
3300 /* PFN event is limited to fit 512 bytes so we may get
3301 * multiple NET_FOUND events. For now place a warning here.
3302 */
3303 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3304 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003305 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003306 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3307 goto out_err;
3308 }
Arend Van Spriel4835f372017-04-06 13:14:40 +01003309
3310 netinfo_start = brcmf_get_netinfo_array(pfn_result);
3311 datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
3312 if (datalen < result_count * sizeof(*netinfo)) {
3313 brcmf_err("insufficient event data\n");
3314 goto out_err;
3315 }
3316
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003317 request = brcmf_alloc_internal_escan_request(wiphy,
3318 result_count);
3319 if (!request) {
3320 err = -ENOMEM;
3321 goto out_err;
3322 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003323
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003324 bucket_map = 0;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003325 for (i = 0; i < result_count; i++) {
3326 netinfo = &netinfo_start[i];
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003327
Arend Van Spriel4835f372017-04-06 13:14:40 +01003328 if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
3329 netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003330 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3331 netinfo->SSID, netinfo->channel);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003332 bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003333 err = brcmf_internal_escan_add_info(request,
3334 netinfo->SSID,
3335 netinfo->SSID_len,
3336 netinfo->channel);
3337 if (err)
3338 goto out_err;
3339 }
3340
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003341 if (!bucket_map)
3342 goto free_req;
3343
3344 err = brcmf_start_internal_escan(ifp, bucket_map, request);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003345 if (!err)
3346 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003347
3348out_err:
Arend Van Sprielb34939b2017-04-28 13:40:28 +01003349 cfg80211_sched_scan_stopped(wiphy, 0);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003350free_req:
3351 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003352 return err;
3353}
3354
3355static int
3356brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3357 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003358 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003359{
3360 struct brcmf_if *ifp = netdev_priv(ndev);
3361 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003362
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003363 brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003364 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003365
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003366 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003367 brcmf_err("Scanning suppressed: status=%lu\n",
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003368 cfg->scan_status);
3369 return -EAGAIN;
3370 }
3371
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003372 if (req->n_match_sets <= 0) {
3373 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3374 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003375 return -EINVAL;
3376 }
3377
Arend Van Spriel3e486112016-11-23 10:25:27 +00003378 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003379}
3380
3381static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003382 struct net_device *ndev, u64 reqid)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003383{
3384 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003385 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003386
3387 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003388 brcmf_pno_stop_sched_scan(ifp, reqid);
3389 if (cfg->int_escan_map)
Arend Van Sprielac551362016-11-23 10:25:22 +00003390 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003391 return 0;
3392}
3393
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003394static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003395{
3396 if (ms < 1000 / HZ) {
3397 cond_resched();
3398 mdelay(ms);
3399 } else {
3400 msleep(ms);
3401 }
3402}
3403
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003404static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3405 u8 *pattern, u32 patternsize, u8 *mask,
3406 u32 packet_offset)
3407{
3408 struct brcmf_fil_wowl_pattern_le *filter;
3409 u32 masksize;
3410 u32 patternoffset;
3411 u8 *buf;
3412 u32 bufsize;
3413 s32 ret;
3414
3415 masksize = (patternsize + 7) / 8;
3416 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3417
3418 bufsize = sizeof(*filter) + patternsize + masksize;
3419 buf = kzalloc(bufsize, GFP_KERNEL);
3420 if (!buf)
3421 return -ENOMEM;
3422 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3423
3424 memcpy(filter->cmd, cmd, 4);
3425 filter->masksize = cpu_to_le32(masksize);
3426 filter->offset = cpu_to_le32(packet_offset);
3427 filter->patternoffset = cpu_to_le32(patternoffset);
3428 filter->patternsize = cpu_to_le32(patternsize);
3429 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3430
3431 if ((mask) && (masksize))
3432 memcpy(buf + sizeof(*filter), mask, masksize);
3433 if ((pattern) && (patternsize))
3434 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3435
3436 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3437
3438 kfree(buf);
3439 return ret;
3440}
3441
Hante Meuleman3021ad92016-01-05 11:05:45 +01003442static s32
3443brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3444 void *data)
3445{
3446 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3447 struct brcmf_pno_scanresults_le *pfn_result;
3448 struct brcmf_pno_net_info_le *netinfo;
3449
3450 brcmf_dbg(SCAN, "Enter\n");
3451
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003452 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3453 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3454 return 0;
3455 }
3456
Hante Meuleman3021ad92016-01-05 11:05:45 +01003457 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3458
3459 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3460 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3461 return 0;
3462 }
3463
3464 if (le32_to_cpu(pfn_result->count) < 1) {
3465 brcmf_err("Invalid result count, expected 1 (%d)\n",
3466 le32_to_cpu(pfn_result->count));
3467 return -EINVAL;
3468 }
3469
Arend Van Sprield29afe92017-01-27 12:27:46 +00003470 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003471 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3472 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3473 cfg->wowl.nd->n_channels = 1;
3474 cfg->wowl.nd->channels[0] =
3475 ieee80211_channel_to_frequency(netinfo->channel,
3476 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3477 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3478 cfg->wowl.nd_info->n_matches = 1;
3479 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3480
3481 /* Inform (the resume task) that the net detect information was recvd */
3482 cfg->wowl.nd_data_completed = true;
3483 wake_up(&cfg->wowl.nd_data_wait);
3484
3485 return 0;
3486}
3487
Hante Meulemanaeb64222015-10-29 20:33:19 +01003488#ifdef CONFIG_PM
3489
3490static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3491{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003492 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003493 struct brcmf_wowl_wakeind_le wake_ind_le;
3494 struct cfg80211_wowlan_wakeup wakeup_data;
3495 struct cfg80211_wowlan_wakeup *wakeup;
3496 u32 wakeind;
3497 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003498 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003499
3500 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3501 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003502 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003503 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3504 return;
3505 }
3506
3507 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3508 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003509 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3510 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003511 wakeup = &wakeup_data;
3512 memset(&wakeup_data, 0, sizeof(wakeup_data));
3513 wakeup_data.pattern_idx = -1;
3514
3515 if (wakeind & BRCMF_WOWL_MAGIC) {
3516 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3517 wakeup_data.magic_pkt = true;
3518 }
3519 if (wakeind & BRCMF_WOWL_DIS) {
3520 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3521 wakeup_data.disconnect = true;
3522 }
3523 if (wakeind & BRCMF_WOWL_BCN) {
3524 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3525 wakeup_data.disconnect = true;
3526 }
3527 if (wakeind & BRCMF_WOWL_RETR) {
3528 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3529 wakeup_data.disconnect = true;
3530 }
3531 if (wakeind & BRCMF_WOWL_NET) {
3532 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3533 /* For now always map to pattern 0, no API to get
3534 * correct information available at the moment.
3535 */
3536 wakeup_data.pattern_idx = 0;
3537 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003538 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3539 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3540 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3541 cfg->wowl.nd_data_completed,
3542 BRCMF_ND_INFO_TIMEOUT);
3543 if (!timeout)
3544 brcmf_err("No result for wowl net detect\n");
3545 else
3546 wakeup_data.net_detect = cfg->wowl.nd_info;
3547 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003548 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3549 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3550 wakeup_data.gtk_rekey_failure = true;
3551 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003552 } else {
3553 wakeup = NULL;
3554 }
3555 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3556}
3557
3558#else
3559
3560static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3561{
3562}
3563
3564#endif /* CONFIG_PM */
3565
Arend van Spriel5b435de2011-10-05 13:19:03 +02003566static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3567{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003568 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3569 struct net_device *ndev = cfg_to_ndev(cfg);
3570 struct brcmf_if *ifp = netdev_priv(ndev);
3571
Arend van Sprield96b8012012-12-05 15:26:02 +01003572 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003573
Hante Meuleman3021ad92016-01-05 11:05:45 +01003574 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003575 brcmf_report_wowl_wakeind(wiphy, ifp);
3576 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3577 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003578 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3579 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003580 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003581 cfg->wowl.pre_pmmode);
3582 cfg->wowl.active = false;
3583 if (cfg->wowl.nd_enabled) {
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003584 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003585 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3586 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3587 brcmf_notify_sched_scan_results);
3588 cfg->wowl.nd_enabled = false;
3589 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003590 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003591 return 0;
3592}
3593
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003594static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3595 struct brcmf_if *ifp,
3596 struct cfg80211_wowlan *wowl)
3597{
3598 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003599 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003600 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003601
3602 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3603
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003604 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3605 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003606 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003607 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3608
3609 wowl_config = 0;
3610 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003611 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003612 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003613 wowl_config |= BRCMF_WOWL_MAGIC;
3614 if ((wowl->patterns) && (wowl->n_patterns)) {
3615 wowl_config |= BRCMF_WOWL_NET;
3616 for (i = 0; i < wowl->n_patterns; i++) {
3617 brcmf_config_wowl_pattern(ifp, "add",
3618 (u8 *)wowl->patterns[i].pattern,
3619 wowl->patterns[i].pattern_len,
3620 (u8 *)wowl->patterns[i].mask,
3621 wowl->patterns[i].pkt_offset);
3622 }
3623 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003624 if (wowl->nd_config) {
3625 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3626 wowl->nd_config);
3627 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3628
3629 cfg->wowl.nd_data_completed = false;
3630 cfg->wowl.nd_enabled = true;
3631 /* Now reroute the event for PFN to the wowl function. */
3632 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3633 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3634 brcmf_wowl_nd_results);
3635 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003636 if (wowl->gtk_rekey_failure)
3637 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003638 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3639 wowl_config |= BRCMF_WOWL_UNASSOC;
3640
Hante Meulemana7ed7822016-09-19 12:09:58 +01003641 memcpy(&wowl_wakeind, "clear", 6);
3642 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3643 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003644 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3645 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3646 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003647 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003648}
3649
Arend van Spriel5b435de2011-10-05 13:19:03 +02003650static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003651 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003652{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003653 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3654 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003655 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003656 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003657
Arend van Sprield96b8012012-12-05 15:26:02 +01003658 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003659
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003660 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003661 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003662 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003663 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003664 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003665
Hante Meuleman3021ad92016-01-05 11:05:45 +01003666 /* Stop scheduled scan */
3667 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003668 brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003669
Arend van Spriel7d641072012-10-22 13:55:39 -07003670 /* end any scanning */
3671 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003672 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003673
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003674 if (wowl == NULL) {
3675 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3676 list_for_each_entry(vif, &cfg->vif_list, list) {
3677 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3678 continue;
3679 /* While going to suspend if associated with AP
3680 * disassociate from AP to save power while system is
3681 * in suspended state
3682 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003683 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003684 /* Make sure WPA_Supplicant receives all the event
3685 * generated due to DISASSOC call to the fw to keep
3686 * the state fw and WPA_Supplicant state consistent
3687 */
3688 brcmf_delay(500);
3689 }
3690 /* Configure MPC */
3691 brcmf_set_mpc(ifp, 1);
3692
3693 } else {
3694 /* Configure WOWL paramaters */
3695 brcmf_configure_wowl(cfg, ifp, wowl);
3696 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003697
Arend van Spriel7d641072012-10-22 13:55:39 -07003698exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003699 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003700 /* clear any scanning activity */
3701 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003702 return 0;
3703}
3704
3705static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003706brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003707{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003708 struct brcmf_pmk_list_le *pmk_list;
3709 int i;
3710 u32 npmk;
3711 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003712
Hante Meuleman6c404f32015-12-10 13:43:03 +01003713 pmk_list = &cfg->pmk_list;
3714 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003715
Hante Meuleman6c404f32015-12-10 13:43:03 +01003716 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3717 for (i = 0; i < npmk; i++)
3718 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003719
Hante Meuleman6c404f32015-12-10 13:43:03 +01003720 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3721 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003722
3723 return err;
3724}
3725
3726static s32
3727brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3728 struct cfg80211_pmksa *pmksa)
3729{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003730 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003731 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003732 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3733 s32 err;
3734 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003735
Arend van Sprield96b8012012-12-05 15:26:02 +01003736 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003737 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003738 return -EIO;
3739
Hante Meuleman6c404f32015-12-10 13:43:03 +01003740 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3741 for (i = 0; i < npmk; i++)
3742 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003743 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003744 if (i < BRCMF_MAXPMKID) {
3745 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3746 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3747 if (i == npmk) {
3748 npmk++;
3749 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003750 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003751 } else {
3752 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3753 return -EINVAL;
3754 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003755
Hante Meuleman6c404f32015-12-10 13:43:03 +01003756 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3757 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3758 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3759 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3760 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003761
Hante Meuleman6c404f32015-12-10 13:43:03 +01003762 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003763
Arend van Sprield96b8012012-12-05 15:26:02 +01003764 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003765 return err;
3766}
3767
3768static s32
3769brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003770 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003771{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003772 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003773 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003774 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3775 s32 err;
3776 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777
Arend van Sprield96b8012012-12-05 15:26:02 +01003778 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003779 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780 return -EIO;
3781
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003782 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003783
Hante Meuleman6c404f32015-12-10 13:43:03 +01003784 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3785 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003786 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003787 break;
3788
Hante Meuleman6c404f32015-12-10 13:43:03 +01003789 if ((npmk > 0) && (i < npmk)) {
3790 for (; i < (npmk - 1); i++) {
3791 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3792 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003793 WLAN_PMKID_LEN);
3794 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003795 memset(&pmk[i], 0, sizeof(*pmk));
3796 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3797 } else {
3798 brcmf_err("Cache entry not found\n");
3799 return -EINVAL;
3800 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003801
Hante Meuleman6c404f32015-12-10 13:43:03 +01003802 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003803
Arend van Sprield96b8012012-12-05 15:26:02 +01003804 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003805 return err;
3806
3807}
3808
3809static s32
3810brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3811{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003812 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003813 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003814 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003815
Arend van Sprield96b8012012-12-05 15:26:02 +01003816 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003817 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003818 return -EIO;
3819
Hante Meuleman6c404f32015-12-10 13:43:03 +01003820 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3821 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003822
Arend van Sprield96b8012012-12-05 15:26:02 +01003823 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003824 return err;
3825
3826}
3827
Hante Meuleman1f170112013-02-06 18:40:38 +01003828static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003829{
3830 s32 err;
Wright Fengfdfb0f92017-08-03 17:37:57 +08003831 s32 wpa_val;
Hante Meuleman1a873342012-09-27 14:17:54 +02003832
3833 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003834 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003835 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003836 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003837 return err;
3838 }
3839 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003840 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003841 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003842 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003843 return err;
3844 }
3845 /* set upper-layer auth */
Wright Fengfdfb0f92017-08-03 17:37:57 +08003846 if (brcmf_is_ibssmode(ifp->vif))
3847 wpa_val = WPA_AUTH_NONE;
3848 else
3849 wpa_val = WPA_AUTH_DISABLED;
3850 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val);
Hante Meuleman1a873342012-09-27 14:17:54 +02003851 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003852 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003853 return err;
3854 }
3855
3856 return 0;
3857}
3858
3859static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3860{
3861 if (is_rsn_ie)
3862 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3863
3864 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3865}
3866
3867static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003868brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003869 const struct brcmf_vs_tlv *wpa_ie,
3870 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003871{
3872 u32 auth = 0; /* d11 open authentication */
3873 u16 count;
3874 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003875 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003876 u32 i;
3877 u32 wsec;
3878 u32 pval = 0;
3879 u32 gval = 0;
3880 u32 wpa_auth = 0;
3881 u32 offset;
3882 u8 *data;
3883 u16 rsn_cap;
3884 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003885 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003886
Arend van Sprield96b8012012-12-05 15:26:02 +01003887 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003888 if (wpa_ie == NULL)
3889 goto exit;
3890
3891 len = wpa_ie->len + TLV_HDR_LEN;
3892 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003893 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003894 if (!is_rsn_ie)
3895 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003896 else
3897 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003898
3899 /* check for multicast cipher suite */
3900 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3901 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003902 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003903 goto exit;
3904 }
3905
3906 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3907 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003908 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003909 goto exit;
3910 }
3911 offset += TLV_OUI_LEN;
3912
3913 /* pick up multicast cipher */
3914 switch (data[offset]) {
3915 case WPA_CIPHER_NONE:
3916 gval = 0;
3917 break;
3918 case WPA_CIPHER_WEP_40:
3919 case WPA_CIPHER_WEP_104:
3920 gval = WEP_ENABLED;
3921 break;
3922 case WPA_CIPHER_TKIP:
3923 gval = TKIP_ENABLED;
3924 break;
3925 case WPA_CIPHER_AES_CCM:
3926 gval = AES_ENABLED;
3927 break;
3928 default:
3929 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003930 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003931 goto exit;
3932 }
3933
3934 offset++;
3935 /* walk thru unicast cipher list and pick up what we recognize */
3936 count = data[offset] + (data[offset + 1] << 8);
3937 offset += WPA_IE_SUITE_COUNT_LEN;
3938 /* Check for unicast suite(s) */
3939 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3940 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003941 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003942 goto exit;
3943 }
3944 for (i = 0; i < count; i++) {
3945 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3946 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003947 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 goto exit;
3949 }
3950 offset += TLV_OUI_LEN;
3951 switch (data[offset]) {
3952 case WPA_CIPHER_NONE:
3953 break;
3954 case WPA_CIPHER_WEP_40:
3955 case WPA_CIPHER_WEP_104:
3956 pval |= WEP_ENABLED;
3957 break;
3958 case WPA_CIPHER_TKIP:
3959 pval |= TKIP_ENABLED;
3960 break;
3961 case WPA_CIPHER_AES_CCM:
3962 pval |= AES_ENABLED;
3963 break;
3964 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00003965 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003966 }
3967 offset++;
3968 }
3969 /* walk thru auth management suite list and pick up what we recognize */
3970 count = data[offset] + (data[offset + 1] << 8);
3971 offset += WPA_IE_SUITE_COUNT_LEN;
3972 /* Check for auth key management suite(s) */
3973 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3974 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003975 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003976 goto exit;
3977 }
3978 for (i = 0; i < count; i++) {
3979 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3980 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003981 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003982 goto exit;
3983 }
3984 offset += TLV_OUI_LEN;
3985 switch (data[offset]) {
3986 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003987 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 wpa_auth |= WPA_AUTH_NONE;
3989 break;
3990 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003991 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003992 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3993 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3994 break;
3995 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003996 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003997 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3998 (wpa_auth |= WPA_AUTH_PSK);
3999 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004000 case RSN_AKM_SHA256_PSK:
4001 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4002 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4003 break;
4004 case RSN_AKM_SHA256_1X:
4005 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4006 wpa_auth |= WPA2_AUTH_1X_SHA256;
4007 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004008 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004009 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004010 }
4011 offset++;
4012 }
4013
Hante Meuleman240d61a2016-02-17 11:27:10 +01004014 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004015 if (is_rsn_ie) {
4016 wme_bss_disable = 1;
4017 if ((offset + RSN_CAP_LEN) <= len) {
4018 rsn_cap = data[offset] + (data[offset + 1] << 8);
4019 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4020 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004021 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4022 brcmf_dbg(TRACE, "MFP Required\n");
4023 mfp = BRCMF_MFP_REQUIRED;
4024 /* Firmware only supports mfp required in
4025 * combination with WPA2_AUTH_PSK_SHA256 or
4026 * WPA2_AUTH_1X_SHA256.
4027 */
4028 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4029 WPA2_AUTH_1X_SHA256))) {
4030 err = -EINVAL;
4031 goto exit;
4032 }
4033 /* Firmware has requirement that WPA2_AUTH_PSK/
4034 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4035 * is to be included in the rsn ie.
4036 */
4037 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4038 wpa_auth |= WPA2_AUTH_PSK;
4039 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4040 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4041 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4042 brcmf_dbg(TRACE, "MFP Capable\n");
4043 mfp = BRCMF_MFP_CAPABLE;
4044 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004045 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004046 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004047 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004048 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004049 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004050 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004051 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004052 goto exit;
4053 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004054
4055 /* Skip PMKID cnt as it is know to be 0 for AP. */
4056 offset += RSN_PMKID_COUNT_LEN;
4057
4058 /* See if there is BIP wpa suite left for MFP */
4059 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4060 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4061 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4062 &data[offset],
4063 WPA_IE_MIN_OUI_LEN);
4064 if (err < 0) {
4065 brcmf_err("bip error %d\n", err);
4066 goto exit;
4067 }
4068 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004069 }
4070 /* FOR WPS , set SES_OW_ENABLED */
4071 wsec = (pval | gval | SES_OW_ENABLED);
4072
4073 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004074 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004075 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004076 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004077 goto exit;
4078 }
4079 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004080 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004081 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004082 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004083 goto exit;
4084 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004085 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4086 * will overwrite the values set by MFP
4087 */
4088 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4089 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4090 if (err < 0) {
4091 brcmf_err("mfp error %d\n", err);
4092 goto exit;
4093 }
4094 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004095 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004096 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004097 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004098 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004099 goto exit;
4100 }
4101
4102exit:
4103 return err;
4104}
4105
4106static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004107brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004108 struct parsed_vndr_ies *vndr_ies)
4109{
Hante Meuleman1a873342012-09-27 14:17:54 +02004110 struct brcmf_vs_tlv *vndrie;
4111 struct brcmf_tlv *ie;
4112 struct parsed_vndr_ie_info *parsed_info;
4113 s32 remaining_len;
4114
4115 remaining_len = (s32)vndr_ie_len;
4116 memset(vndr_ies, 0, sizeof(*vndr_ies));
4117
4118 ie = (struct brcmf_tlv *)vndr_ie_buf;
4119 while (ie) {
4120 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4121 goto next;
4122 vndrie = (struct brcmf_vs_tlv *)ie;
4123 /* len should be bigger than OUI length + one */
4124 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004125 brcmf_err("invalid vndr ie. length is too small %d\n",
4126 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004127 goto next;
4128 }
4129 /* if wpa or wme ie, do not add ie */
4130 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4131 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4132 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004133 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004134 goto next;
4135 }
4136
4137 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4138
4139 /* save vndr ie information */
4140 parsed_info->ie_ptr = (char *)vndrie;
4141 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4142 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4143
4144 vndr_ies->count++;
4145
Arend van Sprield96b8012012-12-05 15:26:02 +01004146 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4147 parsed_info->vndrie.oui[0],
4148 parsed_info->vndrie.oui[1],
4149 parsed_info->vndrie.oui[2],
4150 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004151
Arend van Spriel9f440b72013-02-08 15:53:36 +01004152 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004153 break;
4154next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004155 remaining_len -= (ie->len + TLV_HDR_LEN);
4156 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004157 ie = NULL;
4158 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004159 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4160 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004161 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004162 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004163}
4164
4165static u32
4166brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4167{
4168
Hante Meuleman1a873342012-09-27 14:17:54 +02004169 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4170 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4171
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304172 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004173
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304174 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004175
4176 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4177
4178 return ie_len + VNDR_IE_HDR_SIZE;
4179}
4180
Arend van Spriel1332e262012-11-05 16:22:18 -08004181s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4182 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004183{
Arend van Spriel1332e262012-11-05 16:22:18 -08004184 struct brcmf_if *ifp;
4185 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004186 s32 err = 0;
4187 u8 *iovar_ie_buf;
4188 u8 *curr_ie_buf;
4189 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004190 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004191 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004192 u32 del_add_ie_buf_len = 0;
4193 u32 total_ie_buf_len = 0;
4194 u32 parsed_ie_buf_len = 0;
4195 struct parsed_vndr_ies old_vndr_ies;
4196 struct parsed_vndr_ies new_vndr_ies;
4197 struct parsed_vndr_ie_info *vndrie_info;
4198 s32 i;
4199 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004200 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004201
Arend van Spriel1332e262012-11-05 16:22:18 -08004202 if (!vif)
4203 return -ENODEV;
4204 ifp = vif->ifp;
4205 saved_ie = &vif->saved_ie;
4206
Hante Meuleman37a869e2015-10-29 20:33:17 +01004207 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4208 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004209 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4210 if (!iovar_ie_buf)
4211 return -ENOMEM;
4212 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004213 switch (pktflag) {
4214 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4215 mgmt_ie_buf = saved_ie->probe_req_ie;
4216 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4217 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4218 break;
4219 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4220 mgmt_ie_buf = saved_ie->probe_res_ie;
4221 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4222 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4223 break;
4224 case BRCMF_VNDR_IE_BEACON_FLAG:
4225 mgmt_ie_buf = saved_ie->beacon_ie;
4226 mgmt_ie_len = &saved_ie->beacon_ie_len;
4227 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4228 break;
4229 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4230 mgmt_ie_buf = saved_ie->assoc_req_ie;
4231 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4232 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4233 break;
4234 default:
4235 err = -EPERM;
4236 brcmf_err("not suitable type\n");
4237 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004238 }
4239
4240 if (vndr_ie_len > mgmt_ie_buf_len) {
4241 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004242 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004243 goto exit;
4244 }
4245
4246 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4247 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4248 ptr = curr_ie_buf;
4249 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4250 for (i = 0; i < new_vndr_ies.count; i++) {
4251 vndrie_info = &new_vndr_ies.ie_info[i];
4252 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4253 vndrie_info->ie_len);
4254 parsed_ie_buf_len += vndrie_info->ie_len;
4255 }
4256 }
4257
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004258 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004259 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4260 (memcmp(mgmt_ie_buf, curr_ie_buf,
4261 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004262 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004263 goto exit;
4264 }
4265
4266 /* parse old vndr_ie */
4267 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4268
4269 /* make a command to delete old ie */
4270 for (i = 0; i < old_vndr_ies.count; i++) {
4271 vndrie_info = &old_vndr_ies.ie_info[i];
4272
Arend van Sprield96b8012012-12-05 15:26:02 +01004273 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4274 vndrie_info->vndrie.id,
4275 vndrie_info->vndrie.len,
4276 vndrie_info->vndrie.oui[0],
4277 vndrie_info->vndrie.oui[1],
4278 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004279
4280 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4281 vndrie_info->ie_ptr,
4282 vndrie_info->ie_len,
4283 "del");
4284 curr_ie_buf += del_add_ie_buf_len;
4285 total_ie_buf_len += del_add_ie_buf_len;
4286 }
4287 }
4288
4289 *mgmt_ie_len = 0;
4290 /* Add if there is any extra IE */
4291 if (mgmt_ie_buf && parsed_ie_buf_len) {
4292 ptr = mgmt_ie_buf;
4293
4294 remained_buf_len = mgmt_ie_buf_len;
4295
4296 /* make a command to add new ie */
4297 for (i = 0; i < new_vndr_ies.count; i++) {
4298 vndrie_info = &new_vndr_ies.ie_info[i];
4299
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004300 /* verify remained buf size before copy data */
4301 if (remained_buf_len < (vndrie_info->vndrie.len +
4302 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004303 brcmf_err("no space in mgmt_ie_buf: len left %d",
4304 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004305 break;
4306 }
4307 remained_buf_len -= (vndrie_info->ie_len +
4308 VNDR_IE_VSIE_OFFSET);
4309
Arend van Sprield96b8012012-12-05 15:26:02 +01004310 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4311 vndrie_info->vndrie.id,
4312 vndrie_info->vndrie.len,
4313 vndrie_info->vndrie.oui[0],
4314 vndrie_info->vndrie.oui[1],
4315 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004316
4317 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4318 vndrie_info->ie_ptr,
4319 vndrie_info->ie_len,
4320 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004321
4322 /* save the parsed IE in wl struct */
4323 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4324 vndrie_info->ie_len);
4325 *mgmt_ie_len += vndrie_info->ie_len;
4326
4327 curr_ie_buf += del_add_ie_buf_len;
4328 total_ie_buf_len += del_add_ie_buf_len;
4329 }
4330 }
4331 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004332 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004333 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004334 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004335 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004336 }
4337
4338exit:
4339 kfree(iovar_ie_buf);
4340 return err;
4341}
4342
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004343s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4344{
4345 s32 pktflags[] = {
4346 BRCMF_VNDR_IE_PRBREQ_FLAG,
4347 BRCMF_VNDR_IE_PRBRSP_FLAG,
4348 BRCMF_VNDR_IE_BEACON_FLAG
4349 };
4350 int i;
4351
4352 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4353 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4354
4355 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4356 return 0;
4357}
4358
Hante Meuleman1a873342012-09-27 14:17:54 +02004359static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004360brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4361 struct cfg80211_beacon_data *beacon)
4362{
4363 s32 err;
4364
4365 /* Set Beacon IEs to FW */
4366 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4367 beacon->tail, beacon->tail_len);
4368 if (err) {
4369 brcmf_err("Set Beacon IE Failed\n");
4370 return err;
4371 }
4372 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4373
4374 /* Set Probe Response IEs to FW */
4375 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4376 beacon->proberesp_ies,
4377 beacon->proberesp_ies_len);
4378 if (err)
4379 brcmf_err("Set Probe Resp IE Failed\n");
4380 else
4381 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4382
4383 return err;
4384}
4385
4386static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004387brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4388 struct cfg80211_ap_settings *settings)
4389{
4390 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004391 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004392 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004393 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004394 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004395 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004396 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004397 const struct brcmf_tlv *rsn_ie;
4398 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004399 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004400 enum nl80211_iftype dev_role;
4401 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004402 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004403 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004404 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004405 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004406
Arend van Spriel06c01582014-05-12 10:47:37 +02004407 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4408 settings->chandef.chan->hw_value,
4409 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004410 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004411 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4412 settings->ssid, settings->ssid_len, settings->auth_type,
4413 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004414 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004415 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004416
Arend van Spriel98027762014-12-21 12:43:53 +01004417 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004418 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4419 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004420 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004421 } else {
4422 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4423 settings->beacon.tail_len,
4424 WLAN_EID_COUNTRY);
4425 is_11d = country_ie ? 1 : 0;
4426 supports_11d = true;
4427 }
Arend van Spriel98027762014-12-21 12:43:53 +01004428
Hante Meuleman1a873342012-09-27 14:17:54 +02004429 memset(&ssid_le, 0, sizeof(ssid_le));
4430 if (settings->ssid == NULL || settings->ssid_len == 0) {
4431 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4432 ssid_ie = brcmf_parse_tlvs(
4433 (u8 *)&settings->beacon.head[ie_offset],
4434 settings->beacon.head_len - ie_offset,
4435 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004436 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004437 return -EINVAL;
4438
4439 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4440 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004441 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004442 } else {
4443 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4444 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4445 }
4446
Hante Meulemana44aa402014-12-03 21:05:33 +01004447 if (!mbss) {
4448 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004449 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004450 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004451
4452 /* find the RSN_IE */
4453 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4454 settings->beacon.tail_len, WLAN_EID_RSN);
4455
4456 /* find the WPA_IE */
4457 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4458 settings->beacon.tail_len);
4459
Hante Meuleman1a873342012-09-27 14:17:54 +02004460 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004461 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004462 if (wpa_ie != NULL) {
4463 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004464 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004465 if (err < 0)
4466 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004467 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004468 struct brcmf_vs_tlv *tmp_ie;
4469
4470 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4471
Hante Meuleman1a873342012-09-27 14:17:54 +02004472 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004473 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004474 if (err < 0)
4475 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004476 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004477 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004478 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004479 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004480 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004481
Rafał Miłecki8707e082016-05-27 21:07:19 +02004482 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004483 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004484 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004485 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4486 is_11d);
4487 if (err < 0) {
4488 brcmf_err("Regulatory Set Error, %d\n", err);
4489 goto exit;
4490 }
4491 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004492 if (settings->beacon_interval) {
4493 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4494 settings->beacon_interval);
4495 if (err < 0) {
4496 brcmf_err("Beacon Interval Set Error, %d\n",
4497 err);
4498 goto exit;
4499 }
4500 }
4501 if (settings->dtim_period) {
4502 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4503 settings->dtim_period);
4504 if (err < 0) {
4505 brcmf_err("DTIM Interval Set Error, %d\n", err);
4506 goto exit;
4507 }
4508 }
4509
Hante Meuleman8abffd82015-10-29 20:33:16 +01004510 if ((dev_role == NL80211_IFTYPE_AP) &&
4511 ((ifp->ifidx == 0) ||
4512 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004513 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4514 if (err < 0) {
4515 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4516 goto exit;
4517 }
4518 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4519 }
4520
4521 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004522 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004523 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004524 goto exit;
4525 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004526 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004527 /* Multiple-BSS should use same 11d configuration */
4528 err = -EINVAL;
4529 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004530 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004531
4532 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004533 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004534 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4535 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4536
Hante Meulemana0f07952013-02-08 15:53:47 +01004537 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4538 if (err < 0) {
4539 brcmf_err("setting AP mode failed %d\n", err);
4540 goto exit;
4541 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004542 if (!mbss) {
4543 /* Firmware 10.x requires setting channel after enabling
4544 * AP and before bringing interface up.
4545 */
4546 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4547 if (err < 0) {
4548 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4549 chanspec, err);
4550 goto exit;
4551 }
4552 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004553 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4554 if (err < 0) {
4555 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4556 goto exit;
4557 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004558 /* On DOWN the firmware removes the WEP keys, reconfigure
4559 * them if they were set.
4560 */
4561 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004562
4563 memset(&join_params, 0, sizeof(join_params));
4564 /* join parameters starts with ssid */
4565 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4566 /* create softap */
4567 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4568 &join_params, sizeof(join_params));
4569 if (err < 0) {
4570 brcmf_err("SET SSID error (%d)\n", err);
4571 goto exit;
4572 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004573
4574 if (settings->hidden_ssid) {
4575 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4576 if (err) {
4577 brcmf_err("closednet error (%d)\n", err);
4578 goto exit;
4579 }
4580 }
4581
Hante Meulemana0f07952013-02-08 15:53:47 +01004582 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004583 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4584 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4585 if (err < 0) {
4586 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4587 chanspec, err);
4588 goto exit;
4589 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004590 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4591 sizeof(ssid_le));
4592 if (err < 0) {
4593 brcmf_err("setting ssid failed %d\n", err);
4594 goto exit;
4595 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004596 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004597 bss_enable.enable = cpu_to_le32(1);
4598 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4599 sizeof(bss_enable));
4600 if (err < 0) {
4601 brcmf_err("bss_enable config failed %d\n", err);
4602 goto exit;
4603 }
4604
4605 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004606 } else {
4607 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004608 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004609
Wright Fengf25ba692016-11-18 09:59:52 +08004610 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004611 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004612 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004613
4614exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004615 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004616 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004617 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004618 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004619 return err;
4620}
4621
4622static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4623{
Arend van Sprielc1179032012-10-22 13:55:33 -07004624 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004625 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004626 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004627 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004628
Arend van Sprield96b8012012-12-05 15:26:02 +01004629 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004630
Hante Meuleman426d0a52013-02-08 15:53:53 +01004631 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004632 /* Due to most likely deauths outstanding we sleep */
4633 /* first to make sure they get processed by fw. */
4634 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004635
Hante Meulemana44aa402014-12-03 21:05:33 +01004636 if (ifp->vif->mbss) {
4637 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4638 return err;
4639 }
4640
Rafał Miłeckic940de12016-07-06 12:22:54 +02004641 /* First BSS doesn't get a full reset */
4642 if (ifp->bsscfgidx == 0)
4643 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4644
Hante Meuleman5c33a942013-04-02 21:06:18 +02004645 memset(&join_params, 0, sizeof(join_params));
4646 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4647 &join_params, sizeof(join_params));
4648 if (err < 0)
4649 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004650 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004651 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004652 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004653 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4654 if (err < 0)
4655 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004656 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4657 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004658 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4659 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004660 /* Bring device back up so it can be used again */
4661 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4662 if (err < 0)
4663 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004664
4665 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004666 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004667 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004668 bss_enable.enable = cpu_to_le32(0);
4669 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4670 sizeof(bss_enable));
4671 if (err < 0)
4672 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004673 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004674 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004675 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004676 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004677 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004678
Hante Meuleman1a873342012-09-27 14:17:54 +02004679 return err;
4680}
4681
Hante Meulemana0f07952013-02-08 15:53:47 +01004682static s32
4683brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4684 struct cfg80211_beacon_data *info)
4685{
Hante Meulemana0f07952013-02-08 15:53:47 +01004686 struct brcmf_if *ifp = netdev_priv(ndev);
4687 s32 err;
4688
4689 brcmf_dbg(TRACE, "Enter\n");
4690
Hante Meulemana0f07952013-02-08 15:53:47 +01004691 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4692
4693 return err;
4694}
4695
Hante Meuleman1a873342012-09-27 14:17:54 +02004696static int
4697brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004698 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004699{
Hante Meulemana0f07952013-02-08 15:53:47 +01004700 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004701 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004702 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004703 s32 err;
4704
Jouni Malinen89c771e2014-10-10 20:52:40 +03004705 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004706 return -EFAULT;
4707
Jouni Malinen89c771e2014-10-10 20:52:40 +03004708 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004709
Hante Meulemana0f07952013-02-08 15:53:47 +01004710 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4711 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004712 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004713 return -EIO;
4714
Jouni Malinen89c771e2014-10-10 20:52:40 +03004715 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004716 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004717 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004718 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004719 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004720 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004721
Arend van Sprield96b8012012-12-05 15:26:02 +01004722 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004723 return err;
4724}
4725
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004726static int
4727brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4728 const u8 *mac, struct station_parameters *params)
4729{
4730 struct brcmf_if *ifp = netdev_priv(ndev);
4731 s32 err;
4732
4733 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4734 params->sta_flags_mask, params->sta_flags_set);
4735
4736 /* Ignore all 00 MAC */
4737 if (is_zero_ether_addr(mac))
4738 return 0;
4739
4740 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4741 return 0;
4742
4743 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4744 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4745 (void *)mac, ETH_ALEN);
4746 else
4747 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4748 (void *)mac, ETH_ALEN);
4749 if (err < 0)
4750 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4751
4752 return err;
4753}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004754
4755static void
4756brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4757 struct wireless_dev *wdev,
4758 u16 frame_type, bool reg)
4759{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004760 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004761 u16 mgmt_type;
4762
4763 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4764
4765 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004766 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004767 if (reg)
4768 vif->mgmt_rx_reg |= BIT(mgmt_type);
4769 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004770 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004771}
4772
4773
4774static int
4775brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004776 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004777{
4778 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004779 struct ieee80211_channel *chan = params->chan;
4780 const u8 *buf = params->buf;
4781 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004782 const struct ieee80211_mgmt *mgmt;
4783 struct brcmf_cfg80211_vif *vif;
4784 s32 err = 0;
4785 s32 ie_offset;
4786 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004787 struct brcmf_fil_action_frame_le *action_frame;
4788 struct brcmf_fil_af_params_le *af_params;
4789 bool ack;
4790 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004791 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004792
4793 brcmf_dbg(TRACE, "Enter\n");
4794
4795 *cookie = 0;
4796
4797 mgmt = (const struct ieee80211_mgmt *)buf;
4798
Hante Meulemana0f07952013-02-08 15:53:47 +01004799 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4800 brcmf_err("Driver only allows MGMT packet type\n");
4801 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004802 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004803
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004804 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4805
Hante Meulemana0f07952013-02-08 15:53:47 +01004806 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4807 /* Right now the only reason to get a probe response */
4808 /* is for p2p listen response or for p2p GO from */
4809 /* wpa_supplicant. Unfortunately the probe is send */
4810 /* on primary ndev, while dongle wants it on the p2p */
4811 /* vif. Since this is only reason for a probe */
4812 /* response to be sent, the vif is taken from cfg. */
4813 /* If ever desired to send proberesp for non p2p */
4814 /* response then data should be checked for */
4815 /* "DIRECT-". Note in future supplicant will take */
4816 /* dedicated p2p wdev to do this and then this 'hack'*/
4817 /* is not needed anymore. */
4818 ie_offset = DOT11_MGMT_HDR_LEN +
4819 DOT11_BCN_PRB_FIXED_LEN;
4820 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004821 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4822 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4823 err = brcmf_vif_set_mgmt_ie(vif,
4824 BRCMF_VNDR_IE_PRBRSP_FLAG,
4825 &buf[ie_offset],
4826 ie_len);
4827 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4828 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004829 } else if (ieee80211_is_action(mgmt->frame_control)) {
Arend van Spriel8f44c9a2017-07-07 21:09:06 +01004830 if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
4831 brcmf_err("invalid action frame length\n");
4832 err = -EINVAL;
4833 goto exit;
4834 }
Hante Meuleman18e2f612013-02-08 15:53:49 +01004835 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4836 if (af_params == NULL) {
4837 brcmf_err("unable to allocate frame\n");
4838 err = -ENOMEM;
4839 goto exit;
4840 }
4841 action_frame = &af_params->action_frame;
4842 /* Add the packet Id */
4843 action_frame->packet_id = cpu_to_le32(*cookie);
4844 /* Add BSSID */
4845 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4846 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4847 /* Add the length exepted for 802.11 header */
4848 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004849 /* Add the channel. Use the one specified as parameter if any or
4850 * the current one (got from the firmware) otherwise
4851 */
4852 if (chan)
4853 freq = chan->center_freq;
4854 else
4855 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4856 &freq);
4857 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004858 af_params->channel = cpu_to_le32(chan_nr);
4859
4860 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4861 le16_to_cpu(action_frame->len));
4862
4863 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004864 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004865
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004866 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004867 af_params);
4868
4869 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4870 GFP_KERNEL);
4871 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004872 } else {
4873 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004874 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004875 }
4876
Hante Meuleman18e2f612013-02-08 15:53:49 +01004877exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004878 return err;
4879}
4880
4881
4882static int
4883brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4884 struct wireless_dev *wdev,
4885 u64 cookie)
4886{
4887 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4888 struct brcmf_cfg80211_vif *vif;
4889 int err = 0;
4890
4891 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4892
4893 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4894 if (vif == NULL) {
4895 brcmf_err("No p2p device available for probe response\n");
4896 err = -ENODEV;
4897 goto exit;
4898 }
4899 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4900exit:
4901 return err;
4902}
4903
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004904static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4905 struct wireless_dev *wdev,
4906 struct cfg80211_chan_def *chandef)
4907{
4908 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4909 struct net_device *ndev = wdev->netdev;
4910 struct brcmf_if *ifp;
4911 struct brcmu_chan ch;
4912 enum nl80211_band band = 0;
4913 enum nl80211_chan_width width = 0;
4914 u32 chanspec;
4915 int freq, err;
4916
4917 if (!ndev)
4918 return -ENODEV;
4919 ifp = netdev_priv(ndev);
4920
4921 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4922 if (err) {
4923 brcmf_err("chanspec failed (%d)\n", err);
4924 return err;
4925 }
4926
4927 ch.chspec = chanspec;
4928 cfg->d11inf.decchspec(&ch);
4929
4930 switch (ch.band) {
4931 case BRCMU_CHAN_BAND_2G:
4932 band = NL80211_BAND_2GHZ;
4933 break;
4934 case BRCMU_CHAN_BAND_5G:
4935 band = NL80211_BAND_5GHZ;
4936 break;
4937 }
4938
4939 switch (ch.bw) {
4940 case BRCMU_CHAN_BW_80:
4941 width = NL80211_CHAN_WIDTH_80;
4942 break;
4943 case BRCMU_CHAN_BW_40:
4944 width = NL80211_CHAN_WIDTH_40;
4945 break;
4946 case BRCMU_CHAN_BW_20:
4947 width = NL80211_CHAN_WIDTH_20;
4948 break;
4949 case BRCMU_CHAN_BW_80P80:
4950 width = NL80211_CHAN_WIDTH_80P80;
4951 break;
4952 case BRCMU_CHAN_BW_160:
4953 width = NL80211_CHAN_WIDTH_160;
4954 break;
4955 }
4956
4957 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
4958 chandef->chan = ieee80211_get_channel(wiphy, freq);
4959 chandef->width = width;
4960 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
4961 chandef->center_freq2 = 0;
4962
4963 return 0;
4964}
4965
Piotr Haber61730d42013-04-23 12:53:12 +02004966static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4967 struct wireless_dev *wdev,
4968 enum nl80211_crit_proto_id proto,
4969 u16 duration)
4970{
4971 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4972 struct brcmf_cfg80211_vif *vif;
4973
4974 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4975
4976 /* only DHCP support for now */
4977 if (proto != NL80211_CRIT_PROTO_DHCP)
4978 return -EINVAL;
4979
4980 /* suppress and abort scanning */
4981 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4982 brcmf_abort_scanning(cfg);
4983
4984 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4985}
4986
4987static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4988 struct wireless_dev *wdev)
4989{
4990 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4991 struct brcmf_cfg80211_vif *vif;
4992
4993 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4994
4995 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4996 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4997}
4998
Hante Meuleman70b7d942014-07-30 13:20:07 +02004999static s32
5000brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5001 const struct brcmf_event_msg *e, void *data)
5002{
5003 switch (e->reason) {
5004 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5005 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5006 break;
5007 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5008 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5009 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5010 break;
5011 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5012 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5013 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5014 break;
5015 }
5016
5017 return 0;
5018}
5019
Arend van Spriel89c2f382013-08-10 12:27:25 +02005020static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5021{
5022 int ret;
5023
5024 switch (oper) {
5025 case NL80211_TDLS_DISCOVERY_REQ:
5026 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5027 break;
5028 case NL80211_TDLS_SETUP:
5029 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5030 break;
5031 case NL80211_TDLS_TEARDOWN:
5032 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5033 break;
5034 default:
5035 brcmf_err("unsupported operation: %d\n", oper);
5036 ret = -EOPNOTSUPP;
5037 }
5038 return ret;
5039}
5040
5041static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005042 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005043 enum nl80211_tdls_operation oper)
5044{
5045 struct brcmf_if *ifp;
5046 struct brcmf_tdls_iovar_le info;
5047 int ret = 0;
5048
5049 ret = brcmf_convert_nl80211_tdls_oper(oper);
5050 if (ret < 0)
5051 return ret;
5052
5053 ifp = netdev_priv(ndev);
5054 memset(&info, 0, sizeof(info));
5055 info.mode = (u8)ret;
5056 if (peer)
5057 memcpy(info.ea, peer, ETH_ALEN);
5058
5059 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5060 &info, sizeof(info));
5061 if (ret < 0)
5062 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5063
5064 return ret;
5065}
5066
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005067static int
5068brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5069 struct net_device *ndev,
5070 struct cfg80211_connect_params *sme,
5071 u32 changed)
5072{
5073 struct brcmf_if *ifp;
5074 int err;
5075
5076 if (!(changed & UPDATE_ASSOC_IES))
5077 return 0;
5078
5079 ifp = netdev_priv(ndev);
5080 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5081 sme->ie, sme->ie_len);
5082 if (err)
5083 brcmf_err("Set Assoc REQ IE Failed\n");
5084 else
5085 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5086
5087 return err;
5088}
5089
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005090#ifdef CONFIG_PM
5091static int
5092brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5093 struct cfg80211_gtk_rekey_data *gtk)
5094{
5095 struct brcmf_if *ifp = netdev_priv(ndev);
5096 struct brcmf_gtk_keyinfo_le gtk_le;
5097 int ret;
5098
5099 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5100
5101 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5102 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5103 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5104 sizeof(gtk_le.replay_counter));
5105
5106 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5107 sizeof(gtk_le));
5108 if (ret < 0)
5109 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5110
5111 return ret;
5112}
5113#endif
5114
Arend van Spriel2526ff22017-06-09 13:08:48 +01005115static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
5116 const struct cfg80211_pmk_conf *conf)
5117{
5118 struct brcmf_if *ifp;
5119
5120 brcmf_dbg(TRACE, "enter\n");
5121
5122 /* expect using firmware supplicant for 1X */
5123 ifp = netdev_priv(dev);
5124 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5125 return -EINVAL;
5126
5127 return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
5128}
5129
5130static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
5131 const u8 *aa)
5132{
5133 struct brcmf_if *ifp;
5134
5135 brcmf_dbg(TRACE, "enter\n");
5136 ifp = netdev_priv(dev);
5137 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5138 return -EINVAL;
5139
5140 return brcmf_set_pmk(ifp, NULL, 0);
5141}
5142
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005143static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005144 .add_virtual_intf = brcmf_cfg80211_add_iface,
5145 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005146 .change_virtual_intf = brcmf_cfg80211_change_iface,
5147 .scan = brcmf_cfg80211_scan,
5148 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5149 .join_ibss = brcmf_cfg80211_join_ibss,
5150 .leave_ibss = brcmf_cfg80211_leave_ibss,
5151 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005152 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005153 .set_tx_power = brcmf_cfg80211_set_tx_power,
5154 .get_tx_power = brcmf_cfg80211_get_tx_power,
5155 .add_key = brcmf_cfg80211_add_key,
5156 .del_key = brcmf_cfg80211_del_key,
5157 .get_key = brcmf_cfg80211_get_key,
5158 .set_default_key = brcmf_cfg80211_config_default_key,
5159 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5160 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005161 .connect = brcmf_cfg80211_connect,
5162 .disconnect = brcmf_cfg80211_disconnect,
5163 .suspend = brcmf_cfg80211_suspend,
5164 .resume = brcmf_cfg80211_resume,
5165 .set_pmksa = brcmf_cfg80211_set_pmksa,
5166 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005167 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005168 .start_ap = brcmf_cfg80211_start_ap,
5169 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005170 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005171 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005172 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005173 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5174 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005175 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5176 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5177 .remain_on_channel = brcmf_p2p_remain_on_channel,
5178 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005179 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005180 .start_p2p_device = brcmf_p2p_start_device,
5181 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005182 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5183 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005184 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005185 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel2526ff22017-06-09 13:08:48 +01005186 .set_pmk = brcmf_cfg80211_set_pmk,
5187 .del_pmk = brcmf_cfg80211_del_pmk,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005188};
5189
Arend van Spriel3eacf862012-10-22 13:55:30 -07005190struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005191 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005192{
Hante Meulemana44aa402014-12-03 21:05:33 +01005193 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005194 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005195 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005196
Arend van Spriel33a6b152013-02-08 15:53:39 +01005197 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005198 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005199 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5200 if (!vif)
5201 return ERR_PTR(-ENOMEM);
5202
5203 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005204 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005205
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005206 brcmf_init_prof(&vif->profile);
5207
Hante Meulemana44aa402014-12-03 21:05:33 +01005208 if (type == NL80211_IFTYPE_AP) {
5209 mbss = false;
5210 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5211 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5212 mbss = true;
5213 break;
5214 }
5215 }
5216 vif->mbss = mbss;
5217 }
5218
Arend van Spriel3eacf862012-10-22 13:55:30 -07005219 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005220 return vif;
5221}
5222
Arend van Spriel427dec52014-01-06 12:40:47 +01005223void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005224{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005225 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005226 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005227}
5228
Arend van Spriel9df4d542014-01-06 12:40:49 +01005229void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5230{
5231 struct brcmf_cfg80211_vif *vif;
5232 struct brcmf_if *ifp;
5233
5234 ifp = netdev_priv(ndev);
5235 vif = ifp->vif;
5236
Arend van Spriel95ef1232015-08-26 22:15:04 +02005237 if (vif)
5238 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005239}
5240
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005241static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
5242 const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005243{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005244 u32 event = e->event_code;
5245 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005246
Arend van Spriel2526ff22017-06-09 13:08:48 +01005247 if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
5248 event == BRCMF_E_PSK_SUP &&
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005249 status == BRCMF_E_STATUS_FWSUP_COMPLETED)
5250 set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005251 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005252 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005253 memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
5254 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
5255 return true;
5256
5257 set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005258 }
5259
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005260 if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
5261 test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
5262 clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
5263 clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
5264 return true;
5265 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005266 return false;
5267}
5268
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005269static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005270{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005271 u32 event = e->event_code;
5272 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005273
Hante Meuleman68ca3952014-02-25 20:30:26 +01005274 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5275 (event == BRCMF_E_DISASSOC_IND) ||
5276 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005277 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005278 return true;
5279 }
5280 return false;
5281}
5282
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005283static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005284 const struct brcmf_event_msg *e)
5285{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005286 u32 event = e->event_code;
5287 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005288
5289 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005290 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5291 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005292 return true;
5293 }
5294
5295 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005296 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005297 return true;
5298 }
5299
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005300 if (event == BRCMF_E_PSK_SUP &&
5301 status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
5302 brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
5303 status);
5304 return true;
5305 }
5306
Arend van Spriel5b435de2011-10-05 13:19:03 +02005307 return false;
5308}
5309
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005310static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005311{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005312 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005313
5314 kfree(conn_info->req_ie);
5315 conn_info->req_ie = NULL;
5316 conn_info->req_ie_len = 0;
5317 kfree(conn_info->resp_ie);
5318 conn_info->resp_ie = NULL;
5319 conn_info->resp_ie_len = 0;
5320}
5321
Hante Meuleman89286dc2013-02-08 15:53:46 +01005322static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5323 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005324{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005325 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005326 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005327 u32 req_len;
5328 u32 resp_len;
5329 s32 err = 0;
5330
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005331 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005332
Arend van Sprielac24be62012-10-22 10:36:23 -07005333 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5334 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005335 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005336 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005337 return err;
5338 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005339 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005340 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005341 req_len = le32_to_cpu(assoc_info->req_len);
5342 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005343 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005344 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005345 cfg->extra_buf,
5346 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005347 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005348 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005349 return err;
5350 }
5351 conn_info->req_ie_len = req_len;
5352 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005353 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005354 GFP_KERNEL);
5355 } else {
5356 conn_info->req_ie_len = 0;
5357 conn_info->req_ie = NULL;
5358 }
5359 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005360 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005361 cfg->extra_buf,
5362 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005364 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005365 return err;
5366 }
5367 conn_info->resp_ie_len = resp_len;
5368 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005369 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005370 GFP_KERNEL);
5371 } else {
5372 conn_info->resp_ie_len = 0;
5373 conn_info->resp_ie = NULL;
5374 }
Arend van Spriel16886732012-12-05 15:26:04 +01005375 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5376 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005377
5378 return err;
5379}
5380
5381static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005382brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005383 struct net_device *ndev,
5384 const struct brcmf_event_msg *e)
5385{
Arend van Sprielc1179032012-10-22 13:55:33 -07005386 struct brcmf_if *ifp = netdev_priv(ndev);
5387 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005388 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5389 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005390 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005391 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005392 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005393 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005394 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005395 u32 freq;
5396 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005397 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005398
Arend van Sprield96b8012012-12-05 15:26:02 +01005399 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005400
Hante Meuleman89286dc2013-02-08 15:53:46 +01005401 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005402 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005403 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005404
Franky Lina180b832012-10-10 11:13:09 -07005405 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5406 if (buf == NULL) {
5407 err = -ENOMEM;
5408 goto done;
5409 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005410
Franky Lina180b832012-10-10 11:13:09 -07005411 /* data sent to dongle has to be little endian */
5412 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005413 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005414 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005415
5416 if (err)
5417 goto done;
5418
5419 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005420 ch.chspec = le16_to_cpu(bi->chanspec);
5421 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005422
Franky Lin83cf17a2013-04-11 13:28:50 +02005423 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005424 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005425 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005426 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005427
Rafał Miłecki4712d882016-05-20 13:38:57 +02005428 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005429 notify_channel = ieee80211_get_channel(wiphy, freq);
5430
Franky Lina180b832012-10-10 11:13:09 -07005431done:
5432 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005433
5434 roam_info.channel = notify_channel;
5435 roam_info.bssid = profile->bssid;
5436 roam_info.req_ie = conn_info->req_ie;
5437 roam_info.req_ie_len = conn_info->req_ie_len;
5438 roam_info.resp_ie = conn_info->resp_ie;
5439 roam_info.resp_ie_len = conn_info->resp_ie_len;
5440
5441 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005442 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005443
Arend van Sprielc1179032012-10-22 13:55:33 -07005444 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005445 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005446 return err;
5447}
5448
5449static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005450brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451 struct net_device *ndev, const struct brcmf_event_msg *e,
5452 bool completed)
5453{
Arend van Sprielc1179032012-10-22 13:55:33 -07005454 struct brcmf_if *ifp = netdev_priv(ndev);
5455 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005456 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel123fef32017-06-09 13:08:49 +01005457 struct cfg80211_connect_resp_params conn_params;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005458
Arend van Sprield96b8012012-12-05 15:26:02 +01005459 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005460
Arend van Sprielc1179032012-10-22 13:55:33 -07005461 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5462 &ifp->vif->sme_state)) {
Arend van Spriel123fef32017-06-09 13:08:49 +01005463 memset(&conn_params, 0, sizeof(conn_params));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005464 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005465 brcmf_get_assoc_ies(cfg, ifp);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005466 brcmf_update_bss_info(cfg, ifp);
5467 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5468 &ifp->vif->sme_state);
Arend van Spriel123fef32017-06-09 13:08:49 +01005469 conn_params.status = WLAN_STATUS_SUCCESS;
5470 } else {
5471 conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005472 }
Arend van Spriel123fef32017-06-09 13:08:49 +01005473 conn_params.bssid = profile->bssid;
5474 conn_params.req_ie = conn_info->req_ie;
5475 conn_params.req_ie_len = conn_info->req_ie_len;
5476 conn_params.resp_ie = conn_info->resp_ie;
5477 conn_params.resp_ie_len = conn_info->resp_ie_len;
5478 cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005479 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5480 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005481 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005482 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005483 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005484}
5485
5486static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005487brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005488 struct net_device *ndev,
5489 const struct brcmf_event_msg *e, void *data)
5490{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005491 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005492 u32 event = e->event_code;
5493 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005494 struct station_info sinfo;
5495
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005496 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5497 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005498 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5499 ndev != cfg_to_ndev(cfg)) {
5500 brcmf_dbg(CONN, "AP mode link down\n");
5501 complete(&cfg->vif_disabled);
5502 return 0;
5503 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005504
Hante Meuleman1a873342012-09-27 14:17:54 +02005505 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005506 (reason == BRCMF_E_STATUS_SUCCESS)) {
5507 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005508 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005509 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005510 return -EINVAL;
5511 }
5512 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005513 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005514 generation++;
5515 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005516 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005517 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5518 (event == BRCMF_E_DEAUTH_IND) ||
5519 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005520 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005521 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005522 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005523}
5524
5525static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005526brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005527 const struct brcmf_event_msg *e, void *data)
5528{
Arend van Spriel19937322012-11-05 16:22:32 -08005529 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5530 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005531 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005532 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005533 s32 err = 0;
5534
Hante Meuleman8851cce2014-07-30 13:20:02 +02005535 if ((e->event_code == BRCMF_E_DEAUTH) ||
5536 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5537 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5538 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5539 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5540 }
5541
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005542 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005543 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005544 } else if (brcmf_is_linkup(ifp->vif, e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005545 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005546 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005547 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005548 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005549 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005550 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005551 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5552 &ifp->vif->sme_state);
5553 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5554 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005555 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005556 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005557 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005558 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005559 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005560 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005561 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005562 brcmf_link_down(ifp->vif,
5563 brcmf_map_fw_linkdown_reason(e));
5564 brcmf_init_prof(ndev_to_prof(ndev));
5565 if (ndev != cfg_to_ndev(cfg))
5566 complete(&cfg->vif_disabled);
5567 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005568 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005569 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005570 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005571 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5572 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005573 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005574 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005575 }
5576
5577 return err;
5578}
5579
5580static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005581brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005582 const struct brcmf_event_msg *e, void *data)
5583{
Arend van Spriel19937322012-11-05 16:22:32 -08005584 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005585 u32 event = e->event_code;
5586 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005587
5588 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005589 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
5590 &ifp->vif->sme_state)) {
Arend van Spriel19937322012-11-05 16:22:32 -08005591 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005592 } else {
Arend van Spriel19937322012-11-05 16:22:32 -08005593 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005594 brcmf_net_setcarrier(ifp, true);
5595 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005596 }
5597
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005598 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005599}
5600
5601static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005602brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005603 const struct brcmf_event_msg *e, void *data)
5604{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005605 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005606 enum nl80211_key_type key_type;
5607
5608 if (flags & BRCMF_EVENT_MSG_GROUP)
5609 key_type = NL80211_KEYTYPE_GROUP;
5610 else
5611 key_type = NL80211_KEYTYPE_PAIRWISE;
5612
Arend van Spriel19937322012-11-05 16:22:32 -08005613 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005614 NULL, GFP_KERNEL);
5615
5616 return 0;
5617}
5618
Arend van Sprield3c0b632013-02-08 15:53:37 +01005619static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5620 const struct brcmf_event_msg *e, void *data)
5621{
5622 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5623 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5624 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5625 struct brcmf_cfg80211_vif *vif;
5626
Hante Meuleman37a869e2015-10-29 20:33:17 +01005627 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005628 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005629 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005630
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005631 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005632 event->action = ifevent->action;
5633 vif = event->vif;
5634
5635 switch (ifevent->action) {
5636 case BRCMF_E_IF_ADD:
5637 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005638 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005639 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005640 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005641 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005642
5643 ifp->vif = vif;
5644 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005645 if (ifp->ndev) {
5646 vif->wdev.netdev = ifp->ndev;
5647 ifp->ndev->ieee80211_ptr = &vif->wdev;
5648 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5649 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005650 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005651 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005652 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005653
5654 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005655 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005656 /* event may not be upon user request */
5657 if (brcmf_cfg80211_vif_event_armed(cfg))
5658 wake_up(&event->vif_wq);
5659 return 0;
5660
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005661 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005662 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005663 wake_up(&event->vif_wq);
5664 return 0;
5665
Arend van Sprield3c0b632013-02-08 15:53:37 +01005666 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005667 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005668 break;
5669 }
5670 return -EINVAL;
5671}
5672
Arend van Spriel5b435de2011-10-05 13:19:03 +02005673static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5674{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005675 conf->frag_threshold = (u32)-1;
5676 conf->rts_threshold = (u32)-1;
5677 conf->retry_short = (u32)-1;
5678 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005679}
5680
Arend van Spriel5c36b992012-11-14 18:46:05 -08005681static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005682{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005683 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5684 brcmf_notify_connect_status);
5685 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5686 brcmf_notify_connect_status);
5687 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5688 brcmf_notify_connect_status);
5689 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5690 brcmf_notify_connect_status);
5691 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5692 brcmf_notify_connect_status);
5693 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5694 brcmf_notify_connect_status);
5695 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5696 brcmf_notify_roaming_status);
5697 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5698 brcmf_notify_mic_status);
5699 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5700 brcmf_notify_connect_status);
5701 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5702 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005703 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5704 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005705 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005706 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005707 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5708 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005709 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5710 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005711 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5712 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005713 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5714 brcmf_p2p_notify_action_tx_complete);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005715 brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
5716 brcmf_notify_connect_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005717}
5718
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005719static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005720{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005721 kfree(cfg->conf);
5722 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005723 kfree(cfg->extra_buf);
5724 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005725 kfree(cfg->wowl.nd);
5726 cfg->wowl.nd = NULL;
5727 kfree(cfg->wowl.nd_info);
5728 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005729 kfree(cfg->escan_info.escan_buf);
5730 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005731}
5732
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005733static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005734{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005735 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5736 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005737 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005738 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5739 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005740 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005741 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5742 if (!cfg->wowl.nd)
5743 goto init_priv_mem_out;
5744 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5745 sizeof(struct cfg80211_wowlan_nd_match *),
5746 GFP_KERNEL);
5747 if (!cfg->wowl.nd_info)
5748 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005749 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5750 if (!cfg->escan_info.escan_buf)
5751 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005752
5753 return 0;
5754
5755init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005756 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005757
5758 return -ENOMEM;
5759}
5760
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005761static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005762{
5763 s32 err = 0;
5764
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005765 cfg->scan_request = NULL;
5766 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005767 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005768 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005769 if (err)
5770 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005771 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005772 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005773 brcmf_init_escan(cfg);
5774 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005775 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005776 return err;
5777}
5778
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005779static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005780{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005781 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005782 brcmf_abort_scanning(cfg);
5783 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005784}
5785
Arend van Sprield3c0b632013-02-08 15:53:37 +01005786static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5787{
5788 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005789 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005790}
5791
Hante Meuleman1119e232015-11-25 11:32:42 +01005792static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005793{
Hante Meuleman1119e232015-11-25 11:32:42 +01005794 s32 err;
5795 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005796 __le32 roamtrigger[2];
5797 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005798
Hante Meuleman1119e232015-11-25 11:32:42 +01005799 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005800 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005801 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5802 else
5803 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5804 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5805 if (err) {
5806 brcmf_err("bcn_timeout error (%d)\n", err);
5807 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005808 }
5809
Hante Meuleman1119e232015-11-25 11:32:42 +01005810 /* Enable/Disable built-in roaming to allow supplicant to take care of
5811 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005812 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005813 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005814 ifp->drvr->settings->roamoff ? "Off" : "On");
5815 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5816 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005817 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005818 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005819 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005820 }
5821
Arend van Sprielf588bc02011-10-12 20:51:22 +02005822 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5823 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005824 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005825 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005826 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005827 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005828 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005829 }
5830
Arend van Sprielf588bc02011-10-12 20:51:22 +02005831 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5832 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005833 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005834 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005835 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005836 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005837 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005838 }
5839
Hante Meuleman1119e232015-11-25 11:32:42 +01005840roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005841 return err;
5842}
5843
5844static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005845brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005846{
5847 s32 err = 0;
5848
Arend van Sprielac24be62012-10-22 10:36:23 -07005849 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005850 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005851 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005852 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005853 goto dongle_scantime_out;
5854 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005855 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005856 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005857 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005858 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005859 goto dongle_scantime_out;
5860 }
5861
Arend van Sprielac24be62012-10-22 10:36:23 -07005862 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005863 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005864 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005865 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005866 goto dongle_scantime_out;
5867 }
5868
5869dongle_scantime_out:
5870 return err;
5871}
5872
Arend van Sprielb48d8912014-07-12 08:49:41 +02005873static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5874 struct brcmu_chan *ch)
5875{
5876 u32 ht40_flag;
5877
5878 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5879 if (ch->sb == BRCMU_CHAN_SB_U) {
5880 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5881 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5882 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5883 } else {
5884 /* It should be one of
5885 * IEEE80211_CHAN_NO_HT40 or
5886 * IEEE80211_CHAN_NO_HT40PLUS
5887 */
5888 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5889 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5890 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5891 }
5892}
5893
5894static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5895 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005896{
5897 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005898 struct ieee80211_supported_band *band;
5899 struct ieee80211_channel *channel;
5900 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005901 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005902 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005903 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005904 u8 *pbuf;
5905 u32 i, j;
5906 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005907 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005908
5909 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5910
5911 if (pbuf == NULL)
5912 return -ENOMEM;
5913
5914 list = (struct brcmf_chanspec_list *)pbuf;
5915
5916 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5917 BRCMF_DCMD_MEDLEN);
5918 if (err) {
5919 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005920 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005921 }
5922
Arend van Sprielb48d8912014-07-12 08:49:41 +02005923 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005924 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005925 if (band)
5926 for (i = 0; i < band->n_channels; i++)
5927 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005928 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005929 if (band)
5930 for (i = 0; i < band->n_channels; i++)
5931 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005932
5933 total = le32_to_cpu(list->count);
5934 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005935 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5936 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005937
Franky Lin83cf17a2013-04-11 13:28:50 +02005938 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005939 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005940 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005941 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005942 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005943 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005944 continue;
5945 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005946 if (!band)
5947 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005948 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005949 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005950 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005951 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005952 ch.bw == BRCMU_CHAN_BW_80)
5953 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005954
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005955 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005956 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005957 if (band->channels[j].hw_value == ch.control_ch_num) {
5958 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02005959 break;
5960 }
5961 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005962 if (!channel) {
5963 /* It seems firmware supports some channel we never
5964 * considered. Something new in IEEE standard?
5965 */
5966 brcmf_err("Ignoring unexpected firmware channel %d\n",
5967 ch.control_ch_num);
5968 continue;
5969 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005970
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01005971 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
5972 continue;
5973
Arend van Sprielb48d8912014-07-12 08:49:41 +02005974 /* assuming the chanspecs order is HT20,
5975 * HT40 upper, HT40 lower, and VHT80.
5976 */
5977 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005978 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005979 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005980 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005981 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005982 /* enable the channel and disable other bandwidths
5983 * for now as mentioned order assure they are enabled
5984 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005985 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005986 channel->flags = IEEE80211_CHAN_NO_HT40 |
5987 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005988 ch.bw = BRCMU_CHAN_BW_20;
5989 cfg->d11inf.encchspec(&ch);
5990 chaninfo = ch.chspec;
5991 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5992 &chaninfo);
5993 if (!err) {
5994 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005995 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02005996 (IEEE80211_CHAN_RADAR |
5997 IEEE80211_CHAN_NO_IR);
5998 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005999 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006000 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006001 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006002 }
6003 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006004
Arend van Sprielb48d8912014-07-12 08:49:41 +02006005fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006006 kfree(pbuf);
6007 return err;
6008}
6009
Arend van Sprielb48d8912014-07-12 08:49:41 +02006010static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006011{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006012 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6013 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006014 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006015 struct brcmf_chanspec_list *list;
6016 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006017 u32 val;
6018 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006019 struct brcmu_chan ch;
6020 u32 num_chan;
6021 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006022
6023 /* verify support for bw_cap command */
6024 val = WLC_BAND_5G;
6025 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6026
6027 if (!err) {
6028 /* only set 2G bandwidth using bw_cap command */
6029 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6030 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6031 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6032 sizeof(band_bwcap));
6033 } else {
6034 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6035 val = WLC_N_BW_40ALL;
6036 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6037 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006038
6039 if (!err) {
6040 /* update channel info in 2G band */
6041 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6042
6043 if (pbuf == NULL)
6044 return -ENOMEM;
6045
6046 ch.band = BRCMU_CHAN_BAND_2G;
6047 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006048 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006049 ch.chnum = 0;
6050 cfg->d11inf.encchspec(&ch);
6051
6052 /* pass encoded chanspec in query */
6053 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6054
6055 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6056 BRCMF_DCMD_MEDLEN);
6057 if (err) {
6058 brcmf_err("get chanspecs error (%d)\n", err);
6059 kfree(pbuf);
6060 return err;
6061 }
6062
Johannes Berg57fbcce2016-04-12 15:56:15 +02006063 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006064 list = (struct brcmf_chanspec_list *)pbuf;
6065 num_chan = le32_to_cpu(list->count);
6066 for (i = 0; i < num_chan; i++) {
6067 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6068 cfg->d11inf.decchspec(&ch);
6069 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6070 continue;
6071 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6072 continue;
6073 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006074 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006075 break;
6076 }
6077 if (WARN_ON(j == band->n_channels))
6078 continue;
6079
6080 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6081 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006082 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006083 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006084 return err;
6085}
6086
Arend van Spriel2375d972014-01-06 12:40:41 +01006087static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6088{
6089 u32 band, mimo_bwcap;
6090 int err;
6091
6092 band = WLC_BAND_2G;
6093 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6094 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006095 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006096 band = WLC_BAND_5G;
6097 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6098 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006099 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006100 return;
6101 }
6102 WARN_ON(1);
6103 return;
6104 }
6105 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6106 mimo_bwcap = 0;
6107 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6108 if (err)
6109 /* assume 20MHz if firmware does not give a clue */
6110 mimo_bwcap = WLC_N_BW_20ALL;
6111
6112 switch (mimo_bwcap) {
6113 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006114 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006115 /* fall-thru */
6116 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006117 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006118 /* fall-thru */
6119 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006120 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6121 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006122 break;
6123 default:
6124 brcmf_err("invalid mimo_bw_cap value\n");
6125 }
6126}
Hante Meulemand48200b2013-04-03 12:40:29 +02006127
Arend van Spriel18d6c532014-05-12 10:47:35 +02006128static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6129 u32 bw_cap[2], u32 nchain)
6130{
6131 band->ht_cap.ht_supported = true;
6132 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6133 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6134 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6135 }
6136 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6137 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6138 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6139 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6140 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6141 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6142}
6143
6144static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6145{
6146 u16 mcs_map;
6147 int i;
6148
6149 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6150 mcs_map = (mcs_map << 2) | supp;
6151
6152 return cpu_to_le16(mcs_map);
6153}
6154
6155static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006156 u32 bw_cap[2], u32 nchain, u32 txstreams,
6157 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006158{
6159 __le16 mcs_map;
6160
6161 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006162 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006163 return;
6164
6165 band->vht_cap.vht_supported = true;
6166 /* 80MHz is mandatory */
6167 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6168 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6169 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6170 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6171 }
6172 /* all support 256-QAM */
6173 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6174 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6175 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006176
6177 /* Beamforming support information */
6178 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6179 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6180 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6181 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6182 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6183 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6184 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6185 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6186
6187 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6188 band->vht_cap.cap |=
6189 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6190 band->vht_cap.cap |= ((txstreams - 1) <<
6191 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6192 band->vht_cap.cap |=
6193 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6194 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006195}
6196
Arend van Sprielb48d8912014-07-12 08:49:41 +02006197static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006198{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006199 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006200 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006201 u32 nmode = 0;
6202 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006203 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006204 u32 rxchain;
6205 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006206 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006207 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006208 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006209 u32 txstreams = 0;
6210 u32 txbf_bfe_cap = 0;
6211 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006212
Arend van Spriel18d6c532014-05-12 10:47:35 +02006213 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006214 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6215 if (err) {
6216 brcmf_err("nmode error (%d)\n", err);
6217 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006218 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006219 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006220 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006221 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6222 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006223
Daniel Kim4aca7a12014-02-25 20:30:36 +01006224 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6225 if (err) {
6226 brcmf_err("rxchain error (%d)\n", err);
6227 nchain = 1;
6228 } else {
6229 for (nchain = 0; rxchain; nchain++)
6230 rxchain = rxchain & (rxchain - 1);
6231 }
6232 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6233
Arend van Sprielb48d8912014-07-12 08:49:41 +02006234 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006235 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006236 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006237 return err;
6238 }
6239
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006240 if (vhtmode) {
6241 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6242 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6243 &txbf_bfe_cap);
6244 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6245 &txbf_bfr_cap);
6246 }
6247
Arend van Sprielb48d8912014-07-12 08:49:41 +02006248 wiphy = cfg_to_wiphy(cfg);
6249 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6250 band = wiphy->bands[i];
6251 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006252 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006253
Arend van Spriel18d6c532014-05-12 10:47:35 +02006254 if (nmode)
6255 brcmf_update_ht_cap(band, bw_cap, nchain);
6256 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006257 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6258 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006259 }
6260
Arend van Sprielb48d8912014-07-12 08:49:41 +02006261 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006262}
6263
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006264static const struct ieee80211_txrx_stypes
6265brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6266 [NL80211_IFTYPE_STATION] = {
6267 .tx = 0xffff,
6268 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6269 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6270 },
6271 [NL80211_IFTYPE_P2P_CLIENT] = {
6272 .tx = 0xffff,
6273 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6274 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6275 },
6276 [NL80211_IFTYPE_P2P_GO] = {
6277 .tx = 0xffff,
6278 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6279 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6280 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6281 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6282 BIT(IEEE80211_STYPE_AUTH >> 4) |
6283 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6284 BIT(IEEE80211_STYPE_ACTION >> 4)
6285 },
6286 [NL80211_IFTYPE_P2P_DEVICE] = {
6287 .tx = 0xffff,
6288 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6289 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6290 }
6291};
6292
Arend van Spriel0882dda2015-08-20 22:06:03 +02006293/**
6294 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6295 *
6296 * @wiphy: wiphy object.
6297 * @ifp: interface object needed for feat module api.
6298 *
6299 * The interface modes and combinations are determined dynamically here
6300 * based on firmware functionality.
6301 *
6302 * no p2p and no mbss:
6303 *
6304 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6305 *
6306 * no p2p and mbss:
6307 *
6308 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6309 * #AP <= 4, matching BI, channels = 1, 4 total
6310 *
6311 * p2p, no mchan, and mbss:
6312 *
6313 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6314 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6315 * #AP <= 4, matching BI, channels = 1, 4 total
6316 *
6317 * p2p, mchan, and mbss:
6318 *
6319 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6320 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6321 * #AP <= 4, matching BI, channels = 1, 4 total
6322 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006323static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6324{
6325 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006326 struct ieee80211_iface_limit *c0_limits = NULL;
6327 struct ieee80211_iface_limit *p2p_limits = NULL;
6328 struct ieee80211_iface_limit *mbss_limits = NULL;
6329 bool mbss, p2p;
6330 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006331
Arend van Spriel0882dda2015-08-20 22:06:03 +02006332 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6333 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6334
6335 n_combos = 1 + !!p2p + !!mbss;
6336 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006337 if (!combo)
6338 goto err;
6339
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006340 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6341 BIT(NL80211_IFTYPE_ADHOC) |
6342 BIT(NL80211_IFTYPE_AP);
6343
Arend van Spriel0882dda2015-08-20 22:06:03 +02006344 c = 0;
6345 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006346 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6347 if (!c0_limits)
6348 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006349 c0_limits[i].max = 1;
6350 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6351 if (p2p) {
6352 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6353 combo[c].num_different_channels = 2;
Wright Feng99976fc2017-08-03 17:37:59 +08006354 else
6355 combo[c].num_different_channels = 1;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006356 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6357 BIT(NL80211_IFTYPE_P2P_GO) |
6358 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006359 c0_limits[i].max = 1;
6360 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6361 c0_limits[i].max = 1;
6362 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6363 BIT(NL80211_IFTYPE_P2P_GO);
6364 } else {
Wright Feng99976fc2017-08-03 17:37:59 +08006365 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006366 c0_limits[i].max = 1;
6367 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006368 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006369 combo[c].max_interfaces = i;
6370 combo[c].n_limits = i;
6371 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006372
Arend van Spriel0882dda2015-08-20 22:06:03 +02006373 if (p2p) {
6374 c++;
6375 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006376 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6377 if (!p2p_limits)
6378 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006379 p2p_limits[i].max = 1;
6380 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6381 p2p_limits[i].max = 1;
6382 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6383 p2p_limits[i].max = 1;
6384 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6385 p2p_limits[i].max = 1;
6386 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006387 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006388 combo[c].max_interfaces = i;
6389 combo[c].n_limits = i;
6390 combo[c].limits = p2p_limits;
6391 }
6392
6393 if (mbss) {
6394 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006395 i = 0;
6396 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6397 if (!mbss_limits)
6398 goto err;
6399 mbss_limits[i].max = 4;
6400 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006401 combo[c].beacon_int_infra_match = true;
6402 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006403 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006404 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006405 combo[c].limits = mbss_limits;
6406 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006407
Arend van Spriel0882dda2015-08-20 22:06:03 +02006408 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006409 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006410 return 0;
6411
6412err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006413 kfree(c0_limits);
6414 kfree(p2p_limits);
6415 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006416 kfree(combo);
6417 return -ENOMEM;
6418}
6419
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006420#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006421static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006422 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006423 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6424 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6425 .pattern_min_len = 1,
6426 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006427};
6428#endif
6429
Hante Meuleman3021ad92016-01-05 11:05:45 +01006430static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006431{
6432#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006433 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006434 struct wiphy_wowlan_support *wowl;
6435
6436 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6437 GFP_KERNEL);
6438 if (!wowl) {
6439 brcmf_err("only support basic wowlan features\n");
6440 wiphy->wowlan = &brcmf_wowlan_support;
6441 return;
6442 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006443
6444 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006445 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006446 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6447 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006448 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006449 }
6450 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006451 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006452 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6453 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006454 }
6455
Arend Van Spriel0b570102017-01-27 12:27:47 +00006456 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006457#endif
6458}
6459
Arend van Sprielb48d8912014-07-12 08:49:41 +02006460static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006461{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006462 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006463 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006464 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006465 u16 max_interfaces = 0;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006466 bool gscan;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006467 __le32 bandlist[3];
6468 u32 n_bands;
6469 int err, i;
6470
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006471 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6472 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006473 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006474
6475 err = brcmf_setup_ifmodes(wiphy, ifp);
6476 if (err)
6477 return err;
6478
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006479 for (i = 0, combo = wiphy->iface_combinations;
6480 i < wiphy->n_iface_combinations; i++, combo++) {
6481 max_interfaces = max(max_interfaces, combo->max_interfaces);
6482 }
6483
6484 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6485 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006486 u8 *addr = drvr->addresses[i].addr;
6487
6488 memcpy(addr, drvr->mac, ETH_ALEN);
6489 if (i) {
6490 addr[0] |= BIT(1);
6491 addr[ETH_ALEN - 1] ^= i;
6492 }
6493 }
6494 wiphy->addresses = drvr->addresses;
6495 wiphy->n_addresses = i;
6496
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006497 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006498 wiphy->cipher_suites = brcmf_cipher_suites;
6499 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6500 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6501 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006502 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6503 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6504 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6505
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006506 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6507 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006508 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006509 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6510 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6511 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006512 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006513 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
Arend van Spriel2526ff22017-06-09 13:08:48 +01006514 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01006515 wiphy_ext_feature_set(wiphy,
6516 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
Arend van Spriel2526ff22017-06-09 13:08:48 +01006517 wiphy_ext_feature_set(wiphy,
6518 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
6519 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006520 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6521 wiphy->max_remain_on_channel_duration = 5000;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006522 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
6523 gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
6524 brcmf_pno_wiphy_params(wiphy, gscan);
6525 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006526 /* vendor commands/events support */
6527 wiphy->vendor_commands = brcmf_vendor_cmds;
6528 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6529
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006530 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006531 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006532 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6533 sizeof(bandlist));
6534 if (err) {
6535 brcmf_err("could not obtain band info: err=%d\n", err);
6536 return err;
6537 }
6538 /* first entry in bandlist is number of bands */
6539 n_bands = le32_to_cpu(bandlist[0]);
6540 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6541 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6542 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6543 GFP_KERNEL);
6544 if (!band)
6545 return -ENOMEM;
6546
6547 band->channels = kmemdup(&__wl_2ghz_channels,
6548 sizeof(__wl_2ghz_channels),
6549 GFP_KERNEL);
6550 if (!band->channels) {
6551 kfree(band);
6552 return -ENOMEM;
6553 }
6554
6555 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006556 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006557 }
6558 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6559 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6560 GFP_KERNEL);
6561 if (!band)
6562 return -ENOMEM;
6563
6564 band->channels = kmemdup(&__wl_5ghz_channels,
6565 sizeof(__wl_5ghz_channels),
6566 GFP_KERNEL);
6567 if (!band->channels) {
6568 kfree(band);
6569 return -ENOMEM;
6570 }
6571
6572 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006573 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006574 }
6575 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006576
6577 wiphy_read_of_freq_limits(wiphy);
6578
Rafał Miłeckiab990632017-01-07 21:36:05 +01006579 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006580}
6581
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006582static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006583{
6584 struct net_device *ndev;
6585 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006586 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006587 s32 power_mode;
6588 s32 err = 0;
6589
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006590 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006591 return err;
6592
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006593 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006594 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006595 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006596
Hante Meuleman40a23292013-01-02 15:22:51 +01006597 /* make sure RF is ready for work */
6598 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6599
Hante Meuleman1678ba82015-12-10 13:43:00 +01006600 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006601
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006602 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006603 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006604 if (err)
6605 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006606 brcmf_dbg(INFO, "power save set to %s\n",
6607 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006608
Hante Meuleman1119e232015-11-25 11:32:42 +01006609 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006610 if (err)
6611 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006612 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006613 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006614 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006615 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006616
Franky Lin52f22fb2016-02-17 11:26:55 +01006617 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006618
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006619 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006620default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006621
6622 return err;
6623
6624}
6625
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006626static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006627{
Arend van Sprielc1179032012-10-22 13:55:33 -07006628 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006629
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006630 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006631}
6632
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006633static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006634{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006635 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006636
Arend van Spriel5b435de2011-10-05 13:19:03 +02006637 /*
6638 * While going down, if associated with AP disassociate
6639 * from AP to save power
6640 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006641 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006642 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006643
6644 /* Make sure WPA_Supplicant receives all the event
6645 generated due to DISASSOC call to the fw to keep
6646 the state fw and WPA_Supplicant state consistent
6647 */
6648 brcmf_delay(500);
6649 }
6650
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006651 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006652 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006653
Arend van Spriel5b435de2011-10-05 13:19:03 +02006654 return 0;
6655}
6656
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006657s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006658{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006659 struct brcmf_if *ifp = netdev_priv(ndev);
6660 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006661 s32 err = 0;
6662
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006663 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006664 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006665 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006666
6667 return err;
6668}
6669
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006670s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006671{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006672 struct brcmf_if *ifp = netdev_priv(ndev);
6673 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006674 s32 err = 0;
6675
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006676 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006677 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006678 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006679
6680 return err;
6681}
6682
Arend van Spriela7965fb2013-04-11 17:08:37 +02006683enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6684{
6685 struct wireless_dev *wdev = &ifp->vif->wdev;
6686
6687 return wdev->iftype;
6688}
6689
Hante Meulemanbfe81972014-10-28 14:56:16 +01006690bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6691 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006692{
6693 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006694
6695 list_for_each_entry(vif, &cfg->vif_list, list) {
6696 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006697 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006698 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006699 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006700}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006701
6702static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6703 u8 action)
6704{
6705 u8 evt_action;
6706
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006707 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006708 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006709 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006710 return evt_action == action;
6711}
6712
6713void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6714 struct brcmf_cfg80211_vif *vif)
6715{
6716 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6717
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006718 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006719 event->vif = vif;
6720 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006721 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006722}
6723
6724bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6725{
6726 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6727 bool armed;
6728
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006729 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006730 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006731 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006732
6733 return armed;
6734}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006735
6736int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6737 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006738{
6739 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6740
6741 return wait_event_timeout(event->vif_wq,
6742 vif_event_equals(event, action), timeout);
6743}
6744
Hante Meuleman73345fd2016-02-17 11:26:53 +01006745static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6746 struct brcmf_fil_country_le *ccreq)
6747{
Hante Meuleman4d792892016-02-17 11:27:07 +01006748 struct brcmfmac_pd_cc *country_codes;
6749 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006750 s32 found_index;
6751 int i;
6752
6753 country_codes = drvr->settings->country_codes;
6754 if (!country_codes) {
6755 brcmf_dbg(TRACE, "No country codes configured for device\n");
6756 return -EINVAL;
6757 }
6758
6759 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6760 (alpha2[1] == ccreq->country_abbrev[1])) {
6761 brcmf_dbg(TRACE, "Country code already set\n");
6762 return -EAGAIN;
6763 }
6764
6765 found_index = -1;
6766 for (i = 0; i < country_codes->table_size; i++) {
6767 cc = &country_codes->table[i];
6768 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6769 found_index = i;
6770 if ((cc->iso3166[0] == alpha2[0]) &&
6771 (cc->iso3166[1] == alpha2[1])) {
6772 found_index = i;
6773 break;
6774 }
6775 }
6776 if (found_index == -1) {
6777 brcmf_dbg(TRACE, "No country code match found\n");
6778 return -EINVAL;
6779 }
6780 memset(ccreq, 0, sizeof(*ccreq));
6781 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6782 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6783 BRCMF_COUNTRY_BUF_SZ);
6784 ccreq->country_abbrev[0] = alpha2[0];
6785 ccreq->country_abbrev[1] = alpha2[1];
6786 ccreq->country_abbrev[2] = 0;
6787
6788 return 0;
6789}
6790
Arend van Spriel63db1a42014-12-21 12:43:51 +01006791static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6792 struct regulatory_request *req)
6793{
6794 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6795 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6796 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006797 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006798 int i;
6799
Hans de Goede26e537882017-03-08 14:50:16 +01006800 /* The country code gets set to "00" by default at boot, ignore */
6801 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6802 return;
6803
Arend van Spriel63db1a42014-12-21 12:43:51 +01006804 /* ignore non-ISO3166 country codes */
Stefan Wahren9b9322d2018-03-14 20:02:59 +01006805 for (i = 0; i < 2; i++)
Arend van Spriel63db1a42014-12-21 12:43:51 +01006806 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Martin Michlmayra9507d52017-06-10 11:40:04 +02006807 brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
Hante Meuleman73345fd2016-02-17 11:26:53 +01006808 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006809 return;
6810 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006811
6812 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6813 req->alpha2[0], req->alpha2[1]);
6814
6815 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6816 if (err) {
6817 brcmf_err("Country code iovar returned err = %d\n", err);
6818 return;
6819 }
6820
6821 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6822 if (err)
6823 return;
6824
6825 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6826 if (err) {
6827 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006828 return;
6829 }
6830 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006831}
6832
Arend van Sprielb48d8912014-07-12 08:49:41 +02006833static void brcmf_free_wiphy(struct wiphy *wiphy)
6834{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006835 int i;
6836
Arend van Spriel58de92d2015-04-14 20:10:24 +02006837 if (!wiphy)
6838 return;
6839
Arend van Spriel0882dda2015-08-20 22:06:03 +02006840 if (wiphy->iface_combinations) {
6841 for (i = 0; i < wiphy->n_iface_combinations; i++)
6842 kfree(wiphy->iface_combinations[i].limits);
6843 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006844 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006845 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6846 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6847 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006848 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006849 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6850 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6851 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006852 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006853#if IS_ENABLED(CONFIG_PM)
6854 if (wiphy->wowlan != &brcmf_wowlan_support)
6855 kfree(wiphy->wowlan);
6856#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006857 wiphy_free(wiphy);
6858}
6859
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006860struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006861 struct device *busdev,
6862 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006863{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006864 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006865 struct brcmf_cfg80211_info *cfg;
6866 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006867 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006868 struct brcmf_cfg80211_vif *vif;
6869 struct brcmf_if *ifp;
6870 s32 err = 0;
6871 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006872 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006873
6874 if (!ndev) {
6875 brcmf_err("ndev is invalid\n");
6876 return NULL;
6877 }
6878
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306879 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006880 if (!ops)
6881 return NULL;
6882
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006883 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006884#ifdef CONFIG_PM
6885 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6886 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6887#endif
6888 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006889 if (!wiphy) {
6890 brcmf_err("Could not allocate wiphy device\n");
Christophe Jaillet57c00f22017-06-21 07:45:53 +02006891 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006892 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006893 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006894 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006895
6896 cfg = wiphy_priv(wiphy);
6897 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006898 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006899 cfg->pub = drvr;
6900 init_vif_event(&cfg->vif_event);
6901 INIT_LIST_HEAD(&cfg->vif_list);
6902
Rafał Miłecki26072332016-06-06 23:03:55 +02006903 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006904 if (IS_ERR(vif))
6905 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006906
6907 vif->ifp = ifp;
6908 vif->wdev.netdev = ndev;
6909 ndev->ieee80211_ptr = &vif->wdev;
6910 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6911
6912 err = wl_init_priv(cfg);
6913 if (err) {
6914 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006915 brcmf_free_vif(vif);
6916 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006917 }
6918 ifp->vif = vif;
6919
Arend van Sprielb48d8912014-07-12 08:49:41 +02006920 /* determine d11 io type before wiphy setup */
6921 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006922 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006923 brcmf_err("Failed to get D11 version (%d)\n", err);
6924 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006925 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006926 cfg->d11inf.io_type = (u8)io_type;
6927 brcmu_d11_attach(&cfg->d11inf);
6928
6929 err = brcmf_setup_wiphy(wiphy, ifp);
6930 if (err < 0)
6931 goto priv_out;
6932
6933 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006934 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006935 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6936 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6937
6938 /* firmware defaults to 40MHz disabled in 2G band. We signal
6939 * cfg80211 here that we do and have it decide we can enable
6940 * it. But first check if device does support 2G operation.
6941 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006942 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6943 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006944 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6945 }
6946 err = wiphy_register(wiphy);
6947 if (err < 0) {
6948 brcmf_err("Could not register wiphy device (%d)\n", err);
6949 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006950 }
6951
Rafał Miłeckiab990632017-01-07 21:36:05 +01006952 err = brcmf_setup_wiphybands(wiphy);
6953 if (err) {
6954 brcmf_err("Setting wiphy bands failed (%d)\n", err);
6955 goto wiphy_unreg_out;
6956 }
6957
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006958 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6959 * setup 40MHz in 2GHz band and enable OBSS scanning.
6960 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006961 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6962 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006963 if (!err)
6964 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6965 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006966 else
6967 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006968 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006969 /* p2p might require that "if-events" get processed by fweh. So
6970 * activate the already registered event handlers now and activate
6971 * the rest when initialization has completed. drvr->config needs to
6972 * be assigned before activating events.
6973 */
6974 drvr->config = cfg;
6975 err = brcmf_fweh_activate_events(ifp);
6976 if (err) {
6977 brcmf_err("FWEH activation failed (%d)\n", err);
6978 goto wiphy_unreg_out;
6979 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006980
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006981 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006982 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006983 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006984 goto wiphy_unreg_out;
6985 }
6986 err = brcmf_btcoex_attach(cfg);
6987 if (err) {
6988 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6989 brcmf_p2p_detach(&cfg->p2p);
6990 goto wiphy_unreg_out;
6991 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01006992 err = brcmf_pno_attach(cfg);
6993 if (err) {
6994 brcmf_err("PNO initialisation failed (%d)\n", err);
6995 brcmf_btcoex_detach(cfg);
6996 brcmf_p2p_detach(&cfg->p2p);
6997 goto wiphy_unreg_out;
6998 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006999
Hante Meulemana7b82d42015-12-10 13:43:04 +01007000 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
7001 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
7002 if (err) {
7003 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
7004 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
7005 } else {
7006 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
7007 brcmf_notify_tdls_peer_event);
7008 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007009 }
7010
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007011 /* (re-) activate FWEH event handling */
7012 err = brcmf_fweh_activate_events(ifp);
7013 if (err) {
7014 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007015 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007016 }
7017
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007018 /* Fill in some of the advertised nl80211 supported features */
7019 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7020 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7021#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007022 if (wiphy->wowlan &&
7023 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007024 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7025#endif
7026 }
7027
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007028 return cfg;
7029
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007030detach:
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007031 brcmf_pno_detach(cfg);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007032 brcmf_btcoex_detach(cfg);
7033 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007034wiphy_unreg_out:
7035 wiphy_unregister(cfg->wiphy);
7036priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007037 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007038 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007039 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007040wiphy_out:
7041 brcmf_free_wiphy(wiphy);
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007042ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007043 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007044 return NULL;
7045}
7046
7047void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7048{
7049 if (!cfg)
7050 return;
7051
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007052 brcmf_pno_detach(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007053 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007054 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007055 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007056 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007057 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007058}