blob: 1283798f0b860f41f8e65155121a41897b4cc44e [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 Meuleman81f5dcb2012-10-22 10:36:14 -07001046 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001047 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001048 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001049
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001050 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001051 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001052 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001053 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001054 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001055 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001056 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001057 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001058 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001059 return err;
1060 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001061 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001062 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001063 results->version = 0;
1064 results->count = 0;
1065 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1066
Hante Meulemanc4958102015-11-25 11:32:41 +01001067 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001068 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001069 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001070 return err;
1071}
1072
1073static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001074brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001075 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001076{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001077 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001078 s32 err;
Hante Meulemane756af52012-09-11 21:18:52 +02001079
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001080 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001081
Arend van Sprielc1179032012-10-22 13:55:33 -07001082 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001083 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001084 return -EAGAIN;
1085 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001086 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001087 brcmf_err("Scanning being aborted: status (%lu)\n",
1088 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001089 return -EAGAIN;
1090 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001091 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1092 brcmf_err("Scanning suppressed: status (%lu)\n",
1093 cfg->scan_status);
1094 return -EAGAIN;
1095 }
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001096 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
1097 brcmf_err("Connecting: status (%lu)\n", vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001098 return -EAGAIN;
1099 }
1100
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001101 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001102 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1103 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001104
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001105 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001106 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001107
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001108 cfg->escan_info.run = brcmf_run_escan;
1109 err = brcmf_p2p_scan_prep(wiphy, request, vif);
1110 if (err)
1111 goto scan_out;
Hante Meulemane756af52012-09-11 21:18:52 +02001112
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001113 err = brcmf_do_escan(vif->ifp, request);
1114 if (err)
1115 goto scan_out;
Hante Meulemane756af52012-09-11 21:18:52 +02001116
Hante Meuleman661fa952015-02-06 18:36:47 +01001117 /* Arm scan timeout timer */
1118 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001119 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001120
Hante Meulemane756af52012-09-11 21:18:52 +02001121 return 0;
1122
1123scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001124 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001125 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001126 return err;
1127}
1128
Arend van Spriel5b435de2011-10-05 13:19:03 +02001129static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001130brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001131{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001132 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133 s32 err = 0;
1134
Arend van Sprield96b8012012-12-05 15:26:02 +01001135 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001136 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1137 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138 return -EIO;
1139
Arend Van Spriel8c6efda2017-11-08 14:36:33 +01001140 err = brcmf_cfg80211_escan(wiphy, vif, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001141
Arend van Spriel5b435de2011-10-05 13:19:03 +02001142 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001143 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001144
Arend van Sprield96b8012012-12-05 15:26:02 +01001145 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001146 return err;
1147}
1148
1149static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1150{
1151 s32 err = 0;
1152
Arend van Sprielac24be62012-10-22 10:36:23 -07001153 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1154 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001155 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001156 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001157
1158 return err;
1159}
1160
1161static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1162{
1163 s32 err = 0;
1164
Arend van Sprielac24be62012-10-22 10:36:23 -07001165 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1166 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001167 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001168 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001169
1170 return err;
1171}
1172
1173static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1174{
1175 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001176 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001177
Arend van Sprielac24be62012-10-22 10:36:23 -07001178 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001180 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001181 return err;
1182 }
1183 return err;
1184}
1185
1186static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1187{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001188 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1189 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001190 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001191 s32 err = 0;
1192
Arend van Sprield96b8012012-12-05 15:26:02 +01001193 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001194 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001195 return -EIO;
1196
1197 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001198 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1199 cfg->conf->rts_threshold = wiphy->rts_threshold;
1200 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001201 if (!err)
1202 goto done;
1203 }
1204 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001205 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1206 cfg->conf->frag_threshold = wiphy->frag_threshold;
1207 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001208 if (!err)
1209 goto done;
1210 }
1211 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001212 && (cfg->conf->retry_long != wiphy->retry_long)) {
1213 cfg->conf->retry_long = wiphy->retry_long;
1214 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001215 if (!err)
1216 goto done;
1217 }
1218 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001219 && (cfg->conf->retry_short != wiphy->retry_short)) {
1220 cfg->conf->retry_short = wiphy->retry_short;
1221 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222 if (!err)
1223 goto done;
1224 }
1225
1226done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001227 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001228 return err;
1229}
1230
Arend van Spriel5b435de2011-10-05 13:19:03 +02001231static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1232{
1233 memset(prof, 0, sizeof(*prof));
1234}
1235
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001236static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1237{
1238 u16 reason;
1239
1240 switch (e->event_code) {
1241 case BRCMF_E_DEAUTH:
1242 case BRCMF_E_DEAUTH_IND:
1243 case BRCMF_E_DISASSOC_IND:
1244 reason = e->reason;
1245 break;
1246 case BRCMF_E_LINK:
1247 default:
1248 reason = 0;
1249 break;
1250 }
1251 return reason;
1252}
1253
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001254static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
1255{
1256 struct brcmf_wsec_pmk_le pmk;
1257 int i, err;
1258
1259 /* convert to firmware key format */
1260 pmk.key_len = cpu_to_le16(pmk_len << 1);
1261 pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
1262 for (i = 0; i < pmk_len; i++)
1263 snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
1264
1265 /* store psk in firmware */
1266 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
1267 &pmk, sizeof(pmk));
1268 if (err < 0)
1269 brcmf_err("failed to change PSK in firmware (len=%u)\n",
1270 pmk_len);
1271
1272 return err;
1273}
1274
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001275static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001276{
Piotr Haber61730d42013-04-23 12:53:12 +02001277 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001278 s32 err = 0;
1279
Arend van Sprield96b8012012-12-05 15:26:02 +01001280 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001281
Hante Meulemanb0a79082015-12-10 13:43:07 +01001282 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001283 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001284 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001285 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001286 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001287 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001288 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001289 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1290 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1291 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1292 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001293 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001294 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001295 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1296 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001297 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
1298 brcmf_set_pmk(vif->ifp, NULL, 0);
1299 vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1300 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001301 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001302}
1303
1304static s32
1305brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1306 struct cfg80211_ibss_params *params)
1307{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001308 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001309 struct brcmf_if *ifp = netdev_priv(ndev);
1310 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001311 struct brcmf_join_params join_params;
1312 size_t join_params_size = 0;
1313 s32 err = 0;
1314 s32 wsec = 0;
1315 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001316 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001317 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318
Arend van Sprield96b8012012-12-05 15:26:02 +01001319 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001320 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 return -EIO;
1322
1323 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001324 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001325 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001326 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001327 return -EOPNOTSUPP;
1328 }
1329
Arend van Sprielc1179032012-10-22 13:55:33 -07001330 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001331
1332 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001333 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334 else
Arend van Spriel16886732012-12-05 15:26:04 +01001335 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001336
Johannes Berg683b6d32012-11-08 21:25:48 +01001337 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001338 brcmf_dbg(CONN, "channel: %d\n",
1339 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001340 else
Arend van Spriel16886732012-12-05 15:26:04 +01001341 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001342
1343 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001344 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001345 else
Arend van Spriel16886732012-12-05 15:26:04 +01001346 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001347
1348 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001349 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350 else
Arend van Spriel16886732012-12-05 15:26:04 +01001351 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001352
1353 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001354 brcmf_dbg(CONN, "beacon interval: %d\n",
1355 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001356 else
Arend van Spriel16886732012-12-05 15:26:04 +01001357 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001358
1359 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001360 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001361 else
Arend van Spriel16886732012-12-05 15:26:04 +01001362 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001363
1364 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001365 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001366 else
Arend van Spriel16886732012-12-05 15:26:04 +01001367 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001368
1369 /* Configure Privacy for starter */
1370 if (params->privacy)
1371 wsec |= WEP_ENABLED;
1372
Arend van Sprielc1179032012-10-22 13:55:33 -07001373 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001374 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001375 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001376 goto done;
1377 }
1378
1379 /* Configure Beacon Interval for starter */
1380 if (params->beacon_interval)
1381 bcnprd = params->beacon_interval;
1382 else
1383 bcnprd = 100;
1384
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001385 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001386 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001387 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001388 goto done;
1389 }
1390
1391 /* Configure required join parameter */
1392 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1393
1394 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001395 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1396 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1397 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001398 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399
1400 /* BSSID */
1401 if (params->bssid) {
1402 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001403 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001404 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001405 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001406 eth_broadcast_addr(join_params.params_le.bssid);
1407 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 }
1409
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001411 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001412 u32 target_channel;
1413
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001414 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001416 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 if (params->channel_fixed) {
1418 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001419 chanspec = chandef_to_chanspec(&cfg->d11inf,
1420 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001421 join_params.params_le.chanspec_list[0] =
1422 cpu_to_le16(chanspec);
1423 join_params.params_le.chanspec_num = cpu_to_le32(1);
1424 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001425 }
1426
1427 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001428 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001429 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001430 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001432 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 goto done;
1434 }
1435 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001436 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001437
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001438 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001439
1440
Arend van Sprielc1179032012-10-22 13:55:33 -07001441 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001442 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001443 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001444 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001445 goto done;
1446 }
1447
1448done:
1449 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001450 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001451 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 return err;
1453}
1454
1455static s32
1456brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1457{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001458 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001459
Arend van Sprield96b8012012-12-05 15:26:02 +01001460 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001461 if (!check_vif_up(ifp->vif)) {
1462 /* When driver is being unloaded, it can end up here. If an
1463 * error is returned then later on a debug trace in the wireless
1464 * core module will be printed. To avoid this 0 is returned.
1465 */
1466 return 0;
1467 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001468
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001469 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001470 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471
Arend van Sprield96b8012012-12-05 15:26:02 +01001472 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001474 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001475}
1476
1477static s32 brcmf_set_wpa_version(struct net_device *ndev,
1478 struct cfg80211_connect_params *sme)
1479{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001480 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001481 struct brcmf_cfg80211_security *sec;
1482 s32 val = 0;
1483 s32 err = 0;
1484
1485 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1486 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1487 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1488 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1489 else
1490 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001491 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001492 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001493 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001494 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 return err;
1496 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001497 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001498 sec->wpa_versions = sme->crypto.wpa_versions;
1499 return err;
1500}
1501
1502static s32 brcmf_set_auth_type(struct net_device *ndev,
1503 struct cfg80211_connect_params *sme)
1504{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001505 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001506 struct brcmf_cfg80211_security *sec;
1507 s32 val = 0;
1508 s32 err = 0;
1509
1510 switch (sme->auth_type) {
1511 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1512 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001513 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001514 break;
1515 case NL80211_AUTHTYPE_SHARED_KEY:
1516 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001517 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001519 default:
1520 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001521 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001522 break;
1523 }
1524
Hante Meuleman89286dc2013-02-08 15:53:46 +01001525 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001526 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001527 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001528 return err;
1529 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001530 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531 sec->auth_type = sme->auth_type;
1532 return err;
1533}
1534
1535static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001536brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001537 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001539 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540 struct brcmf_cfg80211_security *sec;
1541 s32 pval = 0;
1542 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001543 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001544 s32 err = 0;
1545
1546 if (sme->crypto.n_ciphers_pairwise) {
1547 switch (sme->crypto.ciphers_pairwise[0]) {
1548 case WLAN_CIPHER_SUITE_WEP40:
1549 case WLAN_CIPHER_SUITE_WEP104:
1550 pval = WEP_ENABLED;
1551 break;
1552 case WLAN_CIPHER_SUITE_TKIP:
1553 pval = TKIP_ENABLED;
1554 break;
1555 case WLAN_CIPHER_SUITE_CCMP:
1556 pval = AES_ENABLED;
1557 break;
1558 case WLAN_CIPHER_SUITE_AES_CMAC:
1559 pval = AES_ENABLED;
1560 break;
1561 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001562 brcmf_err("invalid cipher pairwise (%d)\n",
1563 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001564 return -EINVAL;
1565 }
1566 }
1567 if (sme->crypto.cipher_group) {
1568 switch (sme->crypto.cipher_group) {
1569 case WLAN_CIPHER_SUITE_WEP40:
1570 case WLAN_CIPHER_SUITE_WEP104:
1571 gval = WEP_ENABLED;
1572 break;
1573 case WLAN_CIPHER_SUITE_TKIP:
1574 gval = TKIP_ENABLED;
1575 break;
1576 case WLAN_CIPHER_SUITE_CCMP:
1577 gval = AES_ENABLED;
1578 break;
1579 case WLAN_CIPHER_SUITE_AES_CMAC:
1580 gval = AES_ENABLED;
1581 break;
1582 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001583 brcmf_err("invalid cipher group (%d)\n",
1584 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001585 return -EINVAL;
1586 }
1587 }
1588
Arend van Spriel16886732012-12-05 15:26:04 +01001589 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001590 /* In case of privacy, but no security and WPS then simulate */
1591 /* setting AES. WPS-2.0 allows no security */
1592 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1593 sme->privacy)
1594 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001595
Hante Meuleman240d61a2016-02-17 11:27:10 +01001596 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001597 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001598 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001599 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001600 return err;
1601 }
1602
Arend van Spriel06bb1232012-09-27 14:17:56 +02001603 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001604 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1605 sec->cipher_group = sme->crypto.cipher_group;
1606
1607 return err;
1608}
1609
1610static s32
1611brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1612{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001613 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001614 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001615 s32 val;
1616 s32 err;
1617 const struct brcmf_tlv *rsn_ie;
1618 const u8 *ie;
1619 u32 ie_len;
1620 u32 offset;
1621 u16 rsn_cap;
1622 u32 mfp;
1623 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624
Arend van Spriel2526ff22017-06-09 13:08:48 +01001625 profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1626
Hante Meuleman240d61a2016-02-17 11:27:10 +01001627 if (!sme->crypto.n_akm_suites)
1628 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629
Hante Meuleman240d61a2016-02-17 11:27:10 +01001630 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1631 if (err) {
1632 brcmf_err("could not get wpa_auth (%d)\n", err);
1633 return err;
1634 }
1635 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1636 switch (sme->crypto.akm_suites[0]) {
1637 case WLAN_AKM_SUITE_8021X:
1638 val = WPA_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001639 if (sme->want_1x)
1640 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001641 break;
1642 case WLAN_AKM_SUITE_PSK:
1643 val = WPA_AUTH_PSK;
1644 break;
1645 default:
1646 brcmf_err("invalid cipher group (%d)\n",
1647 sme->crypto.cipher_group);
1648 return -EINVAL;
1649 }
1650 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1651 switch (sme->crypto.akm_suites[0]) {
1652 case WLAN_AKM_SUITE_8021X:
1653 val = WPA2_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001654 if (sme->want_1x)
1655 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001656 break;
1657 case WLAN_AKM_SUITE_8021X_SHA256:
1658 val = WPA2_AUTH_1X_SHA256;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001659 if (sme->want_1x)
1660 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001661 break;
1662 case WLAN_AKM_SUITE_PSK_SHA256:
1663 val = WPA2_AUTH_PSK_SHA256;
1664 break;
1665 case WLAN_AKM_SUITE_PSK:
1666 val = WPA2_AUTH_PSK;
1667 break;
1668 default:
1669 brcmf_err("invalid cipher group (%d)\n",
1670 sme->crypto.cipher_group);
1671 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672 }
1673 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001674
Arend van Spriel2526ff22017-06-09 13:08:48 +01001675 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
1676 brcmf_dbg(INFO, "using 1X offload\n");
1677
Hante Meuleman240d61a2016-02-17 11:27:10 +01001678 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1679 goto skip_mfp_config;
1680 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1681 * IE will not be verified, just a quick search for MFP config
1682 */
1683 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1684 WLAN_EID_RSN);
1685 if (!rsn_ie)
1686 goto skip_mfp_config;
1687 ie = (const u8 *)rsn_ie;
1688 ie_len = rsn_ie->len + TLV_HDR_LEN;
1689 /* Skip unicast suite */
1690 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1691 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1692 goto skip_mfp_config;
1693 /* Skip multicast suite */
1694 count = ie[offset] + (ie[offset + 1] << 8);
1695 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1696 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1697 goto skip_mfp_config;
1698 /* Skip auth key management suite(s) */
1699 count = ie[offset] + (ie[offset + 1] << 8);
1700 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1701 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1702 goto skip_mfp_config;
1703 /* Ready to read capabilities */
1704 mfp = BRCMF_MFP_NONE;
1705 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1706 if (rsn_cap & RSN_CAP_MFPR_MASK)
1707 mfp = BRCMF_MFP_REQUIRED;
1708 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1709 mfp = BRCMF_MFP_CAPABLE;
1710 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1711
1712skip_mfp_config:
1713 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1714 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1715 if (err) {
1716 brcmf_err("could not set wpa_auth (%d)\n", err);
1717 return err;
1718 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001719
1720 return err;
1721}
1722
1723static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001724brcmf_set_sharedkey(struct net_device *ndev,
1725 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001726{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001727 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001728 struct brcmf_cfg80211_security *sec;
1729 struct brcmf_wsec_key key;
1730 s32 val;
1731 s32 err = 0;
1732
Arend van Spriel16886732012-12-05 15:26:04 +01001733 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001734
Roland Vossena718e2f2011-10-12 20:51:24 +02001735 if (sme->key_len == 0)
1736 return 0;
1737
Arend van Spriel06bb1232012-09-27 14:17:56 +02001738 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001739 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1740 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001741
1742 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1743 return 0;
1744
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001745 if (!(sec->cipher_pairwise &
1746 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1747 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001748
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001749 memset(&key, 0, sizeof(key));
1750 key.len = (u32) sme->key_len;
1751 key.index = (u32) sme->key_idx;
1752 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001753 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001754 return -EINVAL;
1755 }
1756 memcpy(key.data, sme->key, key.len);
1757 key.flags = BRCMF_PRIMARY_KEY;
1758 switch (sec->cipher_pairwise) {
1759 case WLAN_CIPHER_SUITE_WEP40:
1760 key.algo = CRYPTO_ALGO_WEP1;
1761 break;
1762 case WLAN_CIPHER_SUITE_WEP104:
1763 key.algo = CRYPTO_ALGO_WEP128;
1764 break;
1765 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001766 brcmf_err("Invalid algorithm (%d)\n",
1767 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001768 return -EINVAL;
1769 }
1770 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001771 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1772 key.len, key.index, key.algo);
1773 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001774 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001775 if (err)
1776 return err;
1777
1778 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001779 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001780 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001781 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001782 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001783 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001784 }
1785 return err;
1786}
1787
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001788static
1789enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1790 enum nl80211_auth_type type)
1791{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001792 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1793 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1794 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1795 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001796 }
1797 return type;
1798}
1799
Arend van Spriel7705ba62016-04-17 16:44:58 +02001800static void brcmf_set_join_pref(struct brcmf_if *ifp,
1801 struct cfg80211_bss_selection *bss_select)
1802{
1803 struct brcmf_join_pref_params join_pref_params[2];
1804 enum nl80211_band band;
1805 int err, i = 0;
1806
1807 join_pref_params[i].len = 2;
1808 join_pref_params[i].rssi_gain = 0;
1809
1810 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1811 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1812
1813 switch (bss_select->behaviour) {
1814 case __NL80211_BSS_SELECT_ATTR_INVALID:
1815 brcmf_c_set_joinpref_default(ifp);
1816 return;
1817 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1818 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1819 band = bss_select->param.band_pref;
1820 join_pref_params[i].band = nl80211_band_to_fwil(band);
1821 i++;
1822 break;
1823 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1824 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1825 band = bss_select->param.adjust.band;
1826 join_pref_params[i].band = nl80211_band_to_fwil(band);
1827 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1828 i++;
1829 break;
1830 case NL80211_BSS_SELECT_ATTR_RSSI:
1831 default:
1832 break;
1833 }
1834 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1835 join_pref_params[i].len = 2;
1836 join_pref_params[i].rssi_gain = 0;
1837 join_pref_params[i].band = 0;
1838 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1839 sizeof(join_pref_params));
1840 if (err)
1841 brcmf_err("Set join_pref error (%d)\n", err);
1842}
1843
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844static s32
1845brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001846 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001847{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001848 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001849 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001850 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001851 struct ieee80211_channel *chan = sme->channel;
1852 struct brcmf_join_params join_params;
1853 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001854 const struct brcmf_tlv *rsn_ie;
1855 const struct brcmf_vs_tlv *wpa_ie;
1856 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001857 u32 ie_len;
1858 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001859 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001860 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001861 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001862
Arend van Sprield96b8012012-12-05 15:26:02 +01001863 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001864 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001865 return -EIO;
1866
1867 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001868 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001869 return -EOPNOTSUPP;
1870 }
1871
Hante Meuleman89286dc2013-02-08 15:53:46 +01001872 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1873 /* A normal (non P2P) connection request setup. */
1874 ie = NULL;
1875 ie_len = 0;
1876 /* find the WPA_IE */
1877 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1878 if (wpa_ie) {
1879 ie = wpa_ie;
1880 ie_len = wpa_ie->len + TLV_HDR_LEN;
1881 } else {
1882 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001883 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1884 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001885 WLAN_EID_RSN);
1886 if (rsn_ie) {
1887 ie = rsn_ie;
1888 ie_len = rsn_ie->len + TLV_HDR_LEN;
1889 }
1890 }
1891 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1892 }
1893
1894 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1895 sme->ie, sme->ie_len);
1896 if (err)
1897 brcmf_err("Set Assoc REQ IE Failed\n");
1898 else
1899 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1900
Arend van Sprielc1179032012-10-22 13:55:33 -07001901 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001902
1903 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001904 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001905 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001906 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001907 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1908 cfg->channel, chan->center_freq, chanspec);
1909 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001910 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001911 chanspec = 0;
1912 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001913
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001914 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001915
1916 err = brcmf_set_wpa_version(ndev, sme);
1917 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001918 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001919 goto done;
1920 }
1921
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001922 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001923 err = brcmf_set_auth_type(ndev, sme);
1924 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001925 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001926 goto done;
1927 }
1928
Hante Meuleman240d61a2016-02-17 11:27:10 +01001929 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001930 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001931 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001932 goto done;
1933 }
1934
1935 err = brcmf_set_key_mgmt(ndev, sme);
1936 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001937 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001938 goto done;
1939 }
1940
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001941 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001942 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001943 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001944 goto done;
1945 }
1946
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001947 if (sme->crypto.psk) {
Arend van Spriel2526ff22017-06-09 13:08:48 +01001948 if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
1949 err = -EINVAL;
1950 goto done;
1951 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001952 brcmf_dbg(INFO, "using PSK offload\n");
Arend van Spriel2526ff22017-06-09 13:08:48 +01001953 profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
1954 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001955
Arend van Spriel2526ff22017-06-09 13:08:48 +01001956 if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001957 /* enable firmware supplicant for this interface */
1958 err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
1959 if (err < 0) {
1960 brcmf_err("failed to enable fw supplicant\n");
1961 goto done;
1962 }
Arend van Spriel2526ff22017-06-09 13:08:48 +01001963 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001964
Arend van Spriel2526ff22017-06-09 13:08:48 +01001965 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001966 err = brcmf_set_pmk(ifp, sme->crypto.psk,
1967 BRCMF_WSEC_MAX_PSK_LEN);
1968 if (err)
1969 goto done;
1970 }
1971
Hante Meuleman89286dc2013-02-08 15:53:46 +01001972 /* Join with specific BSSID and cached SSID
1973 * If SSID is zero join based on BSSID only
1974 */
1975 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1976 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1977 if (cfg->channel)
1978 join_params_size += sizeof(u16);
1979 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1980 if (ext_join_params == NULL) {
1981 err = -ENOMEM;
1982 goto done;
1983 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001984 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1985 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1986 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1987 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1988 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1989 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001990
Hante Meuleman89286dc2013-02-08 15:53:46 +01001991 /* Set up join scan parameters */
1992 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001993 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1994
1995 if (sme->bssid)
1996 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1997 else
Joe Perches93803b32015-03-02 19:54:49 -08001998 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001999
2000 if (cfg->channel) {
2001 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2002
2003 ext_join_params->assoc_le.chanspec_list[0] =
2004 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002005 /* Increase dwell time to receive probe response or detect
2006 * beacon from target AP at a noisy air only during connect
2007 * command.
2008 */
2009 ext_join_params->scan_le.active_time =
2010 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2011 ext_join_params->scan_le.passive_time =
2012 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2013 /* To sync with presence period of VSDB GO send probe request
2014 * more frequently. Probe request will be stopped when it gets
2015 * probe response from target AP/GO.
2016 */
2017 ext_join_params->scan_le.nprobes =
2018 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2019 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2020 } else {
2021 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2022 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2023 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002024 }
2025
Arend van Spriel7705ba62016-04-17 16:44:58 +02002026 brcmf_set_join_pref(ifp, &sme->bss_select);
2027
Hante Meuleman89286dc2013-02-08 15:53:46 +01002028 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2029 join_params_size);
2030 kfree(ext_join_params);
2031 if (!err)
2032 /* This is it. join command worked, we are done */
2033 goto done;
2034
2035 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002036 memset(&join_params, 0, sizeof(join_params));
2037 join_params_size = sizeof(join_params.ssid_le);
2038
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002039 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2040 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002041
Hante Meuleman89286dc2013-02-08 15:53:46 +01002042 if (sme->bssid)
2043 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2044 else
Joe Perches93803b32015-03-02 19:54:49 -08002045 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046
Hante Meuleman17012612013-02-06 18:40:44 +01002047 if (cfg->channel) {
2048 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2049 join_params.params_le.chanspec_num = cpu_to_le32(1);
2050 join_params_size += sizeof(join_params.params_le);
2051 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002052 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002053 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002055 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056
2057done:
2058 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002059 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002060 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002061 return err;
2062}
2063
2064static s32
2065brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2066 u16 reason_code)
2067{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002068 struct brcmf_if *ifp = netdev_priv(ndev);
2069 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002070 struct brcmf_scb_val_le scbval;
2071 s32 err = 0;
2072
Arend van Sprield96b8012012-12-05 15:26:02 +01002073 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002074 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002075 return -EIO;
2076
Arend van Sprielc1179032012-10-22 13:55:33 -07002077 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002078 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002079 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080
Arend van Spriel06bb1232012-09-27 14:17:56 +02002081 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002082 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002083 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002084 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002085 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002086 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002087
Arend van Sprield96b8012012-12-05 15:26:02 +01002088 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 return err;
2090}
2091
2092static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002093brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002094 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002096 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002097 struct net_device *ndev = cfg_to_ndev(cfg);
2098 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002099 s32 err;
2100 s32 disable;
2101 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002102
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002103 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002104 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105 return -EIO;
2106
2107 switch (type) {
2108 case NL80211_TX_POWER_AUTOMATIC:
2109 break;
2110 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002111 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002112 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002113 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114 err = -EINVAL;
2115 goto done;
2116 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002117 qdbm = MBM_TO_DBM(4 * mbm);
2118 if (qdbm > 127)
2119 qdbm = 127;
2120 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002121 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002122 default:
2123 brcmf_err("Unsupported type %d\n", type);
2124 err = -EINVAL;
2125 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002126 }
2127 /* Make sure radio is off or on as far as software is concerned */
2128 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002129 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002130 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002131 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002133 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002134 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002135 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136
2137done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002138 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 return err;
2140}
2141
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002142static s32
2143brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2144 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002145{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002146 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002147 struct net_device *ndev = cfg_to_ndev(cfg);
2148 struct brcmf_if *ifp = netdev_priv(ndev);
2149 s32 qdbm = 0;
2150 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151
Arend van Sprield96b8012012-12-05 15:26:02 +01002152 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002153 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002154 return -EIO;
2155
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002156 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002158 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002159 goto done;
2160 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002161 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
2163done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002164 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002165 return err;
2166}
2167
2168static s32
2169brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002170 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002171{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002172 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173 u32 index;
2174 u32 wsec;
2175 s32 err = 0;
2176
Arend van Sprield96b8012012-12-05 15:26:02 +01002177 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002178 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002179 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002180 return -EIO;
2181
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002182 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002183 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002184 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002185 goto done;
2186 }
2187
2188 if (wsec & WEP_ENABLED) {
2189 /* Just select a new current key */
2190 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002191 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002192 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002193 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002194 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 }
2196done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002197 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002198 return err;
2199}
2200
2201static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002202brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2203 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002204{
Hante Meuleman992f6062013-04-02 21:06:17 +02002205 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002206 struct brcmf_wsec_key *key;
2207 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002208
2209 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002210 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2211
Hante Meuleman219e0f72016-02-17 11:27:09 +01002212 if (!check_vif_up(ifp->vif))
2213 return -EIO;
2214
2215 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2216 /* we ignore this key index in this case */
2217 return -EINVAL;
2218 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002219
Hante Meuleman240d61a2016-02-17 11:27:10 +01002220 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002221
Hante Meuleman240d61a2016-02-17 11:27:10 +01002222 if (key->algo == CRYPTO_ALGO_OFF) {
2223 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2224 return -EINVAL;
2225 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002226
Hante Meuleman240d61a2016-02-17 11:27:10 +01002227 memset(key, 0, sizeof(*key));
2228 key->index = (u32)key_idx;
2229 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002230
Hante Meuleman240d61a2016-02-17 11:27:10 +01002231 /* Clear the key/index */
2232 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002233
Hante Meuleman219e0f72016-02-17 11:27:09 +01002234 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002235 return err;
2236}
2237
2238static s32
2239brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002240 u8 key_idx, bool pairwise, const u8 *mac_addr,
2241 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002242{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002243 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002244 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 s32 val;
2246 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002247 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002248 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002249 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002250
Arend van Sprield96b8012012-12-05 15:26:02 +01002251 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002252 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002253 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002254 return -EIO;
2255
Hante Meuleman118eb302014-12-21 12:43:49 +01002256 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2257 /* we ignore this key index in this case */
2258 brcmf_err("invalid key index (%d)\n", key_idx);
2259 return -EINVAL;
2260 }
2261
Hante Meuleman219e0f72016-02-17 11:27:09 +01002262 if (params->key_len == 0)
2263 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2264 mac_addr);
2265
2266 if (params->key_len > sizeof(key->data)) {
2267 brcmf_err("Too long key length (%u)\n", params->key_len);
2268 return -EINVAL;
2269 }
2270
2271 ext_key = false;
2272 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2273 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2274 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2275 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002276 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277
Hante Meuleman118eb302014-12-21 12:43:49 +01002278 key = &ifp->vif->profile.key[key_idx];
2279 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002280 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2281 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002282 key->len = params->key_len;
2283 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002284 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002285 if (!ext_key)
2286 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002287
Arend van Spriel5b435de2011-10-05 13:19:03 +02002288 switch (params->cipher) {
2289 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002290 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002291 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002292 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002293 break;
2294 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002295 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002296 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002297 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002298 break;
2299 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002300 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002301 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002302 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2303 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2304 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002305 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002306 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002307 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002308 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002309 break;
2310 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002311 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002312 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002313 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314 break;
2315 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002316 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002317 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002318 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002319 break;
2320 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002321 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322 err = -EINVAL;
2323 goto done;
2324 }
2325
Hante Meuleman118eb302014-12-21 12:43:49 +01002326 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002327 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002328 goto done;
2329
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002330 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002331 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002332 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002333 goto done;
2334 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002335 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002336 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002337 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002338 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339 goto done;
2340 }
2341
Arend van Spriel5b435de2011-10-05 13:19:03 +02002342done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002343 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344 return err;
2345}
2346
2347static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002348brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2349 bool pairwise, const u8 *mac_addr, void *cookie,
2350 void (*callback)(void *cookie,
2351 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352{
2353 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002354 struct brcmf_if *ifp = netdev_priv(ndev);
2355 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356 struct brcmf_cfg80211_security *sec;
2357 s32 wsec;
2358 s32 err = 0;
2359
Arend van Sprield96b8012012-12-05 15:26:02 +01002360 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002361 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002362 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 return -EIO;
2364
2365 memset(&params, 0, sizeof(params));
2366
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002367 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002368 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002369 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002370 /* Ignore this error, may happen during DISASSOC */
2371 err = -EAGAIN;
2372 goto done;
2373 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002374 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002375 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2377 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002378 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002379 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2380 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002381 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002383 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002384 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002385 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002386 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002387 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002388 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002389 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002390 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002391 err = -EINVAL;
2392 goto done;
2393 }
2394 callback(cookie, &params);
2395
2396done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002397 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002398 return err;
2399}
2400
2401static s32
2402brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002403 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002405 struct brcmf_if *ifp = netdev_priv(ndev);
2406
2407 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2408
2409 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2410 return 0;
2411
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002412 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002413
2414 return -EOPNOTSUPP;
2415}
2416
Hante Meuleman118eb302014-12-21 12:43:49 +01002417static void
2418brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2419{
2420 s32 err;
2421 u8 key_idx;
2422 struct brcmf_wsec_key *key;
2423 s32 wsec;
2424
2425 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2426 key = &ifp->vif->profile.key[key_idx];
2427 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2428 (key->algo == CRYPTO_ALGO_WEP128))
2429 break;
2430 }
2431 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2432 return;
2433
2434 err = send_key_to_dongle(ifp, key);
2435 if (err) {
2436 brcmf_err("Setting WEP key failed (%d)\n", err);
2437 return;
2438 }
2439 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2440 if (err) {
2441 brcmf_err("get wsec error (%d)\n", err);
2442 return;
2443 }
2444 wsec |= WEP_ENABLED;
2445 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2446 if (err)
2447 brcmf_err("set wsec error (%d)\n", err);
2448}
2449
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002450static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2451{
2452 struct nl80211_sta_flag_update *sfu;
2453
2454 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2455 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2456 sfu = &si->sta_flags;
2457 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2458 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2459 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2460 BIT(NL80211_STA_FLAG_AUTHORIZED);
2461 if (fw_sta_flags & BRCMF_STA_WME)
2462 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2463 if (fw_sta_flags & BRCMF_STA_AUTHE)
2464 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2465 if (fw_sta_flags & BRCMF_STA_ASSOC)
2466 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2467 if (fw_sta_flags & BRCMF_STA_AUTHO)
2468 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2469}
2470
2471static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2472{
2473 struct {
2474 __le32 len;
2475 struct brcmf_bss_info_le bss_le;
2476 } *buf;
2477 u16 capability;
2478 int err;
2479
2480 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2481 if (!buf)
2482 return;
2483
2484 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2485 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2486 WL_BSS_INFO_MAX);
2487 if (err) {
2488 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002489 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002490 }
2491 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2492 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2493 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2494 capability = le16_to_cpu(buf->bss_le.capability);
2495 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2496 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2497 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2498 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2499 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2500 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002501
2502out_kfree:
2503 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002504}
2505
Arend van Spriel5b435de2011-10-05 13:19:03 +02002506static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002507brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2508 struct station_info *sinfo)
2509{
2510 struct brcmf_scb_val_le scbval;
2511 struct brcmf_pktcnt_le pktcnt;
2512 s32 err;
2513 u32 rate;
2514 u32 rssi;
2515
2516 /* Get the current tx rate */
2517 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2518 if (err < 0) {
2519 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2520 return err;
2521 }
2522 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2523 sinfo->txrate.legacy = rate * 5;
2524
2525 memset(&scbval, 0, sizeof(scbval));
2526 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2527 sizeof(scbval));
2528 if (err) {
2529 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2530 return err;
2531 }
2532 rssi = le32_to_cpu(scbval.val);
2533 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2534 sinfo->signal = rssi;
2535
2536 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2537 sizeof(pktcnt));
2538 if (err) {
2539 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2540 return err;
2541 }
2542 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2543 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2544 BIT(NL80211_STA_INFO_TX_PACKETS) |
2545 BIT(NL80211_STA_INFO_TX_FAILED);
2546 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2547 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2548 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2549 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2550
2551 return 0;
2552}
2553
2554static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002555brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002556 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002557{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002558 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002559 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002560 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002561 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002562 u32 sta_flags;
2563 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002564 s32 total_rssi;
2565 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002566 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002567 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002568
Arend van Sprield96b8012012-12-05 15:26:02 +01002569 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002570 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002571 return -EIO;
2572
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002573 if (brcmf_is_ibssmode(ifp->vif))
2574 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2575
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002576 memset(&sta_info_le, 0, sizeof(sta_info_le));
2577 memcpy(&sta_info_le, mac, ETH_ALEN);
2578 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2579 &sta_info_le,
2580 sizeof(sta_info_le));
2581 is_tdls_peer = !err;
2582 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002583 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002584 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002585 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002586 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002587 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002588 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002589 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002590 }
2591 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2592 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2593 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2594 sta_flags = le32_to_cpu(sta_info_le.flags);
2595 brcmf_convert_sta_flags(sta_flags, sinfo);
2596 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2597 if (is_tdls_peer)
2598 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2599 else
2600 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2601 if (sta_flags & BRCMF_STA_ASSOC) {
2602 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2603 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2604 brcmf_fill_bss_param(ifp, sinfo);
2605 }
2606 if (sta_flags & BRCMF_STA_SCBSTATS) {
2607 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2608 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2609 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2610 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2611 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2612 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2613 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2614 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2615 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002616 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002617 sinfo->txrate.legacy =
2618 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002619 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002620 if (sinfo->rx_packets) {
2621 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002622 sinfo->rxrate.legacy =
2623 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002624 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002625 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2626 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2627 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2628 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2629 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2630 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002631 total_rssi = 0;
2632 count_rssi = 0;
2633 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2634 if (sta_info_le.rssi[i]) {
2635 sinfo->chain_signal_avg[count_rssi] =
2636 sta_info_le.rssi[i];
2637 sinfo->chain_signal[count_rssi] =
2638 sta_info_le.rssi[i];
2639 total_rssi += sta_info_le.rssi[i];
2640 count_rssi++;
2641 }
2642 }
2643 if (count_rssi) {
2644 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2645 sinfo->chains = count_rssi;
2646
2647 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2648 total_rssi /= count_rssi;
2649 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002650 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2651 &ifp->vif->sme_state)) {
2652 memset(&scb_val, 0, sizeof(scb_val));
2653 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2654 &scb_val, sizeof(scb_val));
2655 if (err) {
2656 brcmf_err("Could not get rssi (%d)\n", err);
2657 goto done;
2658 } else {
2659 rssi = le32_to_cpu(scb_val.val);
2660 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2661 sinfo->signal = rssi;
2662 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2663 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002664 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002665 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002667 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002668 return err;
2669}
2670
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002671static int
2672brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2673 int idx, u8 *mac, struct station_info *sinfo)
2674{
2675 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2676 struct brcmf_if *ifp = netdev_priv(ndev);
2677 s32 err;
2678
2679 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2680
2681 if (idx == 0) {
2682 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2683 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2684 &cfg->assoclist,
2685 sizeof(cfg->assoclist));
2686 if (err) {
2687 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2688 err);
2689 cfg->assoclist.count = 0;
2690 return -EOPNOTSUPP;
2691 }
2692 }
2693 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2694 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2695 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2696 }
2697 return -ENOENT;
2698}
2699
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700static s32
2701brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2702 bool enabled, s32 timeout)
2703{
2704 s32 pm;
2705 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002706 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002707 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002708
Arend van Sprield96b8012012-12-05 15:26:02 +01002709 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710
2711 /*
2712 * Powersave enable/disable request is coming from the
2713 * cfg80211 even before the interface is up. In that
2714 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002715 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002716 * FW later while initializing the dongle
2717 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002718 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002719 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002720
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002721 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002722 goto done;
2723 }
2724
2725 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002726 /* Do not enable the power save after assoc if it is a p2p interface */
2727 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2728 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2729 pm = PM_OFF;
2730 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002731 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002732
Arend van Sprielc1179032012-10-22 13:55:33 -07002733 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002734 if (err) {
2735 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002736 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002737 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002738 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739 }
2740done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002741 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002742 return err;
2743}
2744
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002745static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002746 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002747{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002748 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002749 struct ieee80211_channel *notify_channel;
2750 struct cfg80211_bss *bss;
2751 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002752 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002753 u16 channel;
2754 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002755 u16 notify_capability;
2756 u16 notify_interval;
2757 u8 *notify_ie;
2758 size_t notify_ielen;
2759 s32 notify_signal;
2760
2761 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002762 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002763 return 0;
2764 }
2765
Franky Lin83cf17a2013-04-11 13:28:50 +02002766 if (!bi->ctl_ch) {
2767 ch.chspec = le16_to_cpu(bi->chanspec);
2768 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002769 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002770 }
2771 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772
2773 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002774 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002775 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002776 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002777
2778 freq = ieee80211_channel_to_frequency(channel, band->band);
2779 notify_channel = ieee80211_get_channel(wiphy, freq);
2780
Arend van Spriel5b435de2011-10-05 13:19:03 +02002781 notify_capability = le16_to_cpu(bi->capability);
2782 notify_interval = le16_to_cpu(bi->beacon_period);
2783 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2784 notify_ielen = le32_to_cpu(bi->ie_length);
2785 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2786
Arend van Spriel16886732012-12-05 15:26:04 +01002787 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2788 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2789 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2790 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2791 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002793 bss = cfg80211_inform_bss(wiphy, notify_channel,
2794 CFG80211_BSS_FTYPE_UNKNOWN,
2795 (const u8 *)bi->BSSID,
2796 0, notify_capability,
2797 notify_interval, notify_ie,
2798 notify_ielen, notify_signal,
2799 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002800
Franky Line78946e2011-11-10 20:30:34 +01002801 if (!bss)
2802 return -ENOMEM;
2803
Johannes Berg5b112d32013-02-01 01:49:58 +01002804 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002805
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002806 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807}
2808
Roland Vossen6f09be02011-10-18 14:03:02 +02002809static struct brcmf_bss_info_le *
2810next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2811{
2812 if (bss == NULL)
2813 return list->bss_info_le;
2814 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2815 le32_to_cpu(bss->length));
2816}
2817
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002818static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819{
2820 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002821 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 s32 err = 0;
2823 int i;
2824
Hante Meulemanef8596e2014-09-30 10:23:13 +02002825 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002826 if (bss_list->count != 0 &&
2827 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002828 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2829 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 return -EOPNOTSUPP;
2831 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002832 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002833 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002834 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002835 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002836 if (err)
2837 break;
2838 }
2839 return err;
2840}
2841
Hante Meulemanb0a79082015-12-10 13:43:07 +01002842static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2843 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002845 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002846 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002847 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002849 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002850 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851 u8 *buf = NULL;
2852 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002853 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002854 u16 notify_capability;
2855 u16 notify_interval;
2856 u8 *notify_ie;
2857 size_t notify_ielen;
2858 s32 notify_signal;
2859
Arend van Sprield96b8012012-12-05 15:26:02 +01002860 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861
2862 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2863 if (buf == NULL) {
2864 err = -ENOMEM;
2865 goto CleanUp;
2866 }
2867
2868 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2869
Arend van Sprielac24be62012-10-22 10:36:23 -07002870 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2871 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002873 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002874 goto CleanUp;
2875 }
2876
Roland Vossend34bf642011-10-18 14:03:01 +02002877 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878
Franky Lin83cf17a2013-04-11 13:28:50 +02002879 ch.chspec = le16_to_cpu(bi->chanspec);
2880 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881
Franky Lin83cf17a2013-04-11 13:28:50 +02002882 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002883 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002884 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002885 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002886
Rafał Miłecki4712d882016-05-20 13:38:57 +02002887 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002888 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002889 notify_channel = ieee80211_get_channel(wiphy, freq);
2890
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891 notify_capability = le16_to_cpu(bi->capability);
2892 notify_interval = le16_to_cpu(bi->beacon_period);
2893 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2894 notify_ielen = le32_to_cpu(bi->ie_length);
2895 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2896
Rafał Miłecki4712d882016-05-20 13:38:57 +02002897 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002898 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2899 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2900 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002901
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002902 bss = cfg80211_inform_bss(wiphy, notify_channel,
2903 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2904 notify_capability, notify_interval,
2905 notify_ie, notify_ielen, notify_signal,
2906 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002907
Franky Line78946e2011-11-10 20:30:34 +01002908 if (!bss) {
2909 err = -ENOMEM;
2910 goto CleanUp;
2911 }
2912
Johannes Berg5b112d32013-02-01 01:49:58 +01002913 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002914
Arend van Spriel5b435de2011-10-05 13:19:03 +02002915CleanUp:
2916
2917 kfree(buf);
2918
Arend van Sprield96b8012012-12-05 15:26:02 +01002919 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002920
2921 return err;
2922}
2923
Hante Meuleman89286dc2013-02-08 15:53:46 +01002924static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2925 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002926{
Roland Vossend34bf642011-10-18 14:03:01 +02002927 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002928 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002929 u16 beacon_interval;
2930 u8 dtim_period;
2931 size_t ie_len;
2932 u8 *ie;
2933 s32 err = 0;
2934
Arend van Sprield96b8012012-12-05 15:26:02 +01002935 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002936 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002937 return err;
2938
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002939 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002940 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002941 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002942 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002943 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002944 goto update_bss_info_out;
2945 }
2946
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002947 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2948 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002949 if (err)
2950 goto update_bss_info_out;
2951
2952 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2953 ie_len = le32_to_cpu(bi->ie_length);
2954 beacon_interval = le16_to_cpu(bi->beacon_period);
2955
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002956 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002957 if (tim)
2958 dtim_period = tim->data[1];
2959 else {
2960 /*
2961 * active scan was done so we could not get dtim
2962 * information out of probe response.
2963 * so we speficially query dtim information to dongle.
2964 */
2965 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002966 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002967 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002968 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002969 goto update_bss_info_out;
2970 }
2971 dtim_period = (u8)var;
2972 }
2973
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002975 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002976 return err;
2977}
2978
Hante Meuleman18e2f612013-02-08 15:53:49 +01002979void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002980{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002981 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002982
Arend van Sprielc1179032012-10-22 13:55:33 -07002983 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01002984 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002985 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002986 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002987 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002988 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2989 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002990}
2991
Hante Meulemane756af52012-09-11 21:18:52 +02002992static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2993{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002994 struct brcmf_cfg80211_info *cfg =
2995 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002996 escan_timeout_work);
2997
Hante Meulemanef8596e2014-09-30 10:23:13 +02002998 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002999 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003000}
3001
3002static void brcmf_escan_timeout(unsigned long data)
3003{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003004 struct brcmf_cfg80211_info *cfg =
3005 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003006
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003007 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003008 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003009 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003010 }
3011}
3012
3013static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003014brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3015 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003016 struct brcmf_bss_info_le *bss_info_le)
3017{
Franky Lin83cf17a2013-04-11 13:28:50 +02003018 struct brcmu_chan ch_bss, ch_bss_info_le;
3019
3020 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3021 cfg->d11inf.decchspec(&ch_bss);
3022 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3023 cfg->d11inf.decchspec(&ch_bss_info_le);
3024
Hante Meulemane756af52012-09-11 21:18:52 +02003025 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003026 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003027 bss_info_le->SSID_len == bss->SSID_len &&
3028 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003029 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3030 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003031 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3032 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3033
Hante Meulemane756af52012-09-11 21:18:52 +02003034 /* preserve max RSSI if the measurements are
3035 * both on-channel or both off-channel
3036 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003037 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003038 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003039 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3040 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003041 /* preserve the on-channel rssi measurement
3042 * if the new measurement is off channel
3043 */
3044 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003045 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003046 }
3047 return 1;
3048 }
3049 return 0;
3050}
3051
3052static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003053brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003054 const struct brcmf_event_msg *e, void *data)
3055{
Arend van Spriel19937322012-11-05 16:22:32 -08003056 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003057 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003058 struct brcmf_escan_result_le *escan_result_le;
Arend Van Spriel17df6452017-09-12 10:47:53 +02003059 u32 escan_buflen;
Hante Meulemane756af52012-09-11 21:18:52 +02003060 struct brcmf_bss_info_le *bss_info_le;
3061 struct brcmf_bss_info_le *bss = NULL;
3062 u32 bi_length;
3063 struct brcmf_scan_results *list;
3064 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003065 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003066
Arend van Spriel5c36b992012-11-14 18:46:05 -08003067 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003068
Hans de Goedeb9472a22017-03-08 14:50:17 +01003069 if (status == BRCMF_E_STATUS_ABORT)
3070 goto exit;
3071
Arend van Spriela0f472a2013-04-05 10:57:49 +02003072 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003073 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003074 return -EPERM;
3075 }
3076
3077 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003078 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Arend Van Spriel17df6452017-09-12 10:47:53 +02003079 if (e->datalen < sizeof(*escan_result_le)) {
3080 brcmf_err("invalid event data length\n");
3081 goto exit;
3082 }
Hante Meulemane756af52012-09-11 21:18:52 +02003083 escan_result_le = (struct brcmf_escan_result_le *) data;
3084 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003085 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003086 goto exit;
3087 }
Arend Van Spriel17df6452017-09-12 10:47:53 +02003088 escan_buflen = le32_to_cpu(escan_result_le->buflen);
3089 if (escan_buflen > BRCMF_ESCAN_BUF_SIZE ||
3090 escan_buflen > e->datalen ||
3091 escan_buflen < sizeof(*escan_result_le)) {
3092 brcmf_err("Invalid escan buffer length: %d\n",
3093 escan_buflen);
3094 goto exit;
3095 }
Hante Meulemane756af52012-09-11 21:18:52 +02003096 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003097 brcmf_err("Invalid bss_count %d: ignoring\n",
3098 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003099 goto exit;
3100 }
3101 bss_info_le = &escan_result_le->bss_info_le;
3102
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003103 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3104 goto exit;
3105
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003106 if (!cfg->int_escan_map && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003107 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3108 goto exit;
3109 }
3110
Hante Meulemane756af52012-09-11 21:18:52 +02003111 bi_length = le32_to_cpu(bss_info_le->length);
Arend Van Spriel17df6452017-09-12 10:47:53 +02003112 if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
3113 brcmf_err("Ignoring invalid bss_info length: %d\n",
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003115 goto exit;
3116 }
3117
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003118 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003119 BIT(NL80211_IFTYPE_ADHOC))) {
3120 if (le16_to_cpu(bss_info_le->capability) &
3121 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003122 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003123 goto exit;
3124 }
3125 }
3126
3127 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003128 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003129 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003130 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003131 goto exit;
3132 }
3133
3134 for (i = 0; i < list->count; i++) {
3135 bss = bss ? (struct brcmf_bss_info_le *)
3136 ((unsigned char *)bss +
3137 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003138 if (brcmf_compare_update_same_bss(cfg, bss,
3139 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003140 goto exit;
3141 }
Hante Meulemand5367332016-02-17 11:26:51 +01003142 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3143 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003144 list->version = le32_to_cpu(bss_info_le->version);
3145 list->buflen += bi_length;
3146 list->count++;
3147 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003148 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003149 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3150 goto exit;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003151 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003152 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003153 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003154 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003155 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003156 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3157 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003158 }
3159exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003160 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003161}
3162
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003163static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003164{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003165 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3166 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003167 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3168 /* Init scan_timeout timer */
Allen Pais27dd0852017-09-21 22:34:25 +05303169 setup_timer(&cfg->escan_timeout, brcmf_escan_timeout,
3170 (unsigned long)cfg);
Hante Meulemanf07998952012-11-05 16:22:13 -08003171 INIT_WORK(&cfg->escan_timeout_work,
3172 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003173}
3174
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003175static struct cfg80211_scan_request *
3176brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3177 struct cfg80211_scan_request *req;
3178 size_t req_size;
3179
3180 req_size = sizeof(*req) +
3181 n_netinfo * sizeof(req->channels[0]) +
3182 n_netinfo * sizeof(*req->ssids);
3183
3184 req = kzalloc(req_size, GFP_KERNEL);
3185 if (req) {
3186 req->wiphy = wiphy;
3187 req->ssids = (void *)(&req->channels[0]) +
3188 n_netinfo * sizeof(req->channels[0]);
3189 }
3190 return req;
3191}
3192
3193static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3194 u8 *ssid, u8 ssid_len, u8 channel)
3195{
3196 struct ieee80211_channel *chan;
3197 enum nl80211_band band;
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003198 int freq, i;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003199
3200 if (channel <= CH_MAX_2G_CHANNEL)
3201 band = NL80211_BAND_2GHZ;
3202 else
3203 band = NL80211_BAND_5GHZ;
3204
3205 freq = ieee80211_channel_to_frequency(channel, band);
3206 if (!freq)
3207 return -EINVAL;
3208
3209 chan = ieee80211_get_channel(req->wiphy, freq);
3210 if (!chan)
3211 return -EINVAL;
3212
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003213 for (i = 0; i < req->n_channels; i++) {
3214 if (req->channels[i] == chan)
3215 break;
3216 }
3217 if (i == req->n_channels)
3218 req->channels[req->n_channels++] = chan;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003219
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003220 for (i = 0; i < req->n_ssids; i++) {
3221 if (req->ssids[i].ssid_len == ssid_len &&
3222 !memcmp(req->ssids[i].ssid, ssid, ssid_len))
3223 break;
3224 }
3225 if (i == req->n_ssids) {
3226 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3227 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3228 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003229 return 0;
3230}
3231
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003232static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003233 struct cfg80211_scan_request *request)
3234{
3235 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3236 int err;
3237
3238 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003239 if (cfg->int_escan_map)
3240 brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
3241 cfg->int_escan_map);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003242 /* Abort any on-going scan */
3243 brcmf_abort_scanning(cfg);
3244 }
3245
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003246 brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003247 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3248 cfg->escan_info.run = brcmf_run_escan;
3249 err = brcmf_do_escan(ifp, request);
3250 if (err) {
3251 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3252 return err;
3253 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003254 cfg->int_escan_map = fwmap;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003255 return 0;
3256}
3257
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003258static struct brcmf_pno_net_info_le *
3259brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3260{
3261 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3262 struct brcmf_pno_net_info_le *netinfo;
3263
3264 switch (pfn_v1->version) {
3265 default:
3266 WARN_ON(1);
3267 /* fall-thru */
3268 case cpu_to_le32(1):
3269 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3270 break;
3271 case cpu_to_le32(2):
3272 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3273 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3274 break;
3275 }
3276
3277 return netinfo;
3278}
3279
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003280/* PFN result doesn't have all the info which are required by the supplicant
3281 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3282 * via wl_inform_single_bss in the required format. Escan does require the
3283 * scan request in the form of cfg80211_scan_request. For timebeing, create
3284 * cfg80211_scan_request one out of the received PNO event.
3285 */
3286static s32
3287brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3288 const struct brcmf_event_msg *e, void *data)
3289{
3290 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3291 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3292 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003293 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003294 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003295 struct brcmf_pno_scanresults_le *pfn_result;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003296 u32 bucket_map;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003297 u32 result_count;
3298 u32 status;
Arend Van Spriel4835f372017-04-06 13:14:40 +01003299 u32 datalen;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003300
3301 brcmf_dbg(SCAN, "Enter\n");
3302
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003303 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3304 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3305 return 0;
3306 }
3307
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003308 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3309 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3310 return 0;
3311 }
3312
3313 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3314 result_count = le32_to_cpu(pfn_result->count);
3315 status = le32_to_cpu(pfn_result->status);
3316
3317 /* PFN event is limited to fit 512 bytes so we may get
3318 * multiple NET_FOUND events. For now place a warning here.
3319 */
3320 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3321 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003322 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003323 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3324 goto out_err;
3325 }
Arend Van Spriel4835f372017-04-06 13:14:40 +01003326
3327 netinfo_start = brcmf_get_netinfo_array(pfn_result);
3328 datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
3329 if (datalen < result_count * sizeof(*netinfo)) {
3330 brcmf_err("insufficient event data\n");
3331 goto out_err;
3332 }
3333
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003334 request = brcmf_alloc_internal_escan_request(wiphy,
3335 result_count);
3336 if (!request) {
3337 err = -ENOMEM;
3338 goto out_err;
3339 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003340
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003341 bucket_map = 0;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003342 for (i = 0; i < result_count; i++) {
3343 netinfo = &netinfo_start[i];
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003344
Arend Van Spriel4835f372017-04-06 13:14:40 +01003345 if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
3346 netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003347 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3348 netinfo->SSID, netinfo->channel);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003349 bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003350 err = brcmf_internal_escan_add_info(request,
3351 netinfo->SSID,
3352 netinfo->SSID_len,
3353 netinfo->channel);
3354 if (err)
3355 goto out_err;
3356 }
3357
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003358 if (!bucket_map)
3359 goto free_req;
3360
3361 err = brcmf_start_internal_escan(ifp, bucket_map, request);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003362 if (!err)
3363 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003364
3365out_err:
Arend Van Sprielb34939b2017-04-28 13:40:28 +01003366 cfg80211_sched_scan_stopped(wiphy, 0);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003367free_req:
3368 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003369 return err;
3370}
3371
3372static int
3373brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3374 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003375 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003376{
3377 struct brcmf_if *ifp = netdev_priv(ndev);
3378 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003379
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003380 brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003381 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003382
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003383 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003384 brcmf_err("Scanning suppressed: status=%lu\n",
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003385 cfg->scan_status);
3386 return -EAGAIN;
3387 }
3388
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003389 if (req->n_match_sets <= 0) {
3390 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3391 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003392 return -EINVAL;
3393 }
3394
Arend Van Spriel3e486112016-11-23 10:25:27 +00003395 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003396}
3397
3398static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003399 struct net_device *ndev, u64 reqid)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003400{
3401 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003402 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003403
3404 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003405 brcmf_pno_stop_sched_scan(ifp, reqid);
3406 if (cfg->int_escan_map)
Arend Van Sprielac551362016-11-23 10:25:22 +00003407 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003408 return 0;
3409}
3410
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003411static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003412{
3413 if (ms < 1000 / HZ) {
3414 cond_resched();
3415 mdelay(ms);
3416 } else {
3417 msleep(ms);
3418 }
3419}
3420
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003421static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3422 u8 *pattern, u32 patternsize, u8 *mask,
3423 u32 packet_offset)
3424{
3425 struct brcmf_fil_wowl_pattern_le *filter;
3426 u32 masksize;
3427 u32 patternoffset;
3428 u8 *buf;
3429 u32 bufsize;
3430 s32 ret;
3431
3432 masksize = (patternsize + 7) / 8;
3433 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3434
3435 bufsize = sizeof(*filter) + patternsize + masksize;
3436 buf = kzalloc(bufsize, GFP_KERNEL);
3437 if (!buf)
3438 return -ENOMEM;
3439 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3440
3441 memcpy(filter->cmd, cmd, 4);
3442 filter->masksize = cpu_to_le32(masksize);
3443 filter->offset = cpu_to_le32(packet_offset);
3444 filter->patternoffset = cpu_to_le32(patternoffset);
3445 filter->patternsize = cpu_to_le32(patternsize);
3446 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3447
3448 if ((mask) && (masksize))
3449 memcpy(buf + sizeof(*filter), mask, masksize);
3450 if ((pattern) && (patternsize))
3451 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3452
3453 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3454
3455 kfree(buf);
3456 return ret;
3457}
3458
Hante Meuleman3021ad92016-01-05 11:05:45 +01003459static s32
3460brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3461 void *data)
3462{
3463 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3464 struct brcmf_pno_scanresults_le *pfn_result;
3465 struct brcmf_pno_net_info_le *netinfo;
3466
3467 brcmf_dbg(SCAN, "Enter\n");
3468
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003469 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3470 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3471 return 0;
3472 }
3473
Hante Meuleman3021ad92016-01-05 11:05:45 +01003474 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3475
3476 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3477 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3478 return 0;
3479 }
3480
3481 if (le32_to_cpu(pfn_result->count) < 1) {
3482 brcmf_err("Invalid result count, expected 1 (%d)\n",
3483 le32_to_cpu(pfn_result->count));
3484 return -EINVAL;
3485 }
3486
Arend Van Sprield29afe92017-01-27 12:27:46 +00003487 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003488 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3489 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3490 cfg->wowl.nd->n_channels = 1;
3491 cfg->wowl.nd->channels[0] =
3492 ieee80211_channel_to_frequency(netinfo->channel,
3493 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3494 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3495 cfg->wowl.nd_info->n_matches = 1;
3496 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3497
3498 /* Inform (the resume task) that the net detect information was recvd */
3499 cfg->wowl.nd_data_completed = true;
3500 wake_up(&cfg->wowl.nd_data_wait);
3501
3502 return 0;
3503}
3504
Hante Meulemanaeb64222015-10-29 20:33:19 +01003505#ifdef CONFIG_PM
3506
3507static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3508{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003509 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003510 struct brcmf_wowl_wakeind_le wake_ind_le;
3511 struct cfg80211_wowlan_wakeup wakeup_data;
3512 struct cfg80211_wowlan_wakeup *wakeup;
3513 u32 wakeind;
3514 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003515 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003516
3517 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3518 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003519 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003520 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3521 return;
3522 }
3523
3524 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3525 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003526 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3527 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003528 wakeup = &wakeup_data;
3529 memset(&wakeup_data, 0, sizeof(wakeup_data));
3530 wakeup_data.pattern_idx = -1;
3531
3532 if (wakeind & BRCMF_WOWL_MAGIC) {
3533 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3534 wakeup_data.magic_pkt = true;
3535 }
3536 if (wakeind & BRCMF_WOWL_DIS) {
3537 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3538 wakeup_data.disconnect = true;
3539 }
3540 if (wakeind & BRCMF_WOWL_BCN) {
3541 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3542 wakeup_data.disconnect = true;
3543 }
3544 if (wakeind & BRCMF_WOWL_RETR) {
3545 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3546 wakeup_data.disconnect = true;
3547 }
3548 if (wakeind & BRCMF_WOWL_NET) {
3549 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3550 /* For now always map to pattern 0, no API to get
3551 * correct information available at the moment.
3552 */
3553 wakeup_data.pattern_idx = 0;
3554 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003555 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3556 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3557 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3558 cfg->wowl.nd_data_completed,
3559 BRCMF_ND_INFO_TIMEOUT);
3560 if (!timeout)
3561 brcmf_err("No result for wowl net detect\n");
3562 else
3563 wakeup_data.net_detect = cfg->wowl.nd_info;
3564 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003565 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3566 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3567 wakeup_data.gtk_rekey_failure = true;
3568 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003569 } else {
3570 wakeup = NULL;
3571 }
3572 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3573}
3574
3575#else
3576
3577static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3578{
3579}
3580
3581#endif /* CONFIG_PM */
3582
Arend van Spriel5b435de2011-10-05 13:19:03 +02003583static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3584{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003585 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3586 struct net_device *ndev = cfg_to_ndev(cfg);
3587 struct brcmf_if *ifp = netdev_priv(ndev);
3588
Arend van Sprield96b8012012-12-05 15:26:02 +01003589 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003590
Hante Meuleman3021ad92016-01-05 11:05:45 +01003591 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003592 brcmf_report_wowl_wakeind(wiphy, ifp);
3593 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3594 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003595 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3596 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003597 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003598 cfg->wowl.pre_pmmode);
3599 cfg->wowl.active = false;
3600 if (cfg->wowl.nd_enabled) {
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003601 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003602 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3603 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3604 brcmf_notify_sched_scan_results);
3605 cfg->wowl.nd_enabled = false;
3606 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003607 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003608 return 0;
3609}
3610
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003611static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3612 struct brcmf_if *ifp,
3613 struct cfg80211_wowlan *wowl)
3614{
3615 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003616 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003617 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003618
3619 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3620
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003621 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3622 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003623 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003624 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3625
3626 wowl_config = 0;
3627 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003628 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003629 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003630 wowl_config |= BRCMF_WOWL_MAGIC;
3631 if ((wowl->patterns) && (wowl->n_patterns)) {
3632 wowl_config |= BRCMF_WOWL_NET;
3633 for (i = 0; i < wowl->n_patterns; i++) {
3634 brcmf_config_wowl_pattern(ifp, "add",
3635 (u8 *)wowl->patterns[i].pattern,
3636 wowl->patterns[i].pattern_len,
3637 (u8 *)wowl->patterns[i].mask,
3638 wowl->patterns[i].pkt_offset);
3639 }
3640 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003641 if (wowl->nd_config) {
3642 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3643 wowl->nd_config);
3644 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3645
3646 cfg->wowl.nd_data_completed = false;
3647 cfg->wowl.nd_enabled = true;
3648 /* Now reroute the event for PFN to the wowl function. */
3649 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3650 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3651 brcmf_wowl_nd_results);
3652 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003653 if (wowl->gtk_rekey_failure)
3654 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003655 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3656 wowl_config |= BRCMF_WOWL_UNASSOC;
3657
Hante Meulemana7ed7822016-09-19 12:09:58 +01003658 memcpy(&wowl_wakeind, "clear", 6);
3659 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3660 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003661 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3662 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3663 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003664 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003665}
3666
Arend van Spriel5b435de2011-10-05 13:19:03 +02003667static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003668 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003669{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003670 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3671 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003672 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003673 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003674
Arend van Sprield96b8012012-12-05 15:26:02 +01003675 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003676
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003677 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003678 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003679 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003680 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003681 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003682
Hante Meuleman3021ad92016-01-05 11:05:45 +01003683 /* Stop scheduled scan */
3684 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003685 brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003686
Arend van Spriel7d641072012-10-22 13:55:39 -07003687 /* end any scanning */
3688 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003689 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003690
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003691 if (wowl == NULL) {
3692 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3693 list_for_each_entry(vif, &cfg->vif_list, list) {
3694 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3695 continue;
3696 /* While going to suspend if associated with AP
3697 * disassociate from AP to save power while system is
3698 * in suspended state
3699 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003700 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003701 /* Make sure WPA_Supplicant receives all the event
3702 * generated due to DISASSOC call to the fw to keep
3703 * the state fw and WPA_Supplicant state consistent
3704 */
3705 brcmf_delay(500);
3706 }
3707 /* Configure MPC */
3708 brcmf_set_mpc(ifp, 1);
3709
3710 } else {
3711 /* Configure WOWL paramaters */
3712 brcmf_configure_wowl(cfg, ifp, wowl);
3713 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003714
Arend van Spriel7d641072012-10-22 13:55:39 -07003715exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003716 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003717 /* clear any scanning activity */
3718 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003719 return 0;
3720}
3721
3722static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003723brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003724{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003725 struct brcmf_pmk_list_le *pmk_list;
3726 int i;
3727 u32 npmk;
3728 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003729
Hante Meuleman6c404f32015-12-10 13:43:03 +01003730 pmk_list = &cfg->pmk_list;
3731 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003732
Hante Meuleman6c404f32015-12-10 13:43:03 +01003733 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3734 for (i = 0; i < npmk; i++)
3735 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003736
Hante Meuleman6c404f32015-12-10 13:43:03 +01003737 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3738 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003739
3740 return err;
3741}
3742
3743static s32
3744brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3745 struct cfg80211_pmksa *pmksa)
3746{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003747 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003748 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003749 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3750 s32 err;
3751 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003752
Arend van Sprield96b8012012-12-05 15:26:02 +01003753 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003754 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003755 return -EIO;
3756
Hante Meuleman6c404f32015-12-10 13:43:03 +01003757 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3758 for (i = 0; i < npmk; i++)
3759 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003760 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003761 if (i < BRCMF_MAXPMKID) {
3762 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3763 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3764 if (i == npmk) {
3765 npmk++;
3766 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003767 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003768 } else {
3769 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3770 return -EINVAL;
3771 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003772
Hante Meuleman6c404f32015-12-10 13:43:03 +01003773 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3774 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3775 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3776 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3777 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003778
Hante Meuleman6c404f32015-12-10 13:43:03 +01003779 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780
Arend van Sprield96b8012012-12-05 15:26:02 +01003781 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003782 return err;
3783}
3784
3785static s32
3786brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003787 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003788{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003789 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003790 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003791 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3792 s32 err;
3793 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003794
Arend van Sprield96b8012012-12-05 15:26:02 +01003795 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003796 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003797 return -EIO;
3798
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003799 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003800
Hante Meuleman6c404f32015-12-10 13:43:03 +01003801 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3802 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003803 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003804 break;
3805
Hante Meuleman6c404f32015-12-10 13:43:03 +01003806 if ((npmk > 0) && (i < npmk)) {
3807 for (; i < (npmk - 1); i++) {
3808 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3809 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003810 WLAN_PMKID_LEN);
3811 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003812 memset(&pmk[i], 0, sizeof(*pmk));
3813 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3814 } else {
3815 brcmf_err("Cache entry not found\n");
3816 return -EINVAL;
3817 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003818
Hante Meuleman6c404f32015-12-10 13:43:03 +01003819 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003820
Arend van Sprield96b8012012-12-05 15:26:02 +01003821 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003822 return err;
3823
3824}
3825
3826static s32
3827brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3828{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003829 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003830 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003831 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003832
Arend van Sprield96b8012012-12-05 15:26:02 +01003833 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003834 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003835 return -EIO;
3836
Hante Meuleman6c404f32015-12-10 13:43:03 +01003837 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3838 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003839
Arend van Sprield96b8012012-12-05 15:26:02 +01003840 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003841 return err;
3842
3843}
3844
Hante Meuleman1f170112013-02-06 18:40:38 +01003845static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003846{
3847 s32 err;
Wright Fengfdfb0f92017-08-03 17:37:57 +08003848 s32 wpa_val;
Hante Meuleman1a873342012-09-27 14:17:54 +02003849
3850 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003851 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003852 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003853 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003854 return err;
3855 }
3856 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003857 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003858 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003859 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003860 return err;
3861 }
3862 /* set upper-layer auth */
Wright Fengfdfb0f92017-08-03 17:37:57 +08003863 if (brcmf_is_ibssmode(ifp->vif))
3864 wpa_val = WPA_AUTH_NONE;
3865 else
3866 wpa_val = WPA_AUTH_DISABLED;
3867 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val);
Hante Meuleman1a873342012-09-27 14:17:54 +02003868 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003869 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003870 return err;
3871 }
3872
3873 return 0;
3874}
3875
3876static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3877{
3878 if (is_rsn_ie)
3879 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3880
3881 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3882}
3883
3884static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003885brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003886 const struct brcmf_vs_tlv *wpa_ie,
3887 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003888{
3889 u32 auth = 0; /* d11 open authentication */
3890 u16 count;
3891 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003892 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003893 u32 i;
3894 u32 wsec;
3895 u32 pval = 0;
3896 u32 gval = 0;
3897 u32 wpa_auth = 0;
3898 u32 offset;
3899 u8 *data;
3900 u16 rsn_cap;
3901 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003902 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003903
Arend van Sprield96b8012012-12-05 15:26:02 +01003904 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003905 if (wpa_ie == NULL)
3906 goto exit;
3907
3908 len = wpa_ie->len + TLV_HDR_LEN;
3909 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003910 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003911 if (!is_rsn_ie)
3912 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003913 else
3914 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003915
3916 /* check for multicast cipher suite */
3917 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3918 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003919 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003920 goto exit;
3921 }
3922
3923 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3924 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003925 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003926 goto exit;
3927 }
3928 offset += TLV_OUI_LEN;
3929
3930 /* pick up multicast cipher */
3931 switch (data[offset]) {
3932 case WPA_CIPHER_NONE:
3933 gval = 0;
3934 break;
3935 case WPA_CIPHER_WEP_40:
3936 case WPA_CIPHER_WEP_104:
3937 gval = WEP_ENABLED;
3938 break;
3939 case WPA_CIPHER_TKIP:
3940 gval = TKIP_ENABLED;
3941 break;
3942 case WPA_CIPHER_AES_CCM:
3943 gval = AES_ENABLED;
3944 break;
3945 default:
3946 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003947 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 goto exit;
3949 }
3950
3951 offset++;
3952 /* walk thru unicast cipher list and pick up what we recognize */
3953 count = data[offset] + (data[offset + 1] << 8);
3954 offset += WPA_IE_SUITE_COUNT_LEN;
3955 /* Check for unicast suite(s) */
3956 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3957 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003958 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003959 goto exit;
3960 }
3961 for (i = 0; i < count; i++) {
3962 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3963 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003964 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003965 goto exit;
3966 }
3967 offset += TLV_OUI_LEN;
3968 switch (data[offset]) {
3969 case WPA_CIPHER_NONE:
3970 break;
3971 case WPA_CIPHER_WEP_40:
3972 case WPA_CIPHER_WEP_104:
3973 pval |= WEP_ENABLED;
3974 break;
3975 case WPA_CIPHER_TKIP:
3976 pval |= TKIP_ENABLED;
3977 break;
3978 case WPA_CIPHER_AES_CCM:
3979 pval |= AES_ENABLED;
3980 break;
3981 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00003982 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003983 }
3984 offset++;
3985 }
3986 /* walk thru auth management suite list and pick up what we recognize */
3987 count = data[offset] + (data[offset + 1] << 8);
3988 offset += WPA_IE_SUITE_COUNT_LEN;
3989 /* Check for auth key management suite(s) */
3990 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3991 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003992 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003993 goto exit;
3994 }
3995 for (i = 0; i < count; i++) {
3996 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3997 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003998 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003999 goto exit;
4000 }
4001 offset += TLV_OUI_LEN;
4002 switch (data[offset]) {
4003 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004004 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004005 wpa_auth |= WPA_AUTH_NONE;
4006 break;
4007 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004008 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004009 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4010 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4011 break;
4012 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004013 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004014 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4015 (wpa_auth |= WPA_AUTH_PSK);
4016 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004017 case RSN_AKM_SHA256_PSK:
4018 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4019 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4020 break;
4021 case RSN_AKM_SHA256_1X:
4022 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4023 wpa_auth |= WPA2_AUTH_1X_SHA256;
4024 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004025 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004026 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004027 }
4028 offset++;
4029 }
4030
Hante Meuleman240d61a2016-02-17 11:27:10 +01004031 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004032 if (is_rsn_ie) {
4033 wme_bss_disable = 1;
4034 if ((offset + RSN_CAP_LEN) <= len) {
4035 rsn_cap = data[offset] + (data[offset + 1] << 8);
4036 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4037 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004038 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4039 brcmf_dbg(TRACE, "MFP Required\n");
4040 mfp = BRCMF_MFP_REQUIRED;
4041 /* Firmware only supports mfp required in
4042 * combination with WPA2_AUTH_PSK_SHA256 or
4043 * WPA2_AUTH_1X_SHA256.
4044 */
4045 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4046 WPA2_AUTH_1X_SHA256))) {
4047 err = -EINVAL;
4048 goto exit;
4049 }
4050 /* Firmware has requirement that WPA2_AUTH_PSK/
4051 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4052 * is to be included in the rsn ie.
4053 */
4054 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4055 wpa_auth |= WPA2_AUTH_PSK;
4056 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4057 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4058 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4059 brcmf_dbg(TRACE, "MFP Capable\n");
4060 mfp = BRCMF_MFP_CAPABLE;
4061 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004062 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004063 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004064 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004065 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004066 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004067 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004068 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004069 goto exit;
4070 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004071
4072 /* Skip PMKID cnt as it is know to be 0 for AP. */
4073 offset += RSN_PMKID_COUNT_LEN;
4074
4075 /* See if there is BIP wpa suite left for MFP */
4076 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4077 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4078 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4079 &data[offset],
4080 WPA_IE_MIN_OUI_LEN);
4081 if (err < 0) {
4082 brcmf_err("bip error %d\n", err);
4083 goto exit;
4084 }
4085 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004086 }
4087 /* FOR WPS , set SES_OW_ENABLED */
4088 wsec = (pval | gval | SES_OW_ENABLED);
4089
4090 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004091 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004092 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004093 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004094 goto exit;
4095 }
4096 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004097 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004098 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004099 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004100 goto exit;
4101 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004102 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4103 * will overwrite the values set by MFP
4104 */
4105 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4106 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4107 if (err < 0) {
4108 brcmf_err("mfp error %d\n", err);
4109 goto exit;
4110 }
4111 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004112 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004113 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004114 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004115 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004116 goto exit;
4117 }
4118
4119exit:
4120 return err;
4121}
4122
4123static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004124brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004125 struct parsed_vndr_ies *vndr_ies)
4126{
Hante Meuleman1a873342012-09-27 14:17:54 +02004127 struct brcmf_vs_tlv *vndrie;
4128 struct brcmf_tlv *ie;
4129 struct parsed_vndr_ie_info *parsed_info;
4130 s32 remaining_len;
4131
4132 remaining_len = (s32)vndr_ie_len;
4133 memset(vndr_ies, 0, sizeof(*vndr_ies));
4134
4135 ie = (struct brcmf_tlv *)vndr_ie_buf;
4136 while (ie) {
4137 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4138 goto next;
4139 vndrie = (struct brcmf_vs_tlv *)ie;
4140 /* len should be bigger than OUI length + one */
4141 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004142 brcmf_err("invalid vndr ie. length is too small %d\n",
4143 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004144 goto next;
4145 }
4146 /* if wpa or wme ie, do not add ie */
4147 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4148 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4149 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004150 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004151 goto next;
4152 }
4153
4154 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4155
4156 /* save vndr ie information */
4157 parsed_info->ie_ptr = (char *)vndrie;
4158 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4159 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4160
4161 vndr_ies->count++;
4162
Arend van Sprield96b8012012-12-05 15:26:02 +01004163 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4164 parsed_info->vndrie.oui[0],
4165 parsed_info->vndrie.oui[1],
4166 parsed_info->vndrie.oui[2],
4167 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004168
Arend van Spriel9f440b72013-02-08 15:53:36 +01004169 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004170 break;
4171next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004172 remaining_len -= (ie->len + TLV_HDR_LEN);
4173 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004174 ie = NULL;
4175 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004176 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4177 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004178 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004179 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004180}
4181
4182static u32
4183brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4184{
4185
Hante Meuleman1a873342012-09-27 14:17:54 +02004186 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4187 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4188
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304189 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004190
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304191 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004192
4193 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4194
4195 return ie_len + VNDR_IE_HDR_SIZE;
4196}
4197
Arend van Spriel1332e262012-11-05 16:22:18 -08004198s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4199 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004200{
Arend van Spriel1332e262012-11-05 16:22:18 -08004201 struct brcmf_if *ifp;
4202 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004203 s32 err = 0;
4204 u8 *iovar_ie_buf;
4205 u8 *curr_ie_buf;
4206 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004207 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004208 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004209 u32 del_add_ie_buf_len = 0;
4210 u32 total_ie_buf_len = 0;
4211 u32 parsed_ie_buf_len = 0;
4212 struct parsed_vndr_ies old_vndr_ies;
4213 struct parsed_vndr_ies new_vndr_ies;
4214 struct parsed_vndr_ie_info *vndrie_info;
4215 s32 i;
4216 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004217 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004218
Arend van Spriel1332e262012-11-05 16:22:18 -08004219 if (!vif)
4220 return -ENODEV;
4221 ifp = vif->ifp;
4222 saved_ie = &vif->saved_ie;
4223
Hante Meuleman37a869e2015-10-29 20:33:17 +01004224 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4225 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004226 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4227 if (!iovar_ie_buf)
4228 return -ENOMEM;
4229 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004230 switch (pktflag) {
4231 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4232 mgmt_ie_buf = saved_ie->probe_req_ie;
4233 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4234 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4235 break;
4236 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4237 mgmt_ie_buf = saved_ie->probe_res_ie;
4238 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4239 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4240 break;
4241 case BRCMF_VNDR_IE_BEACON_FLAG:
4242 mgmt_ie_buf = saved_ie->beacon_ie;
4243 mgmt_ie_len = &saved_ie->beacon_ie_len;
4244 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4245 break;
4246 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4247 mgmt_ie_buf = saved_ie->assoc_req_ie;
4248 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4249 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4250 break;
4251 default:
4252 err = -EPERM;
4253 brcmf_err("not suitable type\n");
4254 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004255 }
4256
4257 if (vndr_ie_len > mgmt_ie_buf_len) {
4258 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004259 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004260 goto exit;
4261 }
4262
4263 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4264 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4265 ptr = curr_ie_buf;
4266 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4267 for (i = 0; i < new_vndr_ies.count; i++) {
4268 vndrie_info = &new_vndr_ies.ie_info[i];
4269 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4270 vndrie_info->ie_len);
4271 parsed_ie_buf_len += vndrie_info->ie_len;
4272 }
4273 }
4274
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004275 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004276 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4277 (memcmp(mgmt_ie_buf, curr_ie_buf,
4278 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004279 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004280 goto exit;
4281 }
4282
4283 /* parse old vndr_ie */
4284 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4285
4286 /* make a command to delete old ie */
4287 for (i = 0; i < old_vndr_ies.count; i++) {
4288 vndrie_info = &old_vndr_ies.ie_info[i];
4289
Arend van Sprield96b8012012-12-05 15:26:02 +01004290 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4291 vndrie_info->vndrie.id,
4292 vndrie_info->vndrie.len,
4293 vndrie_info->vndrie.oui[0],
4294 vndrie_info->vndrie.oui[1],
4295 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004296
4297 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4298 vndrie_info->ie_ptr,
4299 vndrie_info->ie_len,
4300 "del");
4301 curr_ie_buf += del_add_ie_buf_len;
4302 total_ie_buf_len += del_add_ie_buf_len;
4303 }
4304 }
4305
4306 *mgmt_ie_len = 0;
4307 /* Add if there is any extra IE */
4308 if (mgmt_ie_buf && parsed_ie_buf_len) {
4309 ptr = mgmt_ie_buf;
4310
4311 remained_buf_len = mgmt_ie_buf_len;
4312
4313 /* make a command to add new ie */
4314 for (i = 0; i < new_vndr_ies.count; i++) {
4315 vndrie_info = &new_vndr_ies.ie_info[i];
4316
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004317 /* verify remained buf size before copy data */
4318 if (remained_buf_len < (vndrie_info->vndrie.len +
4319 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004320 brcmf_err("no space in mgmt_ie_buf: len left %d",
4321 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004322 break;
4323 }
4324 remained_buf_len -= (vndrie_info->ie_len +
4325 VNDR_IE_VSIE_OFFSET);
4326
Arend van Sprield96b8012012-12-05 15:26:02 +01004327 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4328 vndrie_info->vndrie.id,
4329 vndrie_info->vndrie.len,
4330 vndrie_info->vndrie.oui[0],
4331 vndrie_info->vndrie.oui[1],
4332 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004333
4334 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4335 vndrie_info->ie_ptr,
4336 vndrie_info->ie_len,
4337 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004338
4339 /* save the parsed IE in wl struct */
4340 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4341 vndrie_info->ie_len);
4342 *mgmt_ie_len += vndrie_info->ie_len;
4343
4344 curr_ie_buf += del_add_ie_buf_len;
4345 total_ie_buf_len += del_add_ie_buf_len;
4346 }
4347 }
4348 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004349 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004350 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004351 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004352 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004353 }
4354
4355exit:
4356 kfree(iovar_ie_buf);
4357 return err;
4358}
4359
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004360s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4361{
4362 s32 pktflags[] = {
4363 BRCMF_VNDR_IE_PRBREQ_FLAG,
4364 BRCMF_VNDR_IE_PRBRSP_FLAG,
4365 BRCMF_VNDR_IE_BEACON_FLAG
4366 };
4367 int i;
4368
4369 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4370 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4371
4372 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4373 return 0;
4374}
4375
Hante Meuleman1a873342012-09-27 14:17:54 +02004376static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004377brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4378 struct cfg80211_beacon_data *beacon)
4379{
4380 s32 err;
4381
4382 /* Set Beacon IEs to FW */
4383 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4384 beacon->tail, beacon->tail_len);
4385 if (err) {
4386 brcmf_err("Set Beacon IE Failed\n");
4387 return err;
4388 }
4389 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4390
4391 /* Set Probe Response IEs to FW */
4392 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4393 beacon->proberesp_ies,
4394 beacon->proberesp_ies_len);
4395 if (err)
4396 brcmf_err("Set Probe Resp IE Failed\n");
4397 else
4398 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4399
4400 return err;
4401}
4402
4403static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004404brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4405 struct cfg80211_ap_settings *settings)
4406{
4407 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004408 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004409 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004410 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004411 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004412 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004413 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004414 const struct brcmf_tlv *rsn_ie;
4415 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004416 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004417 enum nl80211_iftype dev_role;
4418 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004419 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004420 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004421 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004422 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004423
Arend van Spriel06c01582014-05-12 10:47:37 +02004424 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4425 settings->chandef.chan->hw_value,
4426 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004427 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004428 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4429 settings->ssid, settings->ssid_len, settings->auth_type,
4430 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004431 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004432 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004433
Arend van Spriel98027762014-12-21 12:43:53 +01004434 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004435 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4436 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004437 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004438 } else {
4439 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4440 settings->beacon.tail_len,
4441 WLAN_EID_COUNTRY);
4442 is_11d = country_ie ? 1 : 0;
4443 supports_11d = true;
4444 }
Arend van Spriel98027762014-12-21 12:43:53 +01004445
Hante Meuleman1a873342012-09-27 14:17:54 +02004446 memset(&ssid_le, 0, sizeof(ssid_le));
4447 if (settings->ssid == NULL || settings->ssid_len == 0) {
4448 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4449 ssid_ie = brcmf_parse_tlvs(
4450 (u8 *)&settings->beacon.head[ie_offset],
4451 settings->beacon.head_len - ie_offset,
4452 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004453 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004454 return -EINVAL;
4455
4456 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4457 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004458 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004459 } else {
4460 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4461 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4462 }
4463
Hante Meulemana44aa402014-12-03 21:05:33 +01004464 if (!mbss) {
4465 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004466 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004467 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004468
4469 /* find the RSN_IE */
4470 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4471 settings->beacon.tail_len, WLAN_EID_RSN);
4472
4473 /* find the WPA_IE */
4474 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4475 settings->beacon.tail_len);
4476
Hante Meuleman1a873342012-09-27 14:17:54 +02004477 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004478 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004479 if (wpa_ie != NULL) {
4480 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004481 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004482 if (err < 0)
4483 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004484 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004485 struct brcmf_vs_tlv *tmp_ie;
4486
4487 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4488
Hante Meuleman1a873342012-09-27 14:17:54 +02004489 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004490 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004491 if (err < 0)
4492 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004493 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004494 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004495 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004496 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004497 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004498
Rafał Miłecki8707e082016-05-27 21:07:19 +02004499 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004500 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004501 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004502 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4503 is_11d);
4504 if (err < 0) {
4505 brcmf_err("Regulatory Set Error, %d\n", err);
4506 goto exit;
4507 }
4508 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004509 if (settings->beacon_interval) {
4510 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4511 settings->beacon_interval);
4512 if (err < 0) {
4513 brcmf_err("Beacon Interval Set Error, %d\n",
4514 err);
4515 goto exit;
4516 }
4517 }
4518 if (settings->dtim_period) {
4519 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4520 settings->dtim_period);
4521 if (err < 0) {
4522 brcmf_err("DTIM Interval Set Error, %d\n", err);
4523 goto exit;
4524 }
4525 }
4526
Hante Meuleman8abffd82015-10-29 20:33:16 +01004527 if ((dev_role == NL80211_IFTYPE_AP) &&
4528 ((ifp->ifidx == 0) ||
4529 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004530 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4531 if (err < 0) {
4532 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4533 goto exit;
4534 }
4535 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4536 }
4537
4538 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004539 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004540 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004541 goto exit;
4542 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004543 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004544 /* Multiple-BSS should use same 11d configuration */
4545 err = -EINVAL;
4546 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004547 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004548
4549 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004550 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004551 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4552 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4553
Hante Meulemana0f07952013-02-08 15:53:47 +01004554 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4555 if (err < 0) {
4556 brcmf_err("setting AP mode failed %d\n", err);
4557 goto exit;
4558 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004559 if (!mbss) {
4560 /* Firmware 10.x requires setting channel after enabling
4561 * AP and before bringing interface up.
4562 */
4563 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4564 if (err < 0) {
4565 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4566 chanspec, err);
4567 goto exit;
4568 }
4569 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004570 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4571 if (err < 0) {
4572 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4573 goto exit;
4574 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004575 /* On DOWN the firmware removes the WEP keys, reconfigure
4576 * them if they were set.
4577 */
4578 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004579
4580 memset(&join_params, 0, sizeof(join_params));
4581 /* join parameters starts with ssid */
4582 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4583 /* create softap */
4584 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4585 &join_params, sizeof(join_params));
4586 if (err < 0) {
4587 brcmf_err("SET SSID error (%d)\n", err);
4588 goto exit;
4589 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004590
4591 if (settings->hidden_ssid) {
4592 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4593 if (err) {
4594 brcmf_err("closednet error (%d)\n", err);
4595 goto exit;
4596 }
4597 }
4598
Hante Meulemana0f07952013-02-08 15:53:47 +01004599 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004600 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4601 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4602 if (err < 0) {
4603 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4604 chanspec, err);
4605 goto exit;
4606 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004607 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4608 sizeof(ssid_le));
4609 if (err < 0) {
4610 brcmf_err("setting ssid failed %d\n", err);
4611 goto exit;
4612 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004613 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004614 bss_enable.enable = cpu_to_le32(1);
4615 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4616 sizeof(bss_enable));
4617 if (err < 0) {
4618 brcmf_err("bss_enable config failed %d\n", err);
4619 goto exit;
4620 }
4621
4622 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004623 } else {
4624 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004625 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004626
Wright Fengf25ba692016-11-18 09:59:52 +08004627 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004628 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004629 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004630
4631exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004632 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004633 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004634 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004635 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004636 return err;
4637}
4638
4639static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4640{
Arend van Sprielc1179032012-10-22 13:55:33 -07004641 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004642 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004643 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004644 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004645
Arend van Sprield96b8012012-12-05 15:26:02 +01004646 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004647
Hante Meuleman426d0a52013-02-08 15:53:53 +01004648 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004649 /* Due to most likely deauths outstanding we sleep */
4650 /* first to make sure they get processed by fw. */
4651 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004652
Hante Meulemana44aa402014-12-03 21:05:33 +01004653 if (ifp->vif->mbss) {
4654 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4655 return err;
4656 }
4657
Rafał Miłeckic940de12016-07-06 12:22:54 +02004658 /* First BSS doesn't get a full reset */
4659 if (ifp->bsscfgidx == 0)
4660 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4661
Hante Meuleman5c33a942013-04-02 21:06:18 +02004662 memset(&join_params, 0, sizeof(join_params));
4663 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4664 &join_params, sizeof(join_params));
4665 if (err < 0)
4666 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004667 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004668 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004669 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004670 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4671 if (err < 0)
4672 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004673 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4674 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004675 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4676 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004677 /* Bring device back up so it can be used again */
4678 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4679 if (err < 0)
4680 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004681
4682 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004683 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004684 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004685 bss_enable.enable = cpu_to_le32(0);
4686 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4687 sizeof(bss_enable));
4688 if (err < 0)
4689 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004690 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004691 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004692 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004693 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004694 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004695
Hante Meuleman1a873342012-09-27 14:17:54 +02004696 return err;
4697}
4698
Hante Meulemana0f07952013-02-08 15:53:47 +01004699static s32
4700brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4701 struct cfg80211_beacon_data *info)
4702{
Hante Meulemana0f07952013-02-08 15:53:47 +01004703 struct brcmf_if *ifp = netdev_priv(ndev);
4704 s32 err;
4705
4706 brcmf_dbg(TRACE, "Enter\n");
4707
Hante Meulemana0f07952013-02-08 15:53:47 +01004708 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4709
4710 return err;
4711}
4712
Hante Meuleman1a873342012-09-27 14:17:54 +02004713static int
4714brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004715 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004716{
Hante Meulemana0f07952013-02-08 15:53:47 +01004717 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004718 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004719 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004720 s32 err;
4721
Jouni Malinen89c771e2014-10-10 20:52:40 +03004722 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004723 return -EFAULT;
4724
Jouni Malinen89c771e2014-10-10 20:52:40 +03004725 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004726
Hante Meulemana0f07952013-02-08 15:53:47 +01004727 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4728 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004729 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004730 return -EIO;
4731
Jouni Malinen89c771e2014-10-10 20:52:40 +03004732 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004733 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004734 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004735 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004736 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004737 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004738
Arend van Sprield96b8012012-12-05 15:26:02 +01004739 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004740 return err;
4741}
4742
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004743static int
4744brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4745 const u8 *mac, struct station_parameters *params)
4746{
4747 struct brcmf_if *ifp = netdev_priv(ndev);
4748 s32 err;
4749
4750 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4751 params->sta_flags_mask, params->sta_flags_set);
4752
4753 /* Ignore all 00 MAC */
4754 if (is_zero_ether_addr(mac))
4755 return 0;
4756
4757 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4758 return 0;
4759
4760 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4761 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4762 (void *)mac, ETH_ALEN);
4763 else
4764 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4765 (void *)mac, ETH_ALEN);
4766 if (err < 0)
4767 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4768
4769 return err;
4770}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004771
4772static void
4773brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4774 struct wireless_dev *wdev,
4775 u16 frame_type, bool reg)
4776{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004777 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004778 u16 mgmt_type;
4779
4780 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4781
4782 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004783 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004784 if (reg)
4785 vif->mgmt_rx_reg |= BIT(mgmt_type);
4786 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004787 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004788}
4789
4790
4791static int
4792brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004793 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004794{
4795 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004796 struct ieee80211_channel *chan = params->chan;
4797 const u8 *buf = params->buf;
4798 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004799 const struct ieee80211_mgmt *mgmt;
4800 struct brcmf_cfg80211_vif *vif;
4801 s32 err = 0;
4802 s32 ie_offset;
4803 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004804 struct brcmf_fil_action_frame_le *action_frame;
4805 struct brcmf_fil_af_params_le *af_params;
4806 bool ack;
4807 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004808 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004809
4810 brcmf_dbg(TRACE, "Enter\n");
4811
4812 *cookie = 0;
4813
4814 mgmt = (const struct ieee80211_mgmt *)buf;
4815
Hante Meulemana0f07952013-02-08 15:53:47 +01004816 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4817 brcmf_err("Driver only allows MGMT packet type\n");
4818 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004819 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004820
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004821 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4822
Hante Meulemana0f07952013-02-08 15:53:47 +01004823 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4824 /* Right now the only reason to get a probe response */
4825 /* is for p2p listen response or for p2p GO from */
4826 /* wpa_supplicant. Unfortunately the probe is send */
4827 /* on primary ndev, while dongle wants it on the p2p */
4828 /* vif. Since this is only reason for a probe */
4829 /* response to be sent, the vif is taken from cfg. */
4830 /* If ever desired to send proberesp for non p2p */
4831 /* response then data should be checked for */
4832 /* "DIRECT-". Note in future supplicant will take */
4833 /* dedicated p2p wdev to do this and then this 'hack'*/
4834 /* is not needed anymore. */
4835 ie_offset = DOT11_MGMT_HDR_LEN +
4836 DOT11_BCN_PRB_FIXED_LEN;
4837 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004838 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4839 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4840 err = brcmf_vif_set_mgmt_ie(vif,
4841 BRCMF_VNDR_IE_PRBRSP_FLAG,
4842 &buf[ie_offset],
4843 ie_len);
4844 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4845 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004846 } else if (ieee80211_is_action(mgmt->frame_control)) {
Arend van Spriel8f44c9a2017-07-07 21:09:06 +01004847 if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
4848 brcmf_err("invalid action frame length\n");
4849 err = -EINVAL;
4850 goto exit;
4851 }
Hante Meuleman18e2f612013-02-08 15:53:49 +01004852 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4853 if (af_params == NULL) {
4854 brcmf_err("unable to allocate frame\n");
4855 err = -ENOMEM;
4856 goto exit;
4857 }
4858 action_frame = &af_params->action_frame;
4859 /* Add the packet Id */
4860 action_frame->packet_id = cpu_to_le32(*cookie);
4861 /* Add BSSID */
4862 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4863 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4864 /* Add the length exepted for 802.11 header */
4865 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004866 /* Add the channel. Use the one specified as parameter if any or
4867 * the current one (got from the firmware) otherwise
4868 */
4869 if (chan)
4870 freq = chan->center_freq;
4871 else
4872 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4873 &freq);
4874 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004875 af_params->channel = cpu_to_le32(chan_nr);
4876
4877 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4878 le16_to_cpu(action_frame->len));
4879
4880 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004881 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004882
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004883 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004884 af_params);
4885
4886 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4887 GFP_KERNEL);
4888 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004889 } else {
4890 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004891 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004892 }
4893
Hante Meuleman18e2f612013-02-08 15:53:49 +01004894exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004895 return err;
4896}
4897
4898
4899static int
4900brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4901 struct wireless_dev *wdev,
4902 u64 cookie)
4903{
4904 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4905 struct brcmf_cfg80211_vif *vif;
4906 int err = 0;
4907
4908 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4909
4910 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4911 if (vif == NULL) {
4912 brcmf_err("No p2p device available for probe response\n");
4913 err = -ENODEV;
4914 goto exit;
4915 }
4916 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4917exit:
4918 return err;
4919}
4920
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004921static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4922 struct wireless_dev *wdev,
4923 struct cfg80211_chan_def *chandef)
4924{
4925 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4926 struct net_device *ndev = wdev->netdev;
4927 struct brcmf_if *ifp;
4928 struct brcmu_chan ch;
4929 enum nl80211_band band = 0;
4930 enum nl80211_chan_width width = 0;
4931 u32 chanspec;
4932 int freq, err;
4933
4934 if (!ndev)
4935 return -ENODEV;
4936 ifp = netdev_priv(ndev);
4937
4938 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4939 if (err) {
4940 brcmf_err("chanspec failed (%d)\n", err);
4941 return err;
4942 }
4943
4944 ch.chspec = chanspec;
4945 cfg->d11inf.decchspec(&ch);
4946
4947 switch (ch.band) {
4948 case BRCMU_CHAN_BAND_2G:
4949 band = NL80211_BAND_2GHZ;
4950 break;
4951 case BRCMU_CHAN_BAND_5G:
4952 band = NL80211_BAND_5GHZ;
4953 break;
4954 }
4955
4956 switch (ch.bw) {
4957 case BRCMU_CHAN_BW_80:
4958 width = NL80211_CHAN_WIDTH_80;
4959 break;
4960 case BRCMU_CHAN_BW_40:
4961 width = NL80211_CHAN_WIDTH_40;
4962 break;
4963 case BRCMU_CHAN_BW_20:
4964 width = NL80211_CHAN_WIDTH_20;
4965 break;
4966 case BRCMU_CHAN_BW_80P80:
4967 width = NL80211_CHAN_WIDTH_80P80;
4968 break;
4969 case BRCMU_CHAN_BW_160:
4970 width = NL80211_CHAN_WIDTH_160;
4971 break;
4972 }
4973
4974 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
4975 chandef->chan = ieee80211_get_channel(wiphy, freq);
4976 chandef->width = width;
4977 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
4978 chandef->center_freq2 = 0;
4979
4980 return 0;
4981}
4982
Piotr Haber61730d42013-04-23 12:53:12 +02004983static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4984 struct wireless_dev *wdev,
4985 enum nl80211_crit_proto_id proto,
4986 u16 duration)
4987{
4988 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4989 struct brcmf_cfg80211_vif *vif;
4990
4991 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4992
4993 /* only DHCP support for now */
4994 if (proto != NL80211_CRIT_PROTO_DHCP)
4995 return -EINVAL;
4996
4997 /* suppress and abort scanning */
4998 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4999 brcmf_abort_scanning(cfg);
5000
5001 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5002}
5003
5004static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5005 struct wireless_dev *wdev)
5006{
5007 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5008 struct brcmf_cfg80211_vif *vif;
5009
5010 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5011
5012 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5013 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5014}
5015
Hante Meuleman70b7d942014-07-30 13:20:07 +02005016static s32
5017brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5018 const struct brcmf_event_msg *e, void *data)
5019{
5020 switch (e->reason) {
5021 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5022 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5023 break;
5024 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5025 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5026 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5027 break;
5028 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5029 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5030 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5031 break;
5032 }
5033
5034 return 0;
5035}
5036
Arend van Spriel89c2f382013-08-10 12:27:25 +02005037static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5038{
5039 int ret;
5040
5041 switch (oper) {
5042 case NL80211_TDLS_DISCOVERY_REQ:
5043 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5044 break;
5045 case NL80211_TDLS_SETUP:
5046 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5047 break;
5048 case NL80211_TDLS_TEARDOWN:
5049 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5050 break;
5051 default:
5052 brcmf_err("unsupported operation: %d\n", oper);
5053 ret = -EOPNOTSUPP;
5054 }
5055 return ret;
5056}
5057
5058static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005059 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005060 enum nl80211_tdls_operation oper)
5061{
5062 struct brcmf_if *ifp;
5063 struct brcmf_tdls_iovar_le info;
5064 int ret = 0;
5065
5066 ret = brcmf_convert_nl80211_tdls_oper(oper);
5067 if (ret < 0)
5068 return ret;
5069
5070 ifp = netdev_priv(ndev);
5071 memset(&info, 0, sizeof(info));
5072 info.mode = (u8)ret;
5073 if (peer)
5074 memcpy(info.ea, peer, ETH_ALEN);
5075
5076 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5077 &info, sizeof(info));
5078 if (ret < 0)
5079 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5080
5081 return ret;
5082}
5083
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005084static int
5085brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5086 struct net_device *ndev,
5087 struct cfg80211_connect_params *sme,
5088 u32 changed)
5089{
5090 struct brcmf_if *ifp;
5091 int err;
5092
5093 if (!(changed & UPDATE_ASSOC_IES))
5094 return 0;
5095
5096 ifp = netdev_priv(ndev);
5097 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5098 sme->ie, sme->ie_len);
5099 if (err)
5100 brcmf_err("Set Assoc REQ IE Failed\n");
5101 else
5102 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5103
5104 return err;
5105}
5106
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005107#ifdef CONFIG_PM
5108static int
5109brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5110 struct cfg80211_gtk_rekey_data *gtk)
5111{
5112 struct brcmf_if *ifp = netdev_priv(ndev);
5113 struct brcmf_gtk_keyinfo_le gtk_le;
5114 int ret;
5115
5116 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5117
5118 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5119 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5120 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5121 sizeof(gtk_le.replay_counter));
5122
5123 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5124 sizeof(gtk_le));
5125 if (ret < 0)
5126 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5127
5128 return ret;
5129}
5130#endif
5131
Arend van Spriel2526ff22017-06-09 13:08:48 +01005132static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
5133 const struct cfg80211_pmk_conf *conf)
5134{
5135 struct brcmf_if *ifp;
5136
5137 brcmf_dbg(TRACE, "enter\n");
5138
5139 /* expect using firmware supplicant for 1X */
5140 ifp = netdev_priv(dev);
5141 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5142 return -EINVAL;
5143
5144 return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
5145}
5146
5147static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
5148 const u8 *aa)
5149{
5150 struct brcmf_if *ifp;
5151
5152 brcmf_dbg(TRACE, "enter\n");
5153 ifp = netdev_priv(dev);
5154 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5155 return -EINVAL;
5156
5157 return brcmf_set_pmk(ifp, NULL, 0);
5158}
5159
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005160static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005161 .add_virtual_intf = brcmf_cfg80211_add_iface,
5162 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005163 .change_virtual_intf = brcmf_cfg80211_change_iface,
5164 .scan = brcmf_cfg80211_scan,
5165 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5166 .join_ibss = brcmf_cfg80211_join_ibss,
5167 .leave_ibss = brcmf_cfg80211_leave_ibss,
5168 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005169 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005170 .set_tx_power = brcmf_cfg80211_set_tx_power,
5171 .get_tx_power = brcmf_cfg80211_get_tx_power,
5172 .add_key = brcmf_cfg80211_add_key,
5173 .del_key = brcmf_cfg80211_del_key,
5174 .get_key = brcmf_cfg80211_get_key,
5175 .set_default_key = brcmf_cfg80211_config_default_key,
5176 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5177 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005178 .connect = brcmf_cfg80211_connect,
5179 .disconnect = brcmf_cfg80211_disconnect,
5180 .suspend = brcmf_cfg80211_suspend,
5181 .resume = brcmf_cfg80211_resume,
5182 .set_pmksa = brcmf_cfg80211_set_pmksa,
5183 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005184 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005185 .start_ap = brcmf_cfg80211_start_ap,
5186 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005187 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005188 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005189 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005190 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5191 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005192 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5193 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5194 .remain_on_channel = brcmf_p2p_remain_on_channel,
5195 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005196 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005197 .start_p2p_device = brcmf_p2p_start_device,
5198 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005199 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5200 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005201 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005202 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel2526ff22017-06-09 13:08:48 +01005203 .set_pmk = brcmf_cfg80211_set_pmk,
5204 .del_pmk = brcmf_cfg80211_del_pmk,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005205};
5206
Arend van Spriel3eacf862012-10-22 13:55:30 -07005207struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005208 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005209{
Hante Meulemana44aa402014-12-03 21:05:33 +01005210 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005211 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005212 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005213
Arend van Spriel33a6b152013-02-08 15:53:39 +01005214 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005215 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005216 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5217 if (!vif)
5218 return ERR_PTR(-ENOMEM);
5219
5220 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005221 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005222
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005223 brcmf_init_prof(&vif->profile);
5224
Hante Meulemana44aa402014-12-03 21:05:33 +01005225 if (type == NL80211_IFTYPE_AP) {
5226 mbss = false;
5227 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5228 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5229 mbss = true;
5230 break;
5231 }
5232 }
5233 vif->mbss = mbss;
5234 }
5235
Arend van Spriel3eacf862012-10-22 13:55:30 -07005236 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005237 return vif;
5238}
5239
Arend van Spriel427dec52014-01-06 12:40:47 +01005240void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005241{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005242 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005243 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005244}
5245
Arend van Spriel9df4d542014-01-06 12:40:49 +01005246void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5247{
5248 struct brcmf_cfg80211_vif *vif;
5249 struct brcmf_if *ifp;
5250
5251 ifp = netdev_priv(ndev);
5252 vif = ifp->vif;
5253
Arend van Spriel95ef1232015-08-26 22:15:04 +02005254 if (vif)
5255 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005256}
5257
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005258static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
5259 const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005260{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005261 u32 event = e->event_code;
5262 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263
Arend van Spriel2526ff22017-06-09 13:08:48 +01005264 if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
5265 event == BRCMF_E_PSK_SUP &&
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005266 status == BRCMF_E_STATUS_FWSUP_COMPLETED)
5267 set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005269 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005270 memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
5271 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
5272 return true;
5273
5274 set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005275 }
5276
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005277 if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
5278 test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
5279 clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
5280 clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
5281 return true;
5282 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005283 return false;
5284}
5285
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005286static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005287{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005288 u32 event = e->event_code;
5289 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005290
Hante Meuleman68ca3952014-02-25 20:30:26 +01005291 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5292 (event == BRCMF_E_DISASSOC_IND) ||
5293 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005294 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005295 return true;
5296 }
5297 return false;
5298}
5299
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005300static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005301 const struct brcmf_event_msg *e)
5302{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005303 u32 event = e->event_code;
5304 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005305
5306 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005307 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5308 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005309 return true;
5310 }
5311
5312 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005313 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005314 return true;
5315 }
5316
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005317 if (event == BRCMF_E_PSK_SUP &&
5318 status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
5319 brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
5320 status);
5321 return true;
5322 }
5323
Arend van Spriel5b435de2011-10-05 13:19:03 +02005324 return false;
5325}
5326
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005327static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005329 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005330
5331 kfree(conn_info->req_ie);
5332 conn_info->req_ie = NULL;
5333 conn_info->req_ie_len = 0;
5334 kfree(conn_info->resp_ie);
5335 conn_info->resp_ie = NULL;
5336 conn_info->resp_ie_len = 0;
5337}
5338
Hante Meuleman89286dc2013-02-08 15:53:46 +01005339static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5340 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005341{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005342 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005343 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005344 u32 req_len;
5345 u32 resp_len;
5346 s32 err = 0;
5347
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005348 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005349
Arend van Sprielac24be62012-10-22 10:36:23 -07005350 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5351 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005352 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005353 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005354 return err;
5355 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005356 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005357 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005358 req_len = le32_to_cpu(assoc_info->req_len);
5359 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005360 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005361 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005362 cfg->extra_buf,
5363 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005364 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005365 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005366 return err;
5367 }
5368 conn_info->req_ie_len = req_len;
5369 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005370 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005371 GFP_KERNEL);
5372 } else {
5373 conn_info->req_ie_len = 0;
5374 conn_info->req_ie = NULL;
5375 }
5376 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005377 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005378 cfg->extra_buf,
5379 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005380 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005381 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005382 return err;
5383 }
5384 conn_info->resp_ie_len = resp_len;
5385 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005386 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005387 GFP_KERNEL);
5388 } else {
5389 conn_info->resp_ie_len = 0;
5390 conn_info->resp_ie = NULL;
5391 }
Arend van Spriel16886732012-12-05 15:26:04 +01005392 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5393 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005394
5395 return err;
5396}
5397
5398static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005399brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005400 struct net_device *ndev,
5401 const struct brcmf_event_msg *e)
5402{
Arend van Sprielc1179032012-10-22 13:55:33 -07005403 struct brcmf_if *ifp = netdev_priv(ndev);
5404 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005405 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5406 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005407 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005408 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005409 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005410 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005411 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005412 u32 freq;
5413 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005414 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415
Arend van Sprield96b8012012-12-05 15:26:02 +01005416 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005417
Hante Meuleman89286dc2013-02-08 15:53:46 +01005418 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005419 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005420 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005421
Franky Lina180b832012-10-10 11:13:09 -07005422 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5423 if (buf == NULL) {
5424 err = -ENOMEM;
5425 goto done;
5426 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005427
Franky Lina180b832012-10-10 11:13:09 -07005428 /* data sent to dongle has to be little endian */
5429 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005430 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005431 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005432
5433 if (err)
5434 goto done;
5435
5436 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005437 ch.chspec = le16_to_cpu(bi->chanspec);
5438 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439
Franky Lin83cf17a2013-04-11 13:28:50 +02005440 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005441 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005442 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005443 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005444
Rafał Miłecki4712d882016-05-20 13:38:57 +02005445 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005446 notify_channel = ieee80211_get_channel(wiphy, freq);
5447
Franky Lina180b832012-10-10 11:13:09 -07005448done:
5449 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005450
5451 roam_info.channel = notify_channel;
5452 roam_info.bssid = profile->bssid;
5453 roam_info.req_ie = conn_info->req_ie;
5454 roam_info.req_ie_len = conn_info->req_ie_len;
5455 roam_info.resp_ie = conn_info->resp_ie;
5456 roam_info.resp_ie_len = conn_info->resp_ie_len;
5457
5458 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005459 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005460
Arend van Sprielc1179032012-10-22 13:55:33 -07005461 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005462 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005463 return err;
5464}
5465
5466static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005467brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005468 struct net_device *ndev, const struct brcmf_event_msg *e,
5469 bool completed)
5470{
Arend van Sprielc1179032012-10-22 13:55:33 -07005471 struct brcmf_if *ifp = netdev_priv(ndev);
5472 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005473 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel123fef32017-06-09 13:08:49 +01005474 struct cfg80211_connect_resp_params conn_params;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005475
Arend van Sprield96b8012012-12-05 15:26:02 +01005476 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005477
Arend van Sprielc1179032012-10-22 13:55:33 -07005478 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5479 &ifp->vif->sme_state)) {
Arend van Spriel123fef32017-06-09 13:08:49 +01005480 memset(&conn_params, 0, sizeof(conn_params));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005481 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005482 brcmf_get_assoc_ies(cfg, ifp);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005483 brcmf_update_bss_info(cfg, ifp);
5484 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5485 &ifp->vif->sme_state);
Arend van Spriel123fef32017-06-09 13:08:49 +01005486 conn_params.status = WLAN_STATUS_SUCCESS;
5487 } else {
5488 conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005489 }
Arend van Spriel123fef32017-06-09 13:08:49 +01005490 conn_params.bssid = profile->bssid;
5491 conn_params.req_ie = conn_info->req_ie;
5492 conn_params.req_ie_len = conn_info->req_ie_len;
5493 conn_params.resp_ie = conn_info->resp_ie;
5494 conn_params.resp_ie_len = conn_info->resp_ie_len;
5495 cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005496 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5497 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005498 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005499 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005500 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005501}
5502
5503static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005504brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005505 struct net_device *ndev,
5506 const struct brcmf_event_msg *e, void *data)
5507{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005508 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005509 u32 event = e->event_code;
5510 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005511 struct station_info sinfo;
5512
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005513 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5514 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005515 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5516 ndev != cfg_to_ndev(cfg)) {
5517 brcmf_dbg(CONN, "AP mode link down\n");
5518 complete(&cfg->vif_disabled);
5519 return 0;
5520 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005521
Hante Meuleman1a873342012-09-27 14:17:54 +02005522 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005523 (reason == BRCMF_E_STATUS_SUCCESS)) {
5524 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005525 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005526 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005527 return -EINVAL;
5528 }
5529 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005530 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005531 generation++;
5532 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005533 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005534 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5535 (event == BRCMF_E_DEAUTH_IND) ||
5536 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005537 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005538 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005539 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005540}
5541
5542static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005543brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005544 const struct brcmf_event_msg *e, void *data)
5545{
Arend van Spriel19937322012-11-05 16:22:32 -08005546 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5547 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005548 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005549 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005550 s32 err = 0;
5551
Hante Meuleman8851cce2014-07-30 13:20:02 +02005552 if ((e->event_code == BRCMF_E_DEAUTH) ||
5553 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5554 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5555 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5556 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5557 }
5558
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005559 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005560 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005561 } else if (brcmf_is_linkup(ifp->vif, e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005562 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005563 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005564 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005565 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005566 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005567 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005568 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5569 &ifp->vif->sme_state);
5570 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5571 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005572 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005573 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005574 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005575 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005576 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005577 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005578 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005579 brcmf_link_down(ifp->vif,
5580 brcmf_map_fw_linkdown_reason(e));
5581 brcmf_init_prof(ndev_to_prof(ndev));
5582 if (ndev != cfg_to_ndev(cfg))
5583 complete(&cfg->vif_disabled);
5584 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005585 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005586 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005587 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005588 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5589 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005590 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005591 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005592 }
5593
5594 return err;
5595}
5596
5597static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005598brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005599 const struct brcmf_event_msg *e, void *data)
5600{
Arend van Spriel19937322012-11-05 16:22:32 -08005601 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005602 u32 event = e->event_code;
5603 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005604
5605 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005606 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
5607 &ifp->vif->sme_state)) {
Arend van Spriel19937322012-11-05 16:22:32 -08005608 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005609 } else {
Arend van Spriel19937322012-11-05 16:22:32 -08005610 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Chung-Hsien Hsu8b943e32017-08-07 16:16:52 +08005611 brcmf_net_setcarrier(ifp, true);
5612 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005613 }
5614
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005615 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005616}
5617
5618static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005619brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005620 const struct brcmf_event_msg *e, void *data)
5621{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005622 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005623 enum nl80211_key_type key_type;
5624
5625 if (flags & BRCMF_EVENT_MSG_GROUP)
5626 key_type = NL80211_KEYTYPE_GROUP;
5627 else
5628 key_type = NL80211_KEYTYPE_PAIRWISE;
5629
Arend van Spriel19937322012-11-05 16:22:32 -08005630 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005631 NULL, GFP_KERNEL);
5632
5633 return 0;
5634}
5635
Arend van Sprield3c0b632013-02-08 15:53:37 +01005636static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5637 const struct brcmf_event_msg *e, void *data)
5638{
5639 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5640 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5641 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5642 struct brcmf_cfg80211_vif *vif;
5643
Hante Meuleman37a869e2015-10-29 20:33:17 +01005644 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005645 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005646 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005647
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005648 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005649 event->action = ifevent->action;
5650 vif = event->vif;
5651
5652 switch (ifevent->action) {
5653 case BRCMF_E_IF_ADD:
5654 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005655 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005656 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005657 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005658 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005659
5660 ifp->vif = vif;
5661 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005662 if (ifp->ndev) {
5663 vif->wdev.netdev = ifp->ndev;
5664 ifp->ndev->ieee80211_ptr = &vif->wdev;
5665 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5666 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005667 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005668 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005669 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005670
5671 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005672 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005673 /* event may not be upon user request */
5674 if (brcmf_cfg80211_vif_event_armed(cfg))
5675 wake_up(&event->vif_wq);
5676 return 0;
5677
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005678 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005679 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005680 wake_up(&event->vif_wq);
5681 return 0;
5682
Arend van Sprield3c0b632013-02-08 15:53:37 +01005683 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005684 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005685 break;
5686 }
5687 return -EINVAL;
5688}
5689
Arend van Spriel5b435de2011-10-05 13:19:03 +02005690static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5691{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005692 conf->frag_threshold = (u32)-1;
5693 conf->rts_threshold = (u32)-1;
5694 conf->retry_short = (u32)-1;
5695 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005696}
5697
Arend van Spriel5c36b992012-11-14 18:46:05 -08005698static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005699{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005700 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5701 brcmf_notify_connect_status);
5702 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5703 brcmf_notify_connect_status);
5704 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5705 brcmf_notify_connect_status);
5706 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5707 brcmf_notify_connect_status);
5708 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5709 brcmf_notify_connect_status);
5710 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5711 brcmf_notify_connect_status);
5712 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5713 brcmf_notify_roaming_status);
5714 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5715 brcmf_notify_mic_status);
5716 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5717 brcmf_notify_connect_status);
5718 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5719 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005720 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5721 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005722 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005723 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005724 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5725 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005726 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5727 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005728 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5729 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005730 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5731 brcmf_p2p_notify_action_tx_complete);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005732 brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
5733 brcmf_notify_connect_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005734}
5735
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005736static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005737{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005738 kfree(cfg->conf);
5739 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005740 kfree(cfg->extra_buf);
5741 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005742 kfree(cfg->wowl.nd);
5743 cfg->wowl.nd = NULL;
5744 kfree(cfg->wowl.nd_info);
5745 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005746 kfree(cfg->escan_info.escan_buf);
5747 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005748}
5749
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005750static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005751{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005752 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5753 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005754 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005755 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5756 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005757 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005758 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5759 if (!cfg->wowl.nd)
5760 goto init_priv_mem_out;
5761 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5762 sizeof(struct cfg80211_wowlan_nd_match *),
5763 GFP_KERNEL);
5764 if (!cfg->wowl.nd_info)
5765 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005766 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5767 if (!cfg->escan_info.escan_buf)
5768 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005769
5770 return 0;
5771
5772init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005773 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005774
5775 return -ENOMEM;
5776}
5777
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005778static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005779{
5780 s32 err = 0;
5781
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005782 cfg->scan_request = NULL;
5783 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005784 cfg->active_scan = true; /* we do active scan per default */
5785 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005786 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005787 if (err)
5788 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005789 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005790 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005791 brcmf_init_escan(cfg);
5792 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005793 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005794 return err;
5795}
5796
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005797static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005798{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005799 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005800 brcmf_abort_scanning(cfg);
5801 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005802}
5803
Arend van Sprield3c0b632013-02-08 15:53:37 +01005804static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5805{
5806 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005807 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005808}
5809
Hante Meuleman1119e232015-11-25 11:32:42 +01005810static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005811{
Hante Meuleman1119e232015-11-25 11:32:42 +01005812 s32 err;
5813 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005814 __le32 roamtrigger[2];
5815 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005816
Hante Meuleman1119e232015-11-25 11:32:42 +01005817 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005818 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005819 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5820 else
5821 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5822 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5823 if (err) {
5824 brcmf_err("bcn_timeout error (%d)\n", err);
5825 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005826 }
5827
Hante Meuleman1119e232015-11-25 11:32:42 +01005828 /* Enable/Disable built-in roaming to allow supplicant to take care of
5829 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005830 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005831 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005832 ifp->drvr->settings->roamoff ? "Off" : "On");
5833 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5834 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005835 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005836 brcmf_err("roam_off 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
Arend van Sprielf588bc02011-10-12 20:51:22 +02005840 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5841 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005842 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005843 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005844 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005845 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005846 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005847 }
5848
Arend van Sprielf588bc02011-10-12 20:51:22 +02005849 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5850 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005852 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005853 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005854 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005855 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005856 }
5857
Hante Meuleman1119e232015-11-25 11:32:42 +01005858roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005859 return err;
5860}
5861
5862static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005863brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005864{
5865 s32 err = 0;
5866
Arend van Sprielac24be62012-10-22 10:36:23 -07005867 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005868 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005869 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005870 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005871 goto dongle_scantime_out;
5872 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005873 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005874 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005875 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005876 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005877 goto dongle_scantime_out;
5878 }
5879
Arend van Sprielac24be62012-10-22 10:36:23 -07005880 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005881 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005882 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005883 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005884 goto dongle_scantime_out;
5885 }
5886
5887dongle_scantime_out:
5888 return err;
5889}
5890
Arend van Sprielb48d8912014-07-12 08:49:41 +02005891static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5892 struct brcmu_chan *ch)
5893{
5894 u32 ht40_flag;
5895
5896 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5897 if (ch->sb == BRCMU_CHAN_SB_U) {
5898 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5899 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5900 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5901 } else {
5902 /* It should be one of
5903 * IEEE80211_CHAN_NO_HT40 or
5904 * IEEE80211_CHAN_NO_HT40PLUS
5905 */
5906 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5907 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5908 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5909 }
5910}
5911
5912static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5913 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005914{
5915 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005916 struct ieee80211_supported_band *band;
5917 struct ieee80211_channel *channel;
5918 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005919 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005920 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005921 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005922 u8 *pbuf;
5923 u32 i, j;
5924 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005925 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005926
5927 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5928
5929 if (pbuf == NULL)
5930 return -ENOMEM;
5931
5932 list = (struct brcmf_chanspec_list *)pbuf;
5933
5934 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5935 BRCMF_DCMD_MEDLEN);
5936 if (err) {
5937 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005938 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005939 }
5940
Arend van Sprielb48d8912014-07-12 08:49:41 +02005941 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005942 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005943 if (band)
5944 for (i = 0; i < band->n_channels; i++)
5945 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005946 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005947 if (band)
5948 for (i = 0; i < band->n_channels; i++)
5949 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005950
5951 total = le32_to_cpu(list->count);
5952 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005953 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5954 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005955
Franky Lin83cf17a2013-04-11 13:28:50 +02005956 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005957 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005958 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005959 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005960 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005961 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005962 continue;
5963 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005964 if (!band)
5965 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005966 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005967 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005968 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005969 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005970 ch.bw == BRCMU_CHAN_BW_80)
5971 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005972
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005973 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005974 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005975 if (band->channels[j].hw_value == ch.control_ch_num) {
5976 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02005977 break;
5978 }
5979 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005980 if (!channel) {
5981 /* It seems firmware supports some channel we never
5982 * considered. Something new in IEEE standard?
5983 */
5984 brcmf_err("Ignoring unexpected firmware channel %d\n",
5985 ch.control_ch_num);
5986 continue;
5987 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005988
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01005989 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
5990 continue;
5991
Arend van Sprielb48d8912014-07-12 08:49:41 +02005992 /* assuming the chanspecs order is HT20,
5993 * HT40 upper, HT40 lower, and VHT80.
5994 */
5995 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005996 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005997 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005998 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005999 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02006000 /* enable the channel and disable other bandwidths
6001 * for now as mentioned order assure they are enabled
6002 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02006003 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006004 channel->flags = IEEE80211_CHAN_NO_HT40 |
6005 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006006 ch.bw = BRCMU_CHAN_BW_20;
6007 cfg->d11inf.encchspec(&ch);
6008 chaninfo = ch.chspec;
6009 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
6010 &chaninfo);
6011 if (!err) {
6012 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006013 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006014 (IEEE80211_CHAN_RADAR |
6015 IEEE80211_CHAN_NO_IR);
6016 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006017 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006018 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006019 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006020 }
6021 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006022
Arend van Sprielb48d8912014-07-12 08:49:41 +02006023fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006024 kfree(pbuf);
6025 return err;
6026}
6027
Arend van Sprielb48d8912014-07-12 08:49:41 +02006028static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006029{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006030 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6031 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006032 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006033 struct brcmf_chanspec_list *list;
6034 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006035 u32 val;
6036 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006037 struct brcmu_chan ch;
6038 u32 num_chan;
6039 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006040
6041 /* verify support for bw_cap command */
6042 val = WLC_BAND_5G;
6043 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6044
6045 if (!err) {
6046 /* only set 2G bandwidth using bw_cap command */
6047 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6048 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6049 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6050 sizeof(band_bwcap));
6051 } else {
6052 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6053 val = WLC_N_BW_40ALL;
6054 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6055 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006056
6057 if (!err) {
6058 /* update channel info in 2G band */
6059 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6060
6061 if (pbuf == NULL)
6062 return -ENOMEM;
6063
6064 ch.band = BRCMU_CHAN_BAND_2G;
6065 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006066 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006067 ch.chnum = 0;
6068 cfg->d11inf.encchspec(&ch);
6069
6070 /* pass encoded chanspec in query */
6071 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6072
6073 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6074 BRCMF_DCMD_MEDLEN);
6075 if (err) {
6076 brcmf_err("get chanspecs error (%d)\n", err);
6077 kfree(pbuf);
6078 return err;
6079 }
6080
Johannes Berg57fbcce2016-04-12 15:56:15 +02006081 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006082 list = (struct brcmf_chanspec_list *)pbuf;
6083 num_chan = le32_to_cpu(list->count);
6084 for (i = 0; i < num_chan; i++) {
6085 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6086 cfg->d11inf.decchspec(&ch);
6087 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6088 continue;
6089 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6090 continue;
6091 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006092 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006093 break;
6094 }
6095 if (WARN_ON(j == band->n_channels))
6096 continue;
6097
6098 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6099 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006100 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006101 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006102 return err;
6103}
6104
Arend van Spriel2375d972014-01-06 12:40:41 +01006105static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6106{
6107 u32 band, mimo_bwcap;
6108 int err;
6109
6110 band = WLC_BAND_2G;
6111 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6112 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006113 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006114 band = WLC_BAND_5G;
6115 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6116 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006117 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006118 return;
6119 }
6120 WARN_ON(1);
6121 return;
6122 }
6123 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6124 mimo_bwcap = 0;
6125 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6126 if (err)
6127 /* assume 20MHz if firmware does not give a clue */
6128 mimo_bwcap = WLC_N_BW_20ALL;
6129
6130 switch (mimo_bwcap) {
6131 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006132 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006133 /* fall-thru */
6134 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006135 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006136 /* fall-thru */
6137 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006138 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6139 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006140 break;
6141 default:
6142 brcmf_err("invalid mimo_bw_cap value\n");
6143 }
6144}
Hante Meulemand48200b2013-04-03 12:40:29 +02006145
Arend van Spriel18d6c532014-05-12 10:47:35 +02006146static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6147 u32 bw_cap[2], u32 nchain)
6148{
6149 band->ht_cap.ht_supported = true;
6150 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6151 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6152 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6153 }
6154 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6155 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6156 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6157 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6158 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6159 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6160}
6161
6162static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6163{
6164 u16 mcs_map;
6165 int i;
6166
6167 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6168 mcs_map = (mcs_map << 2) | supp;
6169
6170 return cpu_to_le16(mcs_map);
6171}
6172
6173static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006174 u32 bw_cap[2], u32 nchain, u32 txstreams,
6175 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006176{
6177 __le16 mcs_map;
6178
6179 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006180 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006181 return;
6182
6183 band->vht_cap.vht_supported = true;
6184 /* 80MHz is mandatory */
6185 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6186 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6187 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6188 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6189 }
6190 /* all support 256-QAM */
6191 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6192 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6193 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006194
6195 /* Beamforming support information */
6196 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6197 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6198 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6199 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6200 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6201 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6202 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6203 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6204
6205 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6206 band->vht_cap.cap |=
6207 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6208 band->vht_cap.cap |= ((txstreams - 1) <<
6209 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6210 band->vht_cap.cap |=
6211 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6212 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006213}
6214
Arend van Sprielb48d8912014-07-12 08:49:41 +02006215static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006216{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006217 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006218 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006219 u32 nmode = 0;
6220 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006221 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006222 u32 rxchain;
6223 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006224 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006225 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006226 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006227 u32 txstreams = 0;
6228 u32 txbf_bfe_cap = 0;
6229 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006230
Arend van Spriel18d6c532014-05-12 10:47:35 +02006231 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006232 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6233 if (err) {
6234 brcmf_err("nmode error (%d)\n", err);
6235 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006236 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006237 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006238 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006239 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6240 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006241
Daniel Kim4aca7a12014-02-25 20:30:36 +01006242 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6243 if (err) {
6244 brcmf_err("rxchain error (%d)\n", err);
6245 nchain = 1;
6246 } else {
6247 for (nchain = 0; rxchain; nchain++)
6248 rxchain = rxchain & (rxchain - 1);
6249 }
6250 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6251
Arend van Sprielb48d8912014-07-12 08:49:41 +02006252 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006253 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006254 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006255 return err;
6256 }
6257
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006258 if (vhtmode) {
6259 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6260 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6261 &txbf_bfe_cap);
6262 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6263 &txbf_bfr_cap);
6264 }
6265
Arend van Sprielb48d8912014-07-12 08:49:41 +02006266 wiphy = cfg_to_wiphy(cfg);
6267 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6268 band = wiphy->bands[i];
6269 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006270 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006271
Arend van Spriel18d6c532014-05-12 10:47:35 +02006272 if (nmode)
6273 brcmf_update_ht_cap(band, bw_cap, nchain);
6274 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006275 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6276 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006277 }
6278
Arend van Sprielb48d8912014-07-12 08:49:41 +02006279 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006280}
6281
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006282static const struct ieee80211_txrx_stypes
6283brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6284 [NL80211_IFTYPE_STATION] = {
6285 .tx = 0xffff,
6286 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6287 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6288 },
6289 [NL80211_IFTYPE_P2P_CLIENT] = {
6290 .tx = 0xffff,
6291 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6292 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6293 },
6294 [NL80211_IFTYPE_P2P_GO] = {
6295 .tx = 0xffff,
6296 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6297 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6298 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6299 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6300 BIT(IEEE80211_STYPE_AUTH >> 4) |
6301 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6302 BIT(IEEE80211_STYPE_ACTION >> 4)
6303 },
6304 [NL80211_IFTYPE_P2P_DEVICE] = {
6305 .tx = 0xffff,
6306 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6307 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6308 }
6309};
6310
Arend van Spriel0882dda2015-08-20 22:06:03 +02006311/**
6312 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6313 *
6314 * @wiphy: wiphy object.
6315 * @ifp: interface object needed for feat module api.
6316 *
6317 * The interface modes and combinations are determined dynamically here
6318 * based on firmware functionality.
6319 *
6320 * no p2p and no mbss:
6321 *
6322 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6323 *
6324 * no p2p and mbss:
6325 *
6326 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6327 * #AP <= 4, matching BI, channels = 1, 4 total
6328 *
6329 * p2p, no mchan, and mbss:
6330 *
6331 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6332 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6333 * #AP <= 4, matching BI, channels = 1, 4 total
6334 *
6335 * p2p, mchan, and mbss:
6336 *
6337 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6338 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6339 * #AP <= 4, matching BI, channels = 1, 4 total
6340 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006341static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6342{
6343 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006344 struct ieee80211_iface_limit *c0_limits = NULL;
6345 struct ieee80211_iface_limit *p2p_limits = NULL;
6346 struct ieee80211_iface_limit *mbss_limits = NULL;
6347 bool mbss, p2p;
6348 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006349
Arend van Spriel0882dda2015-08-20 22:06:03 +02006350 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6351 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6352
6353 n_combos = 1 + !!p2p + !!mbss;
6354 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006355 if (!combo)
6356 goto err;
6357
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006358 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6359 BIT(NL80211_IFTYPE_ADHOC) |
6360 BIT(NL80211_IFTYPE_AP);
6361
Arend van Spriel0882dda2015-08-20 22:06:03 +02006362 c = 0;
6363 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006364 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6365 if (!c0_limits)
6366 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006367 c0_limits[i].max = 1;
6368 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6369 if (p2p) {
6370 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6371 combo[c].num_different_channels = 2;
Wright Feng99976fc2017-08-03 17:37:59 +08006372 else
6373 combo[c].num_different_channels = 1;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006374 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6375 BIT(NL80211_IFTYPE_P2P_GO) |
6376 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006377 c0_limits[i].max = 1;
6378 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6379 c0_limits[i].max = 1;
6380 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6381 BIT(NL80211_IFTYPE_P2P_GO);
6382 } else {
Wright Feng99976fc2017-08-03 17:37:59 +08006383 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006384 c0_limits[i].max = 1;
6385 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006386 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006387 combo[c].max_interfaces = i;
6388 combo[c].n_limits = i;
6389 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006390
Arend van Spriel0882dda2015-08-20 22:06:03 +02006391 if (p2p) {
6392 c++;
6393 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006394 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6395 if (!p2p_limits)
6396 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006397 p2p_limits[i].max = 1;
6398 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6399 p2p_limits[i].max = 1;
6400 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6401 p2p_limits[i].max = 1;
6402 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6403 p2p_limits[i].max = 1;
6404 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006405 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006406 combo[c].max_interfaces = i;
6407 combo[c].n_limits = i;
6408 combo[c].limits = p2p_limits;
6409 }
6410
6411 if (mbss) {
6412 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006413 i = 0;
6414 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6415 if (!mbss_limits)
6416 goto err;
6417 mbss_limits[i].max = 4;
6418 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006419 combo[c].beacon_int_infra_match = true;
6420 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006421 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006422 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006423 combo[c].limits = mbss_limits;
6424 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006425
Arend van Spriel0882dda2015-08-20 22:06:03 +02006426 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006427 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006428 return 0;
6429
6430err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006431 kfree(c0_limits);
6432 kfree(p2p_limits);
6433 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006434 kfree(combo);
6435 return -ENOMEM;
6436}
6437
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006438#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006439static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006440 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006441 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6442 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6443 .pattern_min_len = 1,
6444 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006445};
6446#endif
6447
Hante Meuleman3021ad92016-01-05 11:05:45 +01006448static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006449{
6450#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006451 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006452 struct wiphy_wowlan_support *wowl;
6453
6454 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6455 GFP_KERNEL);
6456 if (!wowl) {
6457 brcmf_err("only support basic wowlan features\n");
6458 wiphy->wowlan = &brcmf_wowlan_support;
6459 return;
6460 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006461
6462 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006463 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006464 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6465 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006466 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006467 }
6468 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006469 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006470 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6471 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006472 }
6473
Arend Van Spriel0b570102017-01-27 12:27:47 +00006474 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006475#endif
6476}
6477
Arend van Sprielb48d8912014-07-12 08:49:41 +02006478static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006479{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006480 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006481 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006482 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006483 u16 max_interfaces = 0;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006484 bool gscan;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006485 __le32 bandlist[3];
6486 u32 n_bands;
6487 int err, i;
6488
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006489 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6490 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006491 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006492
6493 err = brcmf_setup_ifmodes(wiphy, ifp);
6494 if (err)
6495 return err;
6496
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006497 for (i = 0, combo = wiphy->iface_combinations;
6498 i < wiphy->n_iface_combinations; i++, combo++) {
6499 max_interfaces = max(max_interfaces, combo->max_interfaces);
6500 }
6501
6502 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6503 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006504 u8 *addr = drvr->addresses[i].addr;
6505
6506 memcpy(addr, drvr->mac, ETH_ALEN);
6507 if (i) {
6508 addr[0] |= BIT(1);
6509 addr[ETH_ALEN - 1] ^= i;
6510 }
6511 }
6512 wiphy->addresses = drvr->addresses;
6513 wiphy->n_addresses = i;
6514
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006515 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006516 wiphy->cipher_suites = brcmf_cipher_suites;
6517 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6518 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6519 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006520 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6521 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6522 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6523
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006524 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6525 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006526 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006527 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6528 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6529 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006530 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006531 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
Arend van Spriel2526ff22017-06-09 13:08:48 +01006532 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01006533 wiphy_ext_feature_set(wiphy,
6534 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
Arend van Spriel2526ff22017-06-09 13:08:48 +01006535 wiphy_ext_feature_set(wiphy,
6536 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
6537 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006538 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6539 wiphy->max_remain_on_channel_duration = 5000;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006540 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
6541 gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
6542 brcmf_pno_wiphy_params(wiphy, gscan);
6543 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006544 /* vendor commands/events support */
6545 wiphy->vendor_commands = brcmf_vendor_cmds;
6546 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6547
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006548 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006549 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006550 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6551 sizeof(bandlist));
6552 if (err) {
6553 brcmf_err("could not obtain band info: err=%d\n", err);
6554 return err;
6555 }
6556 /* first entry in bandlist is number of bands */
6557 n_bands = le32_to_cpu(bandlist[0]);
6558 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6559 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6560 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6561 GFP_KERNEL);
6562 if (!band)
6563 return -ENOMEM;
6564
6565 band->channels = kmemdup(&__wl_2ghz_channels,
6566 sizeof(__wl_2ghz_channels),
6567 GFP_KERNEL);
6568 if (!band->channels) {
6569 kfree(band);
6570 return -ENOMEM;
6571 }
6572
6573 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006574 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006575 }
6576 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6577 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6578 GFP_KERNEL);
6579 if (!band)
6580 return -ENOMEM;
6581
6582 band->channels = kmemdup(&__wl_5ghz_channels,
6583 sizeof(__wl_5ghz_channels),
6584 GFP_KERNEL);
6585 if (!band->channels) {
6586 kfree(band);
6587 return -ENOMEM;
6588 }
6589
6590 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006591 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006592 }
6593 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006594
6595 wiphy_read_of_freq_limits(wiphy);
6596
Rafał Miłeckiab990632017-01-07 21:36:05 +01006597 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006598}
6599
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006600static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006601{
6602 struct net_device *ndev;
6603 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006604 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006605 s32 power_mode;
6606 s32 err = 0;
6607
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006608 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006609 return err;
6610
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006611 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006612 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006613 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006614
Hante Meuleman40a23292013-01-02 15:22:51 +01006615 /* make sure RF is ready for work */
6616 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6617
Hante Meuleman1678ba82015-12-10 13:43:00 +01006618 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006619
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006620 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006621 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006622 if (err)
6623 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006624 brcmf_dbg(INFO, "power save set to %s\n",
6625 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006626
Hante Meuleman1119e232015-11-25 11:32:42 +01006627 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006628 if (err)
6629 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006630 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006631 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006632 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006633 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006634
Franky Lin52f22fb2016-02-17 11:26:55 +01006635 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006636
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006637 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006638default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006639
6640 return err;
6641
6642}
6643
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006644static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006645{
Arend van Sprielc1179032012-10-22 13:55:33 -07006646 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006647
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006648 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006649}
6650
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006651static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006652{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006653 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006654
Arend van Spriel5b435de2011-10-05 13:19:03 +02006655 /*
6656 * While going down, if associated with AP disassociate
6657 * from AP to save power
6658 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006659 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006660 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006661
6662 /* Make sure WPA_Supplicant receives all the event
6663 generated due to DISASSOC call to the fw to keep
6664 the state fw and WPA_Supplicant state consistent
6665 */
6666 brcmf_delay(500);
6667 }
6668
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006669 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006670 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006671
Arend van Spriel5b435de2011-10-05 13:19:03 +02006672 return 0;
6673}
6674
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006675s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006676{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006677 struct brcmf_if *ifp = netdev_priv(ndev);
6678 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006679 s32 err = 0;
6680
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006681 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006682 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006683 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006684
6685 return err;
6686}
6687
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006688s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006689{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006690 struct brcmf_if *ifp = netdev_priv(ndev);
6691 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006692 s32 err = 0;
6693
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006694 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006695 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006696 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006697
6698 return err;
6699}
6700
Arend van Spriela7965fb2013-04-11 17:08:37 +02006701enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6702{
6703 struct wireless_dev *wdev = &ifp->vif->wdev;
6704
6705 return wdev->iftype;
6706}
6707
Hante Meulemanbfe81972014-10-28 14:56:16 +01006708bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6709 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006710{
6711 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006712
6713 list_for_each_entry(vif, &cfg->vif_list, list) {
6714 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006715 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006716 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006717 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006718}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006719
6720static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6721 u8 action)
6722{
6723 u8 evt_action;
6724
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006725 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006726 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006727 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006728 return evt_action == action;
6729}
6730
6731void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6732 struct brcmf_cfg80211_vif *vif)
6733{
6734 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6735
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006736 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006737 event->vif = vif;
6738 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006739 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006740}
6741
6742bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6743{
6744 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6745 bool armed;
6746
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006747 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006748 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006749 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006750
6751 return armed;
6752}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006753
6754int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6755 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006756{
6757 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6758
6759 return wait_event_timeout(event->vif_wq,
6760 vif_event_equals(event, action), timeout);
6761}
6762
Hante Meuleman73345fd2016-02-17 11:26:53 +01006763static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6764 struct brcmf_fil_country_le *ccreq)
6765{
Hante Meuleman4d792892016-02-17 11:27:07 +01006766 struct brcmfmac_pd_cc *country_codes;
6767 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006768 s32 found_index;
6769 int i;
6770
6771 country_codes = drvr->settings->country_codes;
6772 if (!country_codes) {
6773 brcmf_dbg(TRACE, "No country codes configured for device\n");
6774 return -EINVAL;
6775 }
6776
6777 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6778 (alpha2[1] == ccreq->country_abbrev[1])) {
6779 brcmf_dbg(TRACE, "Country code already set\n");
6780 return -EAGAIN;
6781 }
6782
6783 found_index = -1;
6784 for (i = 0; i < country_codes->table_size; i++) {
6785 cc = &country_codes->table[i];
6786 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6787 found_index = i;
6788 if ((cc->iso3166[0] == alpha2[0]) &&
6789 (cc->iso3166[1] == alpha2[1])) {
6790 found_index = i;
6791 break;
6792 }
6793 }
6794 if (found_index == -1) {
6795 brcmf_dbg(TRACE, "No country code match found\n");
6796 return -EINVAL;
6797 }
6798 memset(ccreq, 0, sizeof(*ccreq));
6799 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6800 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6801 BRCMF_COUNTRY_BUF_SZ);
6802 ccreq->country_abbrev[0] = alpha2[0];
6803 ccreq->country_abbrev[1] = alpha2[1];
6804 ccreq->country_abbrev[2] = 0;
6805
6806 return 0;
6807}
6808
Arend van Spriel63db1a42014-12-21 12:43:51 +01006809static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6810 struct regulatory_request *req)
6811{
6812 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6813 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6814 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006815 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006816 int i;
6817
Hans de Goede26e537882017-03-08 14:50:16 +01006818 /* The country code gets set to "00" by default at boot, ignore */
6819 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6820 return;
6821
Arend van Spriel63db1a42014-12-21 12:43:51 +01006822 /* ignore non-ISO3166 country codes */
6823 for (i = 0; i < sizeof(req->alpha2); i++)
6824 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Martin Michlmayra9507d52017-06-10 11:40:04 +02006825 brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
Hante Meuleman73345fd2016-02-17 11:26:53 +01006826 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006827 return;
6828 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006829
6830 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6831 req->alpha2[0], req->alpha2[1]);
6832
6833 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6834 if (err) {
6835 brcmf_err("Country code iovar returned err = %d\n", err);
6836 return;
6837 }
6838
6839 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6840 if (err)
6841 return;
6842
6843 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6844 if (err) {
6845 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006846 return;
6847 }
6848 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006849}
6850
Arend van Sprielb48d8912014-07-12 08:49:41 +02006851static void brcmf_free_wiphy(struct wiphy *wiphy)
6852{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006853 int i;
6854
Arend van Spriel58de92d2015-04-14 20:10:24 +02006855 if (!wiphy)
6856 return;
6857
Arend van Spriel0882dda2015-08-20 22:06:03 +02006858 if (wiphy->iface_combinations) {
6859 for (i = 0; i < wiphy->n_iface_combinations; i++)
6860 kfree(wiphy->iface_combinations[i].limits);
6861 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006862 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006863 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6864 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6865 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006866 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006867 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6868 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6869 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006870 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006871#if IS_ENABLED(CONFIG_PM)
6872 if (wiphy->wowlan != &brcmf_wowlan_support)
6873 kfree(wiphy->wowlan);
6874#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006875 wiphy_free(wiphy);
6876}
6877
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006878struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006879 struct device *busdev,
6880 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006881{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006882 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006883 struct brcmf_cfg80211_info *cfg;
6884 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006885 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006886 struct brcmf_cfg80211_vif *vif;
6887 struct brcmf_if *ifp;
6888 s32 err = 0;
6889 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006890 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006891
6892 if (!ndev) {
6893 brcmf_err("ndev is invalid\n");
6894 return NULL;
6895 }
6896
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306897 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006898 if (!ops)
6899 return NULL;
6900
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006901 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006902#ifdef CONFIG_PM
6903 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6904 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6905#endif
6906 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006907 if (!wiphy) {
6908 brcmf_err("Could not allocate wiphy device\n");
Christophe Jaillet57c00f22017-06-21 07:45:53 +02006909 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006910 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006911 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006912 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006913
6914 cfg = wiphy_priv(wiphy);
6915 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006916 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006917 cfg->pub = drvr;
6918 init_vif_event(&cfg->vif_event);
6919 INIT_LIST_HEAD(&cfg->vif_list);
6920
Rafał Miłecki26072332016-06-06 23:03:55 +02006921 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006922 if (IS_ERR(vif))
6923 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006924
6925 vif->ifp = ifp;
6926 vif->wdev.netdev = ndev;
6927 ndev->ieee80211_ptr = &vif->wdev;
6928 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6929
6930 err = wl_init_priv(cfg);
6931 if (err) {
6932 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006933 brcmf_free_vif(vif);
6934 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006935 }
6936 ifp->vif = vif;
6937
Arend van Sprielb48d8912014-07-12 08:49:41 +02006938 /* determine d11 io type before wiphy setup */
6939 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006940 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006941 brcmf_err("Failed to get D11 version (%d)\n", err);
6942 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006943 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006944 cfg->d11inf.io_type = (u8)io_type;
6945 brcmu_d11_attach(&cfg->d11inf);
6946
6947 err = brcmf_setup_wiphy(wiphy, ifp);
6948 if (err < 0)
6949 goto priv_out;
6950
6951 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006952 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006953 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6954 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6955
6956 /* firmware defaults to 40MHz disabled in 2G band. We signal
6957 * cfg80211 here that we do and have it decide we can enable
6958 * it. But first check if device does support 2G operation.
6959 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006960 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6961 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006962 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6963 }
6964 err = wiphy_register(wiphy);
6965 if (err < 0) {
6966 brcmf_err("Could not register wiphy device (%d)\n", err);
6967 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006968 }
6969
Rafał Miłeckiab990632017-01-07 21:36:05 +01006970 err = brcmf_setup_wiphybands(wiphy);
6971 if (err) {
6972 brcmf_err("Setting wiphy bands failed (%d)\n", err);
6973 goto wiphy_unreg_out;
6974 }
6975
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006976 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6977 * setup 40MHz in 2GHz band and enable OBSS scanning.
6978 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006979 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6980 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006981 if (!err)
6982 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6983 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006984 else
6985 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006986 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006987 /* p2p might require that "if-events" get processed by fweh. So
6988 * activate the already registered event handlers now and activate
6989 * the rest when initialization has completed. drvr->config needs to
6990 * be assigned before activating events.
6991 */
6992 drvr->config = cfg;
6993 err = brcmf_fweh_activate_events(ifp);
6994 if (err) {
6995 brcmf_err("FWEH activation failed (%d)\n", err);
6996 goto wiphy_unreg_out;
6997 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006998
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006999 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007000 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007001 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007002 goto wiphy_unreg_out;
7003 }
7004 err = brcmf_btcoex_attach(cfg);
7005 if (err) {
7006 brcmf_err("BT-coex initialisation failed (%d)\n", err);
7007 brcmf_p2p_detach(&cfg->p2p);
7008 goto wiphy_unreg_out;
7009 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007010 err = brcmf_pno_attach(cfg);
7011 if (err) {
7012 brcmf_err("PNO initialisation failed (%d)\n", err);
7013 brcmf_btcoex_detach(cfg);
7014 brcmf_p2p_detach(&cfg->p2p);
7015 goto wiphy_unreg_out;
7016 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007017
Hante Meulemana7b82d42015-12-10 13:43:04 +01007018 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
7019 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
7020 if (err) {
7021 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
7022 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
7023 } else {
7024 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
7025 brcmf_notify_tdls_peer_event);
7026 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007027 }
7028
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007029 /* (re-) activate FWEH event handling */
7030 err = brcmf_fweh_activate_events(ifp);
7031 if (err) {
7032 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007033 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007034 }
7035
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007036 /* Fill in some of the advertised nl80211 supported features */
7037 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7038 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7039#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007040 if (wiphy->wowlan &&
7041 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007042 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7043#endif
7044 }
7045
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007046 return cfg;
7047
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007048detach:
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007049 brcmf_pno_detach(cfg);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007050 brcmf_btcoex_detach(cfg);
7051 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007052wiphy_unreg_out:
7053 wiphy_unregister(cfg->wiphy);
7054priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007055 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007056 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007057 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007058wiphy_out:
7059 brcmf_free_wiphy(wiphy);
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007060ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007061 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007062 return NULL;
7063}
7064
7065void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7066{
7067 if (!cfg)
7068 return;
7069
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007070 brcmf_pno_detach(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007071 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007072 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007073 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007074 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007075 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007076}