blob: 7e689c86d56576cf96ca755b16107216470fccdf [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Franky Lin1bacb042014-06-21 12:11:16 +020022#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020024#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
Hante Meuleman122d3d02014-10-28 14:56:18 +010029#include "core.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010030#include "debug.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020031#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010032#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010033#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020034#include "btcoex.h"
Arend Van Sprielac551362016-11-23 10:25:22 +000035#include "pno.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010036#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020037#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070038#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020039#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020040#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010041#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010042#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020043
Arend van Spriele5806072012-09-19 22:21:08 +020044#define BRCMF_SCAN_IE_LEN_MAX 2048
Arend van Spriele5806072012-09-19 22:21:08 +020045
Hante Meuleman1a873342012-09-27 14:17:54 +020046#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
47#define WPA_OUI_TYPE 1
48#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
49#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010050#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020051
52#define VS_IE_FIXED_HDR_LEN 6
53#define WPA_IE_VERSION_LEN 2
54#define WPA_IE_MIN_OUI_LEN 4
55#define WPA_IE_SUITE_COUNT_LEN 2
56
57#define WPA_CIPHER_NONE 0 /* None */
58#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
59#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
60#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
61#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
62
63#define RSN_AKM_NONE 0 /* None (IBSS) */
64#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
65#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010066#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
67#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020068#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010069#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
70#define RSN_CAP_MFPR_MASK BIT(6)
71#define RSN_CAP_MFPC_MASK BIT(7)
72#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020073
74#define VNDR_IE_CMD_LEN 4 /* length of the set command
75 * string :"add", "del" (+ NUL)
76 */
77#define VNDR_IE_COUNT_OFFSET 4
78#define VNDR_IE_PKTFLAG_OFFSET 8
79#define VNDR_IE_VSIE_OFFSET 12
80#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010081#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
84#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020085
Hante Meuleman89286dc2013-02-08 15:53:46 +010086#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
87#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
88#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
89
Hante Meuleman1678ba82015-12-10 13:43:00 +010090#define BRCMF_SCAN_CHANNEL_TIME 40
91#define BRCMF_SCAN_UNASSOC_TIME 40
92#define BRCMF_SCAN_PASSIVE_TIME 120
93
Hante Meuleman3021ad92016-01-05 11:05:45 +010094#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
95
Arend van Spriel5b435de2011-10-05 13:19:03 +020096#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
97 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
98
Arend van Sprielce81e312012-10-22 13:55:37 -070099static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200100{
Arend van Sprielc1179032012-10-22 13:55:33 -0700101 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100102 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
103 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200104 return false;
105 }
106 return true;
107}
108
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
110#define RATETAB_ENT(_rateid, _flags) \
111 { \
112 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
113 .hw_value = (_rateid), \
114 .flags = (_flags), \
115 }
116
117static struct ieee80211_rate __wl_rates[] = {
118 RATETAB_ENT(BRCM_RATE_1M, 0),
119 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
120 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
121 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
122 RATETAB_ENT(BRCM_RATE_6M, 0),
123 RATETAB_ENT(BRCM_RATE_9M, 0),
124 RATETAB_ENT(BRCM_RATE_12M, 0),
125 RATETAB_ENT(BRCM_RATE_18M, 0),
126 RATETAB_ENT(BRCM_RATE_24M, 0),
127 RATETAB_ENT(BRCM_RATE_36M, 0),
128 RATETAB_ENT(BRCM_RATE_48M, 0),
129 RATETAB_ENT(BRCM_RATE_54M, 0),
130};
131
Arend van Spriel5b435de2011-10-05 13:19:03 +0200132#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200133#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
134#define wl_a_rates (__wl_rates + 4)
135#define wl_a_rates_size (wl_g_rates_size - 4)
136
137#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200138 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200139 .center_freq = (_freq), \
140 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200141 .max_antenna_gain = 0, \
142 .max_power = 30, \
143}
144
145#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200146 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200147 .center_freq = 5000 + (5 * (_channel)), \
148 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200149 .max_antenna_gain = 0, \
150 .max_power = 30, \
151}
152
153static struct ieee80211_channel __wl_2ghz_channels[] = {
154 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
155 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
156 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
157 CHAN2G(13, 2472), CHAN2G(14, 2484)
158};
159
160static struct ieee80211_channel __wl_5ghz_channels[] = {
161 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
162 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
163 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
164 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
165 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
166 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
167};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200168
Arend van Sprielb48d8912014-07-12 08:49:41 +0200169/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200170 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200171 */
172static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200173 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200174 .bitrates = wl_g_rates,
175 .n_bitrates = wl_g_rates_size,
176};
177
Arend van Spriel58de92d2015-04-14 20:10:24 +0200178static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200179 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180 .bitrates = wl_a_rates,
181 .n_bitrates = wl_a_rates_size,
182};
183
Hante Meulemand48200b2013-04-03 12:40:29 +0200184/* This is to override regulatory domains defined in cfg80211 module (reg.c)
185 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200186 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
187 * With respect to these flags, wpa_supplicant doesn't * start p2p
188 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200189 * domain are to be done here.
190 */
191static const struct ieee80211_regdomain brcmf_regdom = {
192 .n_reg_rules = 4,
193 .alpha2 = "99",
194 .reg_rules = {
195 /* IEEE 802.11b/g, channels 1..11 */
196 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
197 /* If any */
198 /* IEEE 802.11 channel 14 - Only JP enables
199 * this and for 802.11b only
200 */
201 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
202 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200203 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200204 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200205 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200206};
207
Hante Meuleman240d61a2016-02-17 11:27:10 +0100208/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
209 * are supported. A pointer to this array and the number of entries is passed
210 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
211 * So the cipher suite AES_CMAC has to be the last one in the array, and when
212 * device does not support MFP then the number of suites will be decreased by 1
213 */
214static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200215 WLAN_CIPHER_SUITE_WEP40,
216 WLAN_CIPHER_SUITE_WEP104,
217 WLAN_CIPHER_SUITE_TKIP,
218 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219 /* Keep as last entry: */
220 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200221};
222
Hante Meuleman1a873342012-09-27 14:17:54 +0200223/* Vendor specific ie. id = 221, oui and type defines exact ie */
224struct brcmf_vs_tlv {
225 u8 id;
226 u8 len;
227 u8 oui[3];
228 u8 oui_type;
229};
230
231struct parsed_vndr_ie_info {
232 u8 *ie_ptr;
233 u32 ie_len; /* total length including id & length field */
234 struct brcmf_vs_tlv vndrie;
235};
236
237struct parsed_vndr_ies {
238 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100239 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200240};
241
Arend van Spriel7705ba62016-04-17 16:44:58 +0200242static u8 nl80211_band_to_fwil(enum nl80211_band band)
243{
244 switch (band) {
245 case NL80211_BAND_2GHZ:
246 return WLC_BAND_2G;
247 case NL80211_BAND_5GHZ:
248 return WLC_BAND_5G;
249 default:
250 WARN_ON(1);
251 break;
252 }
253 return 0;
254}
255
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200256static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
257 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200258{
259 struct brcmu_chan ch_inf;
260 s32 primary_offset;
261
262 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
263 ch->chan->center_freq, ch->center_freq1, ch->width);
264 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100265 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200266 switch (ch->width) {
267 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100268 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200269 ch_inf.bw = BRCMU_CHAN_BW_20;
270 WARN_ON(primary_offset != 0);
271 break;
272 case NL80211_CHAN_WIDTH_40:
273 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100274 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200275 ch_inf.sb = BRCMU_CHAN_SB_U;
276 else
277 ch_inf.sb = BRCMU_CHAN_SB_L;
278 break;
279 case NL80211_CHAN_WIDTH_80:
280 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100281 if (primary_offset == -30)
282 ch_inf.sb = BRCMU_CHAN_SB_LL;
283 else if (primary_offset == -10)
284 ch_inf.sb = BRCMU_CHAN_SB_LU;
285 else if (primary_offset == 10)
286 ch_inf.sb = BRCMU_CHAN_SB_UL;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200289 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100290 case NL80211_CHAN_WIDTH_80P80:
291 case NL80211_CHAN_WIDTH_160:
292 case NL80211_CHAN_WIDTH_5:
293 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200294 default:
295 WARN_ON_ONCE(1);
296 }
297 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200298 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200299 ch_inf.band = BRCMU_CHAN_BAND_2G;
300 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200301 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200302 ch_inf.band = BRCMU_CHAN_BAND_5G;
303 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200304 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 d11inf->encchspec(&ch_inf);
309
310 return ch_inf.chspec;
311}
312
Franky Lin83cf17a2013-04-11 13:28:50 +0200313u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
314 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700315{
Franky Lin83cf17a2013-04-11 13:28:50 +0200316 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700317
Franky Lin83cf17a2013-04-11 13:28:50 +0200318 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
319 ch_inf.bw = BRCMU_CHAN_BW_20;
320 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700321
Franky Lin83cf17a2013-04-11 13:28:50 +0200322 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700323}
324
Hante Meuleman89286dc2013-02-08 15:53:46 +0100325/* Traverse a string of 1-byte tag/1-byte length/variable-length value
326 * triples, returning a pointer to the substring whose first element
327 * matches tag
328 */
Rafał Miłeckic8d87072017-01-18 11:48:51 +0100329static const struct brcmf_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100330brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100331{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100332 const struct brcmf_tlv *elt = buf;
333 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100334
335 /* find tagged parameter */
336 while (totlen >= TLV_HDR_LEN) {
337 int len = elt->len;
338
339 /* validate remaining totlen */
340 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
341 return elt;
342
343 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
344 totlen -= (len + TLV_HDR_LEN);
345 }
346
347 return NULL;
348}
349
350/* Is any of the tlvs the expected entry? If
351 * not update the tlvs buffer pointer/length.
352 */
353static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100354brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
355 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100356{
357 /* If the contents match the OUI and the type */
358 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
359 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
360 type == ie[TLV_BODY_OFF + oui_len]) {
361 return true;
362 }
363
364 if (tlvs == NULL)
365 return false;
366 /* point to the next ie */
367 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
368 /* calculate the length of the rest of the buffer */
369 *tlvs_len -= (int)(ie - *tlvs);
370 /* update the pointer to the start of the buffer */
371 *tlvs = ie;
372
373 return false;
374}
375
376static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100377brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100378{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100379 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100380
381 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100382 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100383 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
384 return (struct brcmf_vs_tlv *)ie;
385 }
386 return NULL;
387}
388
389static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100392 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100393
394 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
395 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
396 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
397 return (struct brcmf_vs_tlv *)ie;
398 }
399 return NULL;
400}
401
Arend van Spriel39504a22015-08-20 22:06:05 +0200402static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
403 struct brcmf_cfg80211_vif *vif,
404 enum nl80211_iftype new_type)
405{
Arend van Spriel39504a22015-08-20 22:06:05 +0200406 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100407 bool check_combos = false;
408 int ret = 0;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530409 struct iface_combination_params params = {
410 .num_different_channels = 1,
411 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100414 if (pos == vif) {
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530415 params.iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100416 } else {
417 /* concurrent interfaces so need check combinations */
418 check_combos = true;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530419 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100420 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
Arend van Spriel353c46a2015-12-10 13:43:06 +0100422 if (check_combos)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530423 ret = cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424
425 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200426}
427
428static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
429 enum nl80211_iftype new_type)
430{
Arend van Spriel39504a22015-08-20 22:06:05 +0200431 struct brcmf_cfg80211_vif *pos;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530432 struct iface_combination_params params = {
433 .num_different_channels = 1,
434 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200435
Arend van Spriel39504a22015-08-20 22:06:05 +0200436 list_for_each_entry(pos, &cfg->vif_list, list)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530437 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel39504a22015-08-20 22:06:05 +0200438
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530439 params.iftype_num[new_type]++;
440 return cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel39504a22015-08-20 22:06:05 +0200441}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100442
Arend van Spriel5b435de2011-10-05 13:19:03 +0200443static void convert_key_from_CPU(struct brcmf_wsec_key *key,
444 struct brcmf_wsec_key_le *key_le)
445{
446 key_le->index = cpu_to_le32(key->index);
447 key_le->len = cpu_to_le32(key->len);
448 key_le->algo = cpu_to_le32(key->algo);
449 key_le->flags = cpu_to_le32(key->flags);
450 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
451 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
452 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
453 memcpy(key_le->data, key->data, sizeof(key->data));
454 memcpy(key_le->ea, key->ea, sizeof(key->ea));
455}
456
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200457static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100458send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459{
460 int err;
461 struct brcmf_wsec_key_le key_le;
462
463 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200464
Hante Meuleman118eb302014-12-21 12:43:49 +0100465 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700466
Hante Meuleman118eb302014-12-21 12:43:49 +0100467 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700468 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200469
Arend van Spriel5b435de2011-10-05 13:19:03 +0200470 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100471 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 return err;
473}
474
Hante Meulemanb3657452013-05-27 21:09:53 +0200475static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100476brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200477{
478 s32 err;
479 u32 mode;
480
481 if (enable)
482 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
483 else
484 mode = 0;
485
486 /* Try to set and enable ARP offload feature, this may fail, then it */
487 /* is simply not supported and err 0 will be returned */
488 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
489 if (err) {
490 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
491 mode, err);
492 err = 0;
493 } else {
494 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
495 if (err) {
496 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
497 enable, err);
498 err = 0;
499 } else
500 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
501 enable, mode);
502 }
503
Franky Lin52f22fb2016-02-17 11:26:55 +0100504 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
505 if (err) {
506 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
507 enable, err);
508 err = 0;
509 } else
510 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
511 enable, mode);
512
Hante Meulemanb3657452013-05-27 21:09:53 +0200513 return err;
514}
515
Hante Meuleman8851cce2014-07-30 13:20:02 +0200516static void
517brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
518{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200519 struct brcmf_cfg80211_vif *vif;
520 struct brcmf_if *ifp;
521
522 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
523 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200524
525 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
526 (wdev->iftype == NL80211_IFTYPE_AP) ||
527 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
528 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
529 ADDR_DIRECT);
530 else
531 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
532 ADDR_INDIRECT);
533}
534
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200535static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
536{
537 int bsscfgidx;
538
539 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
540 /* bsscfgidx 1 is reserved for legacy P2P */
541 if (bsscfgidx == 1)
542 continue;
543 if (!drvr->iflist[bsscfgidx])
544 return bsscfgidx;
545 }
546
547 return -ENOMEM;
548}
549
Hante Meulemana44aa402014-12-03 21:05:33 +0100550static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
551{
552 struct brcmf_mbss_ssid_le mbss_ssid_le;
553 int bsscfgidx;
554 int err;
555
556 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200557 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100558 if (bsscfgidx < 0)
559 return bsscfgidx;
560
561 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
562 mbss_ssid_le.SSID_len = cpu_to_le32(5);
563 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
564
565 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
566 sizeof(mbss_ssid_le));
567 if (err < 0)
568 brcmf_err("setting ssid failed %d\n", err);
569
570 return err;
571}
572
573/**
574 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
575 *
576 * @wiphy: wiphy device of new interface.
577 * @name: name of the new interface.
Hante Meulemana44aa402014-12-03 21:05:33 +0100578 * @params: contains mac address for AP device.
579 */
580static
581struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
Johannes Berg818a9862017-04-12 11:23:28 +0200582 struct vif_params *params)
Hante Meulemana44aa402014-12-03 21:05:33 +0100583{
584 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
585 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
586 struct brcmf_cfg80211_vif *vif;
587 int err;
588
589 if (brcmf_cfg80211_vif_event_armed(cfg))
590 return ERR_PTR(-EBUSY);
591
592 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
593
Rafał Miłecki26072332016-06-06 23:03:55 +0200594 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100595 if (IS_ERR(vif))
596 return (struct wireless_dev *)vif;
597
598 brcmf_cfg80211_arm_vif_event(cfg, vif);
599
600 err = brcmf_cfg80211_request_ap_if(ifp);
601 if (err) {
602 brcmf_cfg80211_arm_vif_event(cfg, NULL);
603 goto fail;
604 }
605
606 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100607 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
608 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100609 brcmf_cfg80211_arm_vif_event(cfg, NULL);
610 if (!err) {
611 brcmf_err("timeout occurred\n");
612 err = -EIO;
613 goto fail;
614 }
615
616 /* interface created in firmware */
617 ifp = vif->ifp;
618 if (!ifp) {
619 brcmf_err("no if pointer provided\n");
620 err = -ENOENT;
621 goto fail;
622 }
623
624 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
625 err = brcmf_net_attach(ifp, true);
626 if (err) {
627 brcmf_err("Registering netdevice failed\n");
Arend Van Sprieldca23072017-06-24 22:08:27 +0100628 free_netdev(ifp->ndev);
Hante Meulemana44aa402014-12-03 21:05:33 +0100629 goto fail;
630 }
631
632 return &ifp->vif->wdev;
633
634fail:
635 brcmf_free_vif(vif);
636 return ERR_PTR(err);
637}
638
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100639static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
640{
641 enum nl80211_iftype iftype;
642
643 iftype = vif->wdev.iftype;
644 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
645}
646
647static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
648{
649 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
650}
651
Arend van Spriel9f440b72013-02-08 15:53:36 +0100652static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
653 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100654 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100655 enum nl80211_iftype type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100656 struct vif_params *params)
657{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200658 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200659 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200660
Arend van Spriel9f440b72013-02-08 15:53:36 +0100661 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200662 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
663 if (err) {
664 brcmf_err("iface validation failed: err=%d\n", err);
665 return ERR_PTR(err);
666 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100667 switch (type) {
668 case NL80211_IFTYPE_ADHOC:
669 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100670 case NL80211_IFTYPE_AP_VLAN:
671 case NL80211_IFTYPE_WDS:
672 case NL80211_IFTYPE_MONITOR:
673 case NL80211_IFTYPE_MESH_POINT:
674 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100675 case NL80211_IFTYPE_AP:
Johannes Berg818a9862017-04-12 11:23:28 +0200676 wdev = brcmf_ap_add_vif(wiphy, name, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200677 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100678 case NL80211_IFTYPE_P2P_CLIENT:
679 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200680 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg818a9862017-04-12 11:23:28 +0200681 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200682 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100683 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100684 default:
685 return ERR_PTR(-EINVAL);
686 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200687
688 if (IS_ERR(wdev))
689 brcmf_err("add iface %s type %d failed: err=%d\n",
690 name, type, (int)PTR_ERR(wdev));
691 else
692 brcmf_cfg80211_update_proto_addr_mode(wdev);
693
694 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100695}
696
Daniel Kim5e787f72014-06-21 12:11:18 +0200697static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
698{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200699 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200700 brcmf_set_mpc(ifp, mpc);
701}
702
Arend van Sprielf96aa072013-04-05 10:57:48 +0200703void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100704{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100705 s32 err = 0;
706
707 if (check_vif_up(ifp->vif)) {
708 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
709 if (err) {
710 brcmf_err("fail to set mpc\n");
711 return;
712 }
713 brcmf_dbg(INFO, "MPC : %d\n", mpc);
714 }
715}
716
Arend van Spriela0f472a2013-04-05 10:57:49 +0200717s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
718 struct brcmf_if *ifp, bool aborted,
719 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100720{
721 struct brcmf_scan_params_le params_le;
722 struct cfg80211_scan_request *scan_request;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100723 u64 reqid;
724 u32 bucket;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100725 s32 err = 0;
726
727 brcmf_dbg(SCAN, "Enter\n");
728
729 /* clear scan request, because the FW abort can cause a second call */
730 /* to this functon and might cause a double cfg80211_scan_done */
731 scan_request = cfg->scan_request;
732 cfg->scan_request = NULL;
733
734 if (timer_pending(&cfg->escan_timeout))
735 del_timer_sync(&cfg->escan_timeout);
736
737 if (fw_abort) {
738 /* Do a scan abort to stop the driver's scan engine */
739 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
740 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800741 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100742 params_le.bss_type = DOT11_BSSTYPE_ANY;
743 params_le.scan_type = 0;
744 params_le.channel_num = cpu_to_le32(1);
745 params_le.nprobes = cpu_to_le32(1);
746 params_le.active_time = cpu_to_le32(-1);
747 params_le.passive_time = cpu_to_le32(-1);
748 params_le.home_time = cpu_to_le32(-1);
749 /* Scan is aborted by setting channel_list[0] to -1 */
750 params_le.channel_list[0] = cpu_to_le16(-1);
751 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200752 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100753 &params_le, sizeof(params_le));
754 if (err)
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100755 brcmf_err("Scan abort failed\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100756 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200757
Daniel Kim5e787f72014-06-21 12:11:18 +0200758 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200759
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100760 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000761 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100762 * which takes precedence.
763 */
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +0100764 if (cfg->int_escan_map) {
765 brcmf_dbg(SCAN, "scheduled scan completed (%x)\n",
766 cfg->int_escan_map);
767 while (cfg->int_escan_map) {
768 bucket = __ffs(cfg->int_escan_map);
769 cfg->int_escan_map &= ~BIT(bucket);
770 reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno,
771 bucket);
772 if (!aborted) {
773 brcmf_dbg(SCAN, "report results: reqid=%llu\n",
774 reqid);
775 cfg80211_sched_scan_results(cfg_to_wiphy(cfg),
776 reqid);
777 }
778 }
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100779 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300780 struct cfg80211_scan_info info = {
781 .aborted = aborted,
782 };
783
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100784 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
785 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300786 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100787 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100788 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
789 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100790
791 return err;
792}
793
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200794static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
795 struct wireless_dev *wdev)
796{
797 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
798 struct net_device *ndev = wdev->netdev;
799 struct brcmf_if *ifp = netdev_priv(ndev);
800 int ret;
801 int err;
802
803 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
804
805 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
806 if (err) {
807 brcmf_err("interface_remove failed %d\n", err);
808 goto err_unarm;
809 }
810
811 /* wait for firmware event */
812 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
813 BRCMF_VIF_EVENT_TIMEOUT);
814 if (!ret) {
815 brcmf_err("timeout occurred\n");
816 err = -EIO;
817 goto err_unarm;
818 }
819
820 brcmf_remove_interface(ifp, true);
821
822err_unarm:
823 brcmf_cfg80211_arm_vif_event(cfg, NULL);
824 return err;
825}
826
Arend van Spriel9f440b72013-02-08 15:53:36 +0100827static
828int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
829{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100830 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
831 struct net_device *ndev = wdev->netdev;
832
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200833 if (ndev && ndev == cfg_to_ndev(cfg))
834 return -ENOTSUPP;
835
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100836 /* vif event pending in firmware */
837 if (brcmf_cfg80211_vif_event_armed(cfg))
838 return -EBUSY;
839
840 if (ndev) {
841 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200842 cfg->escan_info.ifp == netdev_priv(ndev))
843 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
844 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100845
846 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
847 }
848
Arend van Spriel9f440b72013-02-08 15:53:36 +0100849 switch (wdev->iftype) {
850 case NL80211_IFTYPE_ADHOC:
851 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100852 case NL80211_IFTYPE_AP_VLAN:
853 case NL80211_IFTYPE_WDS:
854 case NL80211_IFTYPE_MONITOR:
855 case NL80211_IFTYPE_MESH_POINT:
856 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200857 case NL80211_IFTYPE_AP:
858 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100859 case NL80211_IFTYPE_P2P_CLIENT:
860 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200861 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100862 return brcmf_p2p_del_vif(wiphy, wdev);
863 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100864 default:
865 return -EINVAL;
866 }
867 return -EOPNOTSUPP;
868}
869
Arend van Spriel5b435de2011-10-05 13:19:03 +0200870static s32
871brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +0200872 enum nl80211_iftype type,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200873 struct vif_params *params)
874{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100875 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700876 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100877 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200878 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200879 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200880 s32 err = 0;
881
Hante Meuleman37a869e2015-10-29 20:33:17 +0100882 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
883 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200884
885 /* WAR: There are a number of p2p interface related problems which
886 * need to be handled initially (before doing the validate).
887 * wpa_supplicant tends to do iface changes on p2p device/client/go
888 * which are not always possible/allowed. However we need to return
889 * OK otherwise the wpa_supplicant wont start. The situation differs
890 * on configuration and setup (p2pon=1 module param). The first check
891 * is to see if the request is a change to station for p2p iface.
892 */
893 if ((type == NL80211_IFTYPE_STATION) &&
894 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
895 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
896 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
897 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
898 /* Now depending on whether module param p2pon=1 was used the
899 * response needs to be either 0 or EOPNOTSUPP. The reason is
900 * that if p2pon=1 is used, but a newer supplicant is used then
901 * we should return an error, as this combination wont work.
902 * In other situations 0 is returned and supplicant will start
903 * normally. It will give a trace in cfg80211, but it is the
904 * only way to get it working. Unfortunately this will result
905 * in situation where we wont support new supplicant in
906 * combination with module param p2pon=1, but that is the way
907 * it is. If the user tries this then unloading of driver might
908 * fail/lock.
909 */
910 if (cfg->p2p.p2pdev_dynamically)
911 return -EOPNOTSUPP;
912 else
913 return 0;
914 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200915 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
916 if (err) {
917 brcmf_err("iface validation failed: err=%d\n", err);
918 return err;
919 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200920 switch (type) {
921 case NL80211_IFTYPE_MONITOR:
922 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100923 brcmf_err("type (%d) : currently we do not support this type\n",
924 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200925 return -EOPNOTSUPP;
926 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200927 infra = 0;
928 break;
929 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200930 infra = 1;
931 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200932 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100933 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200934 ap = 1;
935 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200936 default:
937 err = -EINVAL;
938 goto done;
939 }
940
Hante Meuleman1a873342012-09-27 14:17:54 +0200941 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100942 if (type == NL80211_IFTYPE_P2P_GO) {
943 brcmf_dbg(INFO, "IF Type = P2P GO\n");
944 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
945 }
946 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100947 brcmf_dbg(INFO, "IF Type = AP\n");
948 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200949 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100950 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200951 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100952 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200953 err = -EAGAIN;
954 goto done;
955 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100956 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100957 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200958 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200959 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200960
Hante Meuleman8851cce2014-07-30 13:20:02 +0200961 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
962
Arend van Spriel5b435de2011-10-05 13:19:03 +0200963done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100964 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200965
966 return err;
967}
968
Franky Lin83cf17a2013-04-11 13:28:50 +0200969static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
970 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200971 struct cfg80211_scan_request *request)
972{
973 u32 n_ssids;
974 u32 n_channels;
975 s32 i;
976 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200977 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200978 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200979 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200980
Joe Perches93803b32015-03-02 19:54:49 -0800981 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200982 params_le->bss_type = DOT11_BSSTYPE_ANY;
983 params_le->scan_type = 0;
984 params_le->channel_num = 0;
985 params_le->nprobes = cpu_to_le32(-1);
986 params_le->active_time = cpu_to_le32(-1);
987 params_le->passive_time = cpu_to_le32(-1);
988 params_le->home_time = cpu_to_le32(-1);
989 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
990
991 /* if request is null exit so it will be all channel broadcast scan */
992 if (!request)
993 return;
994
995 n_ssids = request->n_ssids;
996 n_channels = request->n_channels;
997 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100998 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
999 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +02001000 if (n_channels > 0) {
1001 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02001002 chanspec = channel_to_chanspec(&cfg->d11inf,
1003 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001004 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
1005 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +02001006 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +02001007 }
1008 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001009 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001010 }
1011 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001012 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001013 if (n_ssids > 0) {
1014 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1015 n_channels * sizeof(u16);
1016 offset = roundup(offset, sizeof(u32));
1017 ptr = (char *)params_le + offset;
1018 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001019 memset(&ssid_le, 0, sizeof(ssid_le));
1020 ssid_le.SSID_len =
1021 cpu_to_le32(request->ssids[i].ssid_len);
1022 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1023 request->ssids[i].ssid_len);
1024 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001025 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001026 else
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01001027 brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001028 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001029 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1030 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001031 }
1032 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001033 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001034 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001035 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1036 params_le->ssid_le.SSID,
1037 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001038 params_le->ssid_le.SSID_len =
1039 cpu_to_le32(request->ssids->ssid_len);
1040 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1041 request->ssids->ssid_len);
1042 }
1043 }
1044 /* Adding mask to channel numbers */
1045 params_le->channel_num =
1046 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1047 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1048}
1049
1050static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001051brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001052 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001053{
1054 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1055 offsetof(struct brcmf_escan_params_le, params_le);
1056 struct brcmf_escan_params_le *params;
1057 s32 err = 0;
1058
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001059 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001060
1061 if (request != NULL) {
1062 /* Allocate space for populating ssids in struct */
1063 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1064
1065 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001066 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001067 }
1068
1069 params = kzalloc(params_size, GFP_KERNEL);
1070 if (!params) {
1071 err = -ENOMEM;
1072 goto exit;
1073 }
1074 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001075 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001076 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001077 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001078 params->sync_id = cpu_to_le16(0x1234);
1079
Arend van Spriela0f472a2013-04-05 10:57:49 +02001080 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001081 if (err) {
1082 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001083 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001084 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001085 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001086 }
1087
1088 kfree(params);
1089exit:
1090 return err;
1091}
1092
1093static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001094brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001095{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001096 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001097 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001098 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001099 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001100 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001101
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001102 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001103 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001104 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001105 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001106 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001107 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001108 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001110 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001111 return err;
1112 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001113 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001114 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001115 results->version = 0;
1116 results->count = 0;
1117 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1118
Hante Meulemanc4958102015-11-25 11:32:41 +01001119 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001120 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001121 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001122 return err;
1123}
1124
1125static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001126brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001127 struct cfg80211_scan_request *request,
1128 struct cfg80211_ssid *this_ssid)
1129{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001130 struct brcmf_if *ifp = vif->ifp;
1131 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001132 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001133 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001134 bool escan_req;
1135 bool spec_scan;
1136 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001137 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001138 u32 SSID_len;
1139
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001140 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001141
Arend van Sprielc1179032012-10-22 13:55:33 -07001142 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001143 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001144 return -EAGAIN;
1145 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001146 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001147 brcmf_err("Scanning being aborted: status (%lu)\n",
1148 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001149 return -EAGAIN;
1150 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001151 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1152 brcmf_err("Scanning suppressed: status (%lu)\n",
1153 cfg->scan_status);
1154 return -EAGAIN;
1155 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001156 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001157 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001158 return -EAGAIN;
1159 }
1160
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001161 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001162 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1163 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001164
Hante Meulemane756af52012-09-11 21:18:52 +02001165 escan_req = false;
1166 if (request) {
1167 /* scan bss */
1168 ssids = request->ssids;
1169 escan_req = true;
1170 } else {
1171 /* scan in ibss */
1172 /* we don't do escan in ibss */
1173 ssids = this_ssid;
1174 }
1175
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001176 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001177 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001178 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001179 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001180 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001181 if (err)
1182 goto scan_out;
1183
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001184 err = brcmf_do_escan(vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001185 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001186 goto scan_out;
1187 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001188 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1189 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001190 memset(&ssid_le, 0, sizeof(ssid_le));
1191 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1192 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001193 spec_scan = false;
1194 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001195 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1196 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001197 spec_scan = true;
1198 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001199 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001200
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001201 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001202 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001203 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001204 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001205 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001206 goto scan_out;
1207 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001208 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001209 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1210 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001211 if (err) {
1212 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001213 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001214 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001215 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001216 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001217
Daniel Kim5e787f72014-06-21 12:11:18 +02001218 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001219 goto scan_out;
1220 }
1221 }
1222
Hante Meuleman661fa952015-02-06 18:36:47 +01001223 /* Arm scan timeout timer */
1224 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001225 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001226
Hante Meulemane756af52012-09-11 21:18:52 +02001227 return 0;
1228
1229scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001230 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001231 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001232 return err;
1233}
1234
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001236brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001238 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 s32 err = 0;
1240
Arend van Sprield96b8012012-12-05 15:26:02 +01001241 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001242 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1243 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001244 return -EIO;
1245
Arend van Spriela0f472a2013-04-05 10:57:49 +02001246 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001247
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001249 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250
Arend van Sprield96b8012012-12-05 15:26:02 +01001251 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001252 return err;
1253}
1254
1255static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1256{
1257 s32 err = 0;
1258
Arend van Sprielac24be62012-10-22 10:36:23 -07001259 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1260 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001261 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001262 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001263
1264 return err;
1265}
1266
1267static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1268{
1269 s32 err = 0;
1270
Arend van Sprielac24be62012-10-22 10:36:23 -07001271 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1272 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001273 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001274 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275
1276 return err;
1277}
1278
1279static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1280{
1281 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001282 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283
Arend van Sprielac24be62012-10-22 10:36:23 -07001284 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001286 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001287 return err;
1288 }
1289 return err;
1290}
1291
1292static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1293{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001294 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1295 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001296 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001297 s32 err = 0;
1298
Arend van Sprield96b8012012-12-05 15:26:02 +01001299 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001300 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301 return -EIO;
1302
1303 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001304 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1305 cfg->conf->rts_threshold = wiphy->rts_threshold;
1306 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001307 if (!err)
1308 goto done;
1309 }
1310 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001311 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1312 cfg->conf->frag_threshold = wiphy->frag_threshold;
1313 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001314 if (!err)
1315 goto done;
1316 }
1317 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001318 && (cfg->conf->retry_long != wiphy->retry_long)) {
1319 cfg->conf->retry_long = wiphy->retry_long;
1320 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 if (!err)
1322 goto done;
1323 }
1324 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001325 && (cfg->conf->retry_short != wiphy->retry_short)) {
1326 cfg->conf->retry_short = wiphy->retry_short;
1327 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001328 if (!err)
1329 goto done;
1330 }
1331
1332done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001333 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334 return err;
1335}
1336
Arend van Spriel5b435de2011-10-05 13:19:03 +02001337static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1338{
1339 memset(prof, 0, sizeof(*prof));
1340}
1341
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001342static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1343{
1344 u16 reason;
1345
1346 switch (e->event_code) {
1347 case BRCMF_E_DEAUTH:
1348 case BRCMF_E_DEAUTH_IND:
1349 case BRCMF_E_DISASSOC_IND:
1350 reason = e->reason;
1351 break;
1352 case BRCMF_E_LINK:
1353 default:
1354 reason = 0;
1355 break;
1356 }
1357 return reason;
1358}
1359
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001360static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
1361{
1362 struct brcmf_wsec_pmk_le pmk;
1363 int i, err;
1364
1365 /* convert to firmware key format */
1366 pmk.key_len = cpu_to_le16(pmk_len << 1);
1367 pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
1368 for (i = 0; i < pmk_len; i++)
1369 snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
1370
1371 /* store psk in firmware */
1372 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
1373 &pmk, sizeof(pmk));
1374 if (err < 0)
1375 brcmf_err("failed to change PSK in firmware (len=%u)\n",
1376 pmk_len);
1377
1378 return err;
1379}
1380
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001381static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001382{
Piotr Haber61730d42013-04-23 12:53:12 +02001383 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001384 s32 err = 0;
1385
Arend van Sprield96b8012012-12-05 15:26:02 +01001386 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387
Hante Meulemanb0a79082015-12-10 13:43:07 +01001388 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001389 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001390 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001391 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001392 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001393 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001394 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001395 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1396 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1397 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1398 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001400 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001401 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1402 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01001403 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
1404 brcmf_set_pmk(vif->ifp, NULL, 0);
1405 vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1406 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001407 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408}
1409
1410static s32
1411brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1412 struct cfg80211_ibss_params *params)
1413{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001414 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001415 struct brcmf_if *ifp = netdev_priv(ndev);
1416 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 struct brcmf_join_params join_params;
1418 size_t join_params_size = 0;
1419 s32 err = 0;
1420 s32 wsec = 0;
1421 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001422 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001423 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424
Arend van Sprield96b8012012-12-05 15:26:02 +01001425 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001426 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 return -EIO;
1428
1429 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001430 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001432 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 return -EOPNOTSUPP;
1434 }
1435
Arend van Sprielc1179032012-10-22 13:55:33 -07001436 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001437
1438 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001439 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 else
Arend van Spriel16886732012-12-05 15:26:04 +01001441 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442
Johannes Berg683b6d32012-11-08 21:25:48 +01001443 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001444 brcmf_dbg(CONN, "channel: %d\n",
1445 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446 else
Arend van Spriel16886732012-12-05 15:26:04 +01001447 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001448
1449 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001450 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001451 else
Arend van Spriel16886732012-12-05 15:26:04 +01001452 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453
1454 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001455 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 else
Arend van Spriel16886732012-12-05 15:26:04 +01001457 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458
1459 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001460 brcmf_dbg(CONN, "beacon interval: %d\n",
1461 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001462 else
Arend van Spriel16886732012-12-05 15:26:04 +01001463 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001464
1465 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001466 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467 else
Arend van Spriel16886732012-12-05 15:26:04 +01001468 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001469
1470 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001471 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472 else
Arend van Spriel16886732012-12-05 15:26:04 +01001473 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474
1475 /* Configure Privacy for starter */
1476 if (params->privacy)
1477 wsec |= WEP_ENABLED;
1478
Arend van Sprielc1179032012-10-22 13:55:33 -07001479 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001481 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 goto done;
1483 }
1484
1485 /* Configure Beacon Interval for starter */
1486 if (params->beacon_interval)
1487 bcnprd = params->beacon_interval;
1488 else
1489 bcnprd = 100;
1490
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001491 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001492 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001493 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494 goto done;
1495 }
1496
1497 /* Configure required join parameter */
1498 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1499
1500 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001501 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1502 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1503 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001504 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505
1506 /* BSSID */
1507 if (params->bssid) {
1508 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001509 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001510 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001512 eth_broadcast_addr(join_params.params_le.bssid);
1513 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001514 }
1515
Arend van Spriel5b435de2011-10-05 13:19:03 +02001516 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001517 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518 u32 target_channel;
1519
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001520 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001521 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001522 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001523 if (params->channel_fixed) {
1524 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001525 chanspec = chandef_to_chanspec(&cfg->d11inf,
1526 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001527 join_params.params_le.chanspec_list[0] =
1528 cpu_to_le16(chanspec);
1529 join_params.params_le.chanspec_num = cpu_to_le32(1);
1530 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531 }
1532
1533 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001534 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001535 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001536 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001538 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539 goto done;
1540 }
1541 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001542 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001544 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001545
1546
Arend van Sprielc1179032012-10-22 13:55:33 -07001547 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001548 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001550 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 goto done;
1552 }
1553
1554done:
1555 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001556 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001557 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001558 return err;
1559}
1560
1561static s32
1562brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1563{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001564 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565
Arend van Sprield96b8012012-12-05 15:26:02 +01001566 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001567 if (!check_vif_up(ifp->vif)) {
1568 /* When driver is being unloaded, it can end up here. If an
1569 * error is returned then later on a debug trace in the wireless
1570 * core module will be printed. To avoid this 0 is returned.
1571 */
1572 return 0;
1573 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001575 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001576 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577
Arend van Sprield96b8012012-12-05 15:26:02 +01001578 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001579
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001580 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001581}
1582
1583static s32 brcmf_set_wpa_version(struct net_device *ndev,
1584 struct cfg80211_connect_params *sme)
1585{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001586 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587 struct brcmf_cfg80211_security *sec;
1588 s32 val = 0;
1589 s32 err = 0;
1590
1591 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1592 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1593 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1594 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1595 else
1596 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001597 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001598 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001600 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001601 return err;
1602 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001603 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001604 sec->wpa_versions = sme->crypto.wpa_versions;
1605 return err;
1606}
1607
1608static s32 brcmf_set_auth_type(struct net_device *ndev,
1609 struct cfg80211_connect_params *sme)
1610{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001611 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612 struct brcmf_cfg80211_security *sec;
1613 s32 val = 0;
1614 s32 err = 0;
1615
1616 switch (sme->auth_type) {
1617 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1618 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001619 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001620 break;
1621 case NL80211_AUTHTYPE_SHARED_KEY:
1622 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001623 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 default:
1626 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001627 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001628 break;
1629 }
1630
Hante Meuleman89286dc2013-02-08 15:53:46 +01001631 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001633 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001634 return err;
1635 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001636 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001637 sec->auth_type = sme->auth_type;
1638 return err;
1639}
1640
1641static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001642brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001643 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001644{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001645 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 struct brcmf_cfg80211_security *sec;
1647 s32 pval = 0;
1648 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001649 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001650 s32 err = 0;
1651
1652 if (sme->crypto.n_ciphers_pairwise) {
1653 switch (sme->crypto.ciphers_pairwise[0]) {
1654 case WLAN_CIPHER_SUITE_WEP40:
1655 case WLAN_CIPHER_SUITE_WEP104:
1656 pval = WEP_ENABLED;
1657 break;
1658 case WLAN_CIPHER_SUITE_TKIP:
1659 pval = TKIP_ENABLED;
1660 break;
1661 case WLAN_CIPHER_SUITE_CCMP:
1662 pval = AES_ENABLED;
1663 break;
1664 case WLAN_CIPHER_SUITE_AES_CMAC:
1665 pval = AES_ENABLED;
1666 break;
1667 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001668 brcmf_err("invalid cipher pairwise (%d)\n",
1669 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001670 return -EINVAL;
1671 }
1672 }
1673 if (sme->crypto.cipher_group) {
1674 switch (sme->crypto.cipher_group) {
1675 case WLAN_CIPHER_SUITE_WEP40:
1676 case WLAN_CIPHER_SUITE_WEP104:
1677 gval = WEP_ENABLED;
1678 break;
1679 case WLAN_CIPHER_SUITE_TKIP:
1680 gval = TKIP_ENABLED;
1681 break;
1682 case WLAN_CIPHER_SUITE_CCMP:
1683 gval = AES_ENABLED;
1684 break;
1685 case WLAN_CIPHER_SUITE_AES_CMAC:
1686 gval = AES_ENABLED;
1687 break;
1688 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001689 brcmf_err("invalid cipher group (%d)\n",
1690 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001691 return -EINVAL;
1692 }
1693 }
1694
Arend van Spriel16886732012-12-05 15:26:04 +01001695 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001696 /* In case of privacy, but no security and WPS then simulate */
1697 /* setting AES. WPS-2.0 allows no security */
1698 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1699 sme->privacy)
1700 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001701
Hante Meuleman240d61a2016-02-17 11:27:10 +01001702 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001703 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001704 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001705 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001706 return err;
1707 }
1708
Arend van Spriel06bb1232012-09-27 14:17:56 +02001709 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001710 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1711 sec->cipher_group = sme->crypto.cipher_group;
1712
1713 return err;
1714}
1715
1716static s32
1717brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1718{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001719 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001720 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001721 s32 val;
1722 s32 err;
1723 const struct brcmf_tlv *rsn_ie;
1724 const u8 *ie;
1725 u32 ie_len;
1726 u32 offset;
1727 u16 rsn_cap;
1728 u32 mfp;
1729 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001730
Arend van Spriel2526ff22017-06-09 13:08:48 +01001731 profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
1732
Hante Meuleman240d61a2016-02-17 11:27:10 +01001733 if (!sme->crypto.n_akm_suites)
1734 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735
Hante Meuleman240d61a2016-02-17 11:27:10 +01001736 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1737 if (err) {
1738 brcmf_err("could not get wpa_auth (%d)\n", err);
1739 return err;
1740 }
1741 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1742 switch (sme->crypto.akm_suites[0]) {
1743 case WLAN_AKM_SUITE_8021X:
1744 val = WPA_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001745 if (sme->want_1x)
1746 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001747 break;
1748 case WLAN_AKM_SUITE_PSK:
1749 val = WPA_AUTH_PSK;
1750 break;
1751 default:
1752 brcmf_err("invalid cipher group (%d)\n",
1753 sme->crypto.cipher_group);
1754 return -EINVAL;
1755 }
1756 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1757 switch (sme->crypto.akm_suites[0]) {
1758 case WLAN_AKM_SUITE_8021X:
1759 val = WPA2_AUTH_UNSPECIFIED;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001760 if (sme->want_1x)
1761 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001762 break;
1763 case WLAN_AKM_SUITE_8021X_SHA256:
1764 val = WPA2_AUTH_1X_SHA256;
Arend van Spriel2526ff22017-06-09 13:08:48 +01001765 if (sme->want_1x)
1766 profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
Hante Meuleman240d61a2016-02-17 11:27:10 +01001767 break;
1768 case WLAN_AKM_SUITE_PSK_SHA256:
1769 val = WPA2_AUTH_PSK_SHA256;
1770 break;
1771 case WLAN_AKM_SUITE_PSK:
1772 val = WPA2_AUTH_PSK;
1773 break;
1774 default:
1775 brcmf_err("invalid cipher group (%d)\n",
1776 sme->crypto.cipher_group);
1777 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001778 }
1779 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001780
Arend van Spriel2526ff22017-06-09 13:08:48 +01001781 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
1782 brcmf_dbg(INFO, "using 1X offload\n");
1783
Hante Meuleman240d61a2016-02-17 11:27:10 +01001784 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1785 goto skip_mfp_config;
1786 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1787 * IE will not be verified, just a quick search for MFP config
1788 */
1789 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1790 WLAN_EID_RSN);
1791 if (!rsn_ie)
1792 goto skip_mfp_config;
1793 ie = (const u8 *)rsn_ie;
1794 ie_len = rsn_ie->len + TLV_HDR_LEN;
1795 /* Skip unicast suite */
1796 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1797 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1798 goto skip_mfp_config;
1799 /* Skip multicast suite */
1800 count = ie[offset] + (ie[offset + 1] << 8);
1801 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1802 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1803 goto skip_mfp_config;
1804 /* Skip auth key management suite(s) */
1805 count = ie[offset] + (ie[offset + 1] << 8);
1806 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1807 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1808 goto skip_mfp_config;
1809 /* Ready to read capabilities */
1810 mfp = BRCMF_MFP_NONE;
1811 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1812 if (rsn_cap & RSN_CAP_MFPR_MASK)
1813 mfp = BRCMF_MFP_REQUIRED;
1814 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1815 mfp = BRCMF_MFP_CAPABLE;
1816 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1817
1818skip_mfp_config:
1819 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1820 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1821 if (err) {
1822 brcmf_err("could not set wpa_auth (%d)\n", err);
1823 return err;
1824 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001825
1826 return err;
1827}
1828
1829static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001830brcmf_set_sharedkey(struct net_device *ndev,
1831 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001832{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001833 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001834 struct brcmf_cfg80211_security *sec;
1835 struct brcmf_wsec_key key;
1836 s32 val;
1837 s32 err = 0;
1838
Arend van Spriel16886732012-12-05 15:26:04 +01001839 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840
Roland Vossena718e2f2011-10-12 20:51:24 +02001841 if (sme->key_len == 0)
1842 return 0;
1843
Arend van Spriel06bb1232012-09-27 14:17:56 +02001844 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001845 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1846 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001847
1848 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1849 return 0;
1850
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001851 if (!(sec->cipher_pairwise &
1852 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1853 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001854
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001855 memset(&key, 0, sizeof(key));
1856 key.len = (u32) sme->key_len;
1857 key.index = (u32) sme->key_idx;
1858 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001859 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001860 return -EINVAL;
1861 }
1862 memcpy(key.data, sme->key, key.len);
1863 key.flags = BRCMF_PRIMARY_KEY;
1864 switch (sec->cipher_pairwise) {
1865 case WLAN_CIPHER_SUITE_WEP40:
1866 key.algo = CRYPTO_ALGO_WEP1;
1867 break;
1868 case WLAN_CIPHER_SUITE_WEP104:
1869 key.algo = CRYPTO_ALGO_WEP128;
1870 break;
1871 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001872 brcmf_err("Invalid algorithm (%d)\n",
1873 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001874 return -EINVAL;
1875 }
1876 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001877 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1878 key.len, key.index, key.algo);
1879 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001880 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001881 if (err)
1882 return err;
1883
1884 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001885 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001886 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001887 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001888 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001889 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 }
1891 return err;
1892}
1893
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001894static
1895enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1896 enum nl80211_auth_type type)
1897{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001898 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1899 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1900 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1901 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001902 }
1903 return type;
1904}
1905
Arend van Spriel7705ba62016-04-17 16:44:58 +02001906static void brcmf_set_join_pref(struct brcmf_if *ifp,
1907 struct cfg80211_bss_selection *bss_select)
1908{
1909 struct brcmf_join_pref_params join_pref_params[2];
1910 enum nl80211_band band;
1911 int err, i = 0;
1912
1913 join_pref_params[i].len = 2;
1914 join_pref_params[i].rssi_gain = 0;
1915
1916 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1917 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1918
1919 switch (bss_select->behaviour) {
1920 case __NL80211_BSS_SELECT_ATTR_INVALID:
1921 brcmf_c_set_joinpref_default(ifp);
1922 return;
1923 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1924 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1925 band = bss_select->param.band_pref;
1926 join_pref_params[i].band = nl80211_band_to_fwil(band);
1927 i++;
1928 break;
1929 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1930 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1931 band = bss_select->param.adjust.band;
1932 join_pref_params[i].band = nl80211_band_to_fwil(band);
1933 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1934 i++;
1935 break;
1936 case NL80211_BSS_SELECT_ATTR_RSSI:
1937 default:
1938 break;
1939 }
1940 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1941 join_pref_params[i].len = 2;
1942 join_pref_params[i].rssi_gain = 0;
1943 join_pref_params[i].band = 0;
1944 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1945 sizeof(join_pref_params));
1946 if (err)
1947 brcmf_err("Set join_pref error (%d)\n", err);
1948}
1949
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950static s32
1951brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001952 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001953{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001954 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001955 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel2526ff22017-06-09 13:08:48 +01001956 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 struct ieee80211_channel *chan = sme->channel;
1958 struct brcmf_join_params join_params;
1959 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001960 const struct brcmf_tlv *rsn_ie;
1961 const struct brcmf_vs_tlv *wpa_ie;
1962 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001963 u32 ie_len;
1964 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001965 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001966 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001967 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968
Arend van Sprield96b8012012-12-05 15:26:02 +01001969 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001970 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001971 return -EIO;
1972
1973 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001974 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001975 return -EOPNOTSUPP;
1976 }
1977
Hante Meuleman89286dc2013-02-08 15:53:46 +01001978 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1979 /* A normal (non P2P) connection request setup. */
1980 ie = NULL;
1981 ie_len = 0;
1982 /* find the WPA_IE */
1983 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1984 if (wpa_ie) {
1985 ie = wpa_ie;
1986 ie_len = wpa_ie->len + TLV_HDR_LEN;
1987 } else {
1988 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001989 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1990 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001991 WLAN_EID_RSN);
1992 if (rsn_ie) {
1993 ie = rsn_ie;
1994 ie_len = rsn_ie->len + TLV_HDR_LEN;
1995 }
1996 }
1997 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1998 }
1999
2000 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
2001 sme->ie, sme->ie_len);
2002 if (err)
2003 brcmf_err("Set Assoc REQ IE Failed\n");
2004 else
2005 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
2006
Arend van Sprielc1179032012-10-22 13:55:33 -07002007 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008
2009 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002010 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02002011 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02002012 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01002013 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
2014 cfg->channel, chan->center_freq, chanspec);
2015 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002016 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01002017 chanspec = 0;
2018 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002019
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002020 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021
2022 err = brcmf_set_wpa_version(ndev, sme);
2023 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002024 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002025 goto done;
2026 }
2027
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01002028 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002029 err = brcmf_set_auth_type(ndev, sme);
2030 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002031 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002032 goto done;
2033 }
2034
Hante Meuleman240d61a2016-02-17 11:27:10 +01002035 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002036 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002037 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002038 goto done;
2039 }
2040
2041 err = brcmf_set_key_mgmt(ndev, sme);
2042 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002043 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002044 goto done;
2045 }
2046
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002047 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002049 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 goto done;
2051 }
2052
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002053 if (sme->crypto.psk) {
Arend van Spriel2526ff22017-06-09 13:08:48 +01002054 if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
2055 err = -EINVAL;
2056 goto done;
2057 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002058 brcmf_dbg(INFO, "using PSK offload\n");
Arend van Spriel2526ff22017-06-09 13:08:48 +01002059 profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
2060 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002061
Arend van Spriel2526ff22017-06-09 13:08:48 +01002062 if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002063 /* enable firmware supplicant for this interface */
2064 err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
2065 if (err < 0) {
2066 brcmf_err("failed to enable fw supplicant\n");
2067 goto done;
2068 }
Arend van Spriel2526ff22017-06-09 13:08:48 +01002069 }
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002070
Arend van Spriel2526ff22017-06-09 13:08:48 +01002071 if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01002072 err = brcmf_set_pmk(ifp, sme->crypto.psk,
2073 BRCMF_WSEC_MAX_PSK_LEN);
2074 if (err)
2075 goto done;
2076 }
2077
Hante Meuleman89286dc2013-02-08 15:53:46 +01002078 /* Join with specific BSSID and cached SSID
2079 * If SSID is zero join based on BSSID only
2080 */
2081 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2082 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2083 if (cfg->channel)
2084 join_params_size += sizeof(u16);
2085 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2086 if (ext_join_params == NULL) {
2087 err = -ENOMEM;
2088 goto done;
2089 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002090 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2091 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2092 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2093 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2094 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2095 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002096
Hante Meuleman89286dc2013-02-08 15:53:46 +01002097 /* Set up join scan parameters */
2098 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002099 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2100
2101 if (sme->bssid)
2102 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2103 else
Joe Perches93803b32015-03-02 19:54:49 -08002104 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002105
2106 if (cfg->channel) {
2107 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2108
2109 ext_join_params->assoc_le.chanspec_list[0] =
2110 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002111 /* Increase dwell time to receive probe response or detect
2112 * beacon from target AP at a noisy air only during connect
2113 * command.
2114 */
2115 ext_join_params->scan_le.active_time =
2116 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2117 ext_join_params->scan_le.passive_time =
2118 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2119 /* To sync with presence period of VSDB GO send probe request
2120 * more frequently. Probe request will be stopped when it gets
2121 * probe response from target AP/GO.
2122 */
2123 ext_join_params->scan_le.nprobes =
2124 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2125 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2126 } else {
2127 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2128 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2129 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002130 }
2131
Arend van Spriel7705ba62016-04-17 16:44:58 +02002132 brcmf_set_join_pref(ifp, &sme->bss_select);
2133
Hante Meuleman89286dc2013-02-08 15:53:46 +01002134 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2135 join_params_size);
2136 kfree(ext_join_params);
2137 if (!err)
2138 /* This is it. join command worked, we are done */
2139 goto done;
2140
2141 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142 memset(&join_params, 0, sizeof(join_params));
2143 join_params_size = sizeof(join_params.ssid_le);
2144
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002145 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2146 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147
Hante Meuleman89286dc2013-02-08 15:53:46 +01002148 if (sme->bssid)
2149 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2150 else
Joe Perches93803b32015-03-02 19:54:49 -08002151 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152
Hante Meuleman17012612013-02-06 18:40:44 +01002153 if (cfg->channel) {
2154 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2155 join_params.params_le.chanspec_num = cpu_to_le32(1);
2156 join_params_size += sizeof(join_params.params_le);
2157 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002158 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002159 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002161 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
2163done:
2164 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002165 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002166 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 return err;
2168}
2169
2170static s32
2171brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2172 u16 reason_code)
2173{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002174 struct brcmf_if *ifp = netdev_priv(ndev);
2175 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002176 struct brcmf_scb_val_le scbval;
2177 s32 err = 0;
2178
Arend van Sprield96b8012012-12-05 15:26:02 +01002179 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002180 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181 return -EIO;
2182
Arend van Sprielc1179032012-10-22 13:55:33 -07002183 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002184 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002185 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002186
Arend van Spriel06bb1232012-09-27 14:17:56 +02002187 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002188 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002189 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002190 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002191 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002192 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002193
Arend van Sprield96b8012012-12-05 15:26:02 +01002194 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 return err;
2196}
2197
2198static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002199brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002200 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002202 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002203 struct net_device *ndev = cfg_to_ndev(cfg);
2204 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002205 s32 err;
2206 s32 disable;
2207 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002208
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002209 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002210 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002211 return -EIO;
2212
2213 switch (type) {
2214 case NL80211_TX_POWER_AUTOMATIC:
2215 break;
2216 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002218 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002219 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220 err = -EINVAL;
2221 goto done;
2222 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002223 qdbm = MBM_TO_DBM(4 * mbm);
2224 if (qdbm > 127)
2225 qdbm = 127;
2226 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002227 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002228 default:
2229 brcmf_err("Unsupported type %d\n", type);
2230 err = -EINVAL;
2231 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 }
2233 /* Make sure radio is off or on as far as software is concerned */
2234 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002235 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002237 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002239 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002240 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002241 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002242
2243done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002244 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 return err;
2246}
2247
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002248static s32
2249brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2250 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002252 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002253 struct net_device *ndev = cfg_to_ndev(cfg);
2254 struct brcmf_if *ifp = netdev_priv(ndev);
2255 s32 qdbm = 0;
2256 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002257
Arend van Sprield96b8012012-12-05 15:26:02 +01002258 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002259 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260 return -EIO;
2261
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002262 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002264 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 goto done;
2266 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002267 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002268
2269done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002270 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002271 return err;
2272}
2273
2274static s32
2275brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002276 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002278 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002279 u32 index;
2280 u32 wsec;
2281 s32 err = 0;
2282
Arend van Sprield96b8012012-12-05 15:26:02 +01002283 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002284 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002285 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002286 return -EIO;
2287
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002288 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002290 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002291 goto done;
2292 }
2293
2294 if (wsec & WEP_ENABLED) {
2295 /* Just select a new current key */
2296 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002297 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002298 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002299 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002300 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 }
2302done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002303 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002304 return err;
2305}
2306
2307static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002308brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2309 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310{
Hante Meuleman992f6062013-04-02 21:06:17 +02002311 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002312 struct brcmf_wsec_key *key;
2313 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002314
2315 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002316 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2317
Hante Meuleman219e0f72016-02-17 11:27:09 +01002318 if (!check_vif_up(ifp->vif))
2319 return -EIO;
2320
2321 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2322 /* we ignore this key index in this case */
2323 return -EINVAL;
2324 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002325
Hante Meuleman240d61a2016-02-17 11:27:10 +01002326 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002327
Hante Meuleman240d61a2016-02-17 11:27:10 +01002328 if (key->algo == CRYPTO_ALGO_OFF) {
2329 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2330 return -EINVAL;
2331 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332
Hante Meuleman240d61a2016-02-17 11:27:10 +01002333 memset(key, 0, sizeof(*key));
2334 key->index = (u32)key_idx;
2335 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336
Hante Meuleman240d61a2016-02-17 11:27:10 +01002337 /* Clear the key/index */
2338 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339
Hante Meuleman219e0f72016-02-17 11:27:09 +01002340 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002341 return err;
2342}
2343
2344static s32
2345brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002346 u8 key_idx, bool pairwise, const u8 *mac_addr,
2347 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002349 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002350 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002351 s32 val;
2352 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002353 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002354 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002355 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356
Arend van Sprield96b8012012-12-05 15:26:02 +01002357 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002358 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002359 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360 return -EIO;
2361
Hante Meuleman118eb302014-12-21 12:43:49 +01002362 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2363 /* we ignore this key index in this case */
2364 brcmf_err("invalid key index (%d)\n", key_idx);
2365 return -EINVAL;
2366 }
2367
Hante Meuleman219e0f72016-02-17 11:27:09 +01002368 if (params->key_len == 0)
2369 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2370 mac_addr);
2371
2372 if (params->key_len > sizeof(key->data)) {
2373 brcmf_err("Too long key length (%u)\n", params->key_len);
2374 return -EINVAL;
2375 }
2376
2377 ext_key = false;
2378 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2379 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2380 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2381 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002383
Hante Meuleman118eb302014-12-21 12:43:49 +01002384 key = &ifp->vif->profile.key[key_idx];
2385 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002386 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2387 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002388 key->len = params->key_len;
2389 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002390 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002391 if (!ext_key)
2392 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002393
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 switch (params->cipher) {
2395 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002396 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002397 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002398 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399 break;
2400 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002401 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002402 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002403 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404 break;
2405 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002406 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002407 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002408 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2409 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2410 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002411 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002412 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002413 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002414 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 break;
2416 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002417 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002418 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002419 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002420 break;
2421 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002422 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002423 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002424 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425 break;
2426 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002427 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 err = -EINVAL;
2429 goto done;
2430 }
2431
Hante Meuleman118eb302014-12-21 12:43:49 +01002432 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002433 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434 goto done;
2435
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002436 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002437 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002438 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002439 goto done;
2440 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002441 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002442 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002443 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002444 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002445 goto done;
2446 }
2447
Arend van Spriel5b435de2011-10-05 13:19:03 +02002448done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002449 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002450 return err;
2451}
2452
2453static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002454brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2455 bool pairwise, const u8 *mac_addr, void *cookie,
2456 void (*callback)(void *cookie,
2457 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002458{
2459 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002460 struct brcmf_if *ifp = netdev_priv(ndev);
2461 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002462 struct brcmf_cfg80211_security *sec;
2463 s32 wsec;
2464 s32 err = 0;
2465
Arend van Sprield96b8012012-12-05 15:26:02 +01002466 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002467 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002468 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002469 return -EIO;
2470
2471 memset(&params, 0, sizeof(params));
2472
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002473 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002474 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002475 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002476 /* Ignore this error, may happen during DISASSOC */
2477 err = -EAGAIN;
2478 goto done;
2479 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002480 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002481 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002482 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2483 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002484 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002485 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2486 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002487 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002489 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002491 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002492 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002493 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002494 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002495 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002496 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497 err = -EINVAL;
2498 goto done;
2499 }
2500 callback(cookie, &params);
2501
2502done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002503 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002504 return err;
2505}
2506
2507static s32
2508brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002509 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002510{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002511 struct brcmf_if *ifp = netdev_priv(ndev);
2512
2513 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2514
2515 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2516 return 0;
2517
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002518 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002519
2520 return -EOPNOTSUPP;
2521}
2522
Hante Meuleman118eb302014-12-21 12:43:49 +01002523static void
2524brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2525{
2526 s32 err;
2527 u8 key_idx;
2528 struct brcmf_wsec_key *key;
2529 s32 wsec;
2530
2531 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2532 key = &ifp->vif->profile.key[key_idx];
2533 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2534 (key->algo == CRYPTO_ALGO_WEP128))
2535 break;
2536 }
2537 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2538 return;
2539
2540 err = send_key_to_dongle(ifp, key);
2541 if (err) {
2542 brcmf_err("Setting WEP key failed (%d)\n", err);
2543 return;
2544 }
2545 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2546 if (err) {
2547 brcmf_err("get wsec error (%d)\n", err);
2548 return;
2549 }
2550 wsec |= WEP_ENABLED;
2551 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2552 if (err)
2553 brcmf_err("set wsec error (%d)\n", err);
2554}
2555
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002556static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2557{
2558 struct nl80211_sta_flag_update *sfu;
2559
2560 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2561 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2562 sfu = &si->sta_flags;
2563 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2564 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2565 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2566 BIT(NL80211_STA_FLAG_AUTHORIZED);
2567 if (fw_sta_flags & BRCMF_STA_WME)
2568 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2569 if (fw_sta_flags & BRCMF_STA_AUTHE)
2570 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2571 if (fw_sta_flags & BRCMF_STA_ASSOC)
2572 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2573 if (fw_sta_flags & BRCMF_STA_AUTHO)
2574 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2575}
2576
2577static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2578{
2579 struct {
2580 __le32 len;
2581 struct brcmf_bss_info_le bss_le;
2582 } *buf;
2583 u16 capability;
2584 int err;
2585
2586 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2587 if (!buf)
2588 return;
2589
2590 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2591 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2592 WL_BSS_INFO_MAX);
2593 if (err) {
2594 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002595 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002596 }
2597 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2598 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2599 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2600 capability = le16_to_cpu(buf->bss_le.capability);
2601 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2602 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2603 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2604 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2605 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2606 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002607
2608out_kfree:
2609 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002610}
2611
Arend van Spriel5b435de2011-10-05 13:19:03 +02002612static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002613brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2614 struct station_info *sinfo)
2615{
2616 struct brcmf_scb_val_le scbval;
2617 struct brcmf_pktcnt_le pktcnt;
2618 s32 err;
2619 u32 rate;
2620 u32 rssi;
2621
2622 /* Get the current tx rate */
2623 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2624 if (err < 0) {
2625 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2626 return err;
2627 }
2628 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2629 sinfo->txrate.legacy = rate * 5;
2630
2631 memset(&scbval, 0, sizeof(scbval));
2632 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2633 sizeof(scbval));
2634 if (err) {
2635 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2636 return err;
2637 }
2638 rssi = le32_to_cpu(scbval.val);
2639 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2640 sinfo->signal = rssi;
2641
2642 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2643 sizeof(pktcnt));
2644 if (err) {
2645 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2646 return err;
2647 }
2648 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2649 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2650 BIT(NL80211_STA_INFO_TX_PACKETS) |
2651 BIT(NL80211_STA_INFO_TX_FAILED);
2652 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2653 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2654 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2655 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2656
2657 return 0;
2658}
2659
2660static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002661brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002662 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002663{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002664 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002665 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002667 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002668 u32 sta_flags;
2669 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002670 s32 total_rssi;
2671 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002672 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002673 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002674
Arend van Sprield96b8012012-12-05 15:26:02 +01002675 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002676 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002677 return -EIO;
2678
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002679 if (brcmf_is_ibssmode(ifp->vif))
2680 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2681
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002682 memset(&sta_info_le, 0, sizeof(sta_info_le));
2683 memcpy(&sta_info_le, mac, ETH_ALEN);
2684 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2685 &sta_info_le,
2686 sizeof(sta_info_le));
2687 is_tdls_peer = !err;
2688 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002689 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002690 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002691 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002692 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002693 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002694 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002695 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002696 }
2697 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2698 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2699 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2700 sta_flags = le32_to_cpu(sta_info_le.flags);
2701 brcmf_convert_sta_flags(sta_flags, sinfo);
2702 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2703 if (is_tdls_peer)
2704 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2705 else
2706 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2707 if (sta_flags & BRCMF_STA_ASSOC) {
2708 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2709 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2710 brcmf_fill_bss_param(ifp, sinfo);
2711 }
2712 if (sta_flags & BRCMF_STA_SCBSTATS) {
2713 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2714 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2715 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2716 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2717 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2718 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2719 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2720 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2721 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002722 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002723 sinfo->txrate.legacy =
2724 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002725 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002726 if (sinfo->rx_packets) {
2727 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002728 sinfo->rxrate.legacy =
2729 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002730 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002731 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2732 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2733 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2734 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2735 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2736 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002737 total_rssi = 0;
2738 count_rssi = 0;
2739 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2740 if (sta_info_le.rssi[i]) {
2741 sinfo->chain_signal_avg[count_rssi] =
2742 sta_info_le.rssi[i];
2743 sinfo->chain_signal[count_rssi] =
2744 sta_info_le.rssi[i];
2745 total_rssi += sta_info_le.rssi[i];
2746 count_rssi++;
2747 }
2748 }
2749 if (count_rssi) {
2750 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2751 sinfo->chains = count_rssi;
2752
2753 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2754 total_rssi /= count_rssi;
2755 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002756 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2757 &ifp->vif->sme_state)) {
2758 memset(&scb_val, 0, sizeof(scb_val));
2759 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2760 &scb_val, sizeof(scb_val));
2761 if (err) {
2762 brcmf_err("Could not get rssi (%d)\n", err);
2763 goto done;
2764 } else {
2765 rssi = le32_to_cpu(scb_val.val);
2766 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2767 sinfo->signal = rssi;
2768 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2769 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002770 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002771 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002773 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002774 return err;
2775}
2776
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002777static int
2778brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2779 int idx, u8 *mac, struct station_info *sinfo)
2780{
2781 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2782 struct brcmf_if *ifp = netdev_priv(ndev);
2783 s32 err;
2784
2785 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2786
2787 if (idx == 0) {
2788 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2789 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2790 &cfg->assoclist,
2791 sizeof(cfg->assoclist));
2792 if (err) {
2793 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2794 err);
2795 cfg->assoclist.count = 0;
2796 return -EOPNOTSUPP;
2797 }
2798 }
2799 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2800 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2801 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2802 }
2803 return -ENOENT;
2804}
2805
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806static s32
2807brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2808 bool enabled, s32 timeout)
2809{
2810 s32 pm;
2811 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002812 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002813 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814
Arend van Sprield96b8012012-12-05 15:26:02 +01002815 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002816
2817 /*
2818 * Powersave enable/disable request is coming from the
2819 * cfg80211 even before the interface is up. In that
2820 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002821 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 * FW later while initializing the dongle
2823 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002824 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002825 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002826
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002827 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002828 goto done;
2829 }
2830
2831 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002832 /* Do not enable the power save after assoc if it is a p2p interface */
2833 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2834 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2835 pm = PM_OFF;
2836 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002837 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002838
Arend van Sprielc1179032012-10-22 13:55:33 -07002839 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002840 if (err) {
2841 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002842 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002843 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002844 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845 }
2846done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002847 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848 return err;
2849}
2850
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002851static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002852 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002853{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002854 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002855 struct ieee80211_channel *notify_channel;
2856 struct cfg80211_bss *bss;
2857 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002858 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002859 u16 channel;
2860 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861 u16 notify_capability;
2862 u16 notify_interval;
2863 u8 *notify_ie;
2864 size_t notify_ielen;
2865 s32 notify_signal;
2866
2867 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002868 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002869 return 0;
2870 }
2871
Franky Lin83cf17a2013-04-11 13:28:50 +02002872 if (!bi->ctl_ch) {
2873 ch.chspec = le16_to_cpu(bi->chanspec);
2874 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002875 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002876 }
2877 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878
2879 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002880 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002882 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002883
2884 freq = ieee80211_channel_to_frequency(channel, band->band);
2885 notify_channel = ieee80211_get_channel(wiphy, freq);
2886
Arend van Spriel5b435de2011-10-05 13:19:03 +02002887 notify_capability = le16_to_cpu(bi->capability);
2888 notify_interval = le16_to_cpu(bi->beacon_period);
2889 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2890 notify_ielen = le32_to_cpu(bi->ie_length);
2891 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2892
Arend van Spriel16886732012-12-05 15:26:04 +01002893 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2894 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2895 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2896 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2897 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002899 bss = cfg80211_inform_bss(wiphy, notify_channel,
2900 CFG80211_BSS_FTYPE_UNKNOWN,
2901 (const u8 *)bi->BSSID,
2902 0, notify_capability,
2903 notify_interval, notify_ie,
2904 notify_ielen, notify_signal,
2905 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002906
Franky Line78946e2011-11-10 20:30:34 +01002907 if (!bss)
2908 return -ENOMEM;
2909
Johannes Berg5b112d32013-02-01 01:49:58 +01002910 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002911
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002912 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913}
2914
Roland Vossen6f09be02011-10-18 14:03:02 +02002915static struct brcmf_bss_info_le *
2916next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2917{
2918 if (bss == NULL)
2919 return list->bss_info_le;
2920 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2921 le32_to_cpu(bss->length));
2922}
2923
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002924static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002925{
2926 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002927 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928 s32 err = 0;
2929 int i;
2930
Hante Meulemanef8596e2014-09-30 10:23:13 +02002931 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002932 if (bss_list->count != 0 &&
2933 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002934 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2935 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002936 return -EOPNOTSUPP;
2937 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002938 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002939 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002940 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002941 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002942 if (err)
2943 break;
2944 }
2945 return err;
2946}
2947
Hante Meulemanb0a79082015-12-10 13:43:07 +01002948static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2949 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002950{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002951 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002952 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002953 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002954 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002955 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002956 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002957 u8 *buf = NULL;
2958 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002959 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002960 u16 notify_capability;
2961 u16 notify_interval;
2962 u8 *notify_ie;
2963 size_t notify_ielen;
2964 s32 notify_signal;
2965
Arend van Sprield96b8012012-12-05 15:26:02 +01002966 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002967
2968 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2969 if (buf == NULL) {
2970 err = -ENOMEM;
2971 goto CleanUp;
2972 }
2973
2974 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2975
Arend van Sprielac24be62012-10-22 10:36:23 -07002976 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2977 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002978 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002979 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002980 goto CleanUp;
2981 }
2982
Roland Vossend34bf642011-10-18 14:03:01 +02002983 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002984
Franky Lin83cf17a2013-04-11 13:28:50 +02002985 ch.chspec = le16_to_cpu(bi->chanspec);
2986 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002987
Franky Lin83cf17a2013-04-11 13:28:50 +02002988 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002989 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002990 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002991 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002992
Rafał Miłecki4712d882016-05-20 13:38:57 +02002993 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002994 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002995 notify_channel = ieee80211_get_channel(wiphy, freq);
2996
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997 notify_capability = le16_to_cpu(bi->capability);
2998 notify_interval = le16_to_cpu(bi->beacon_period);
2999 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
3000 notify_ielen = le32_to_cpu(bi->ie_length);
3001 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
3002
Rafał Miłecki4712d882016-05-20 13:38:57 +02003003 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01003004 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
3005 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
3006 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003007
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02003008 bss = cfg80211_inform_bss(wiphy, notify_channel,
3009 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
3010 notify_capability, notify_interval,
3011 notify_ie, notify_ielen, notify_signal,
3012 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003013
Franky Line78946e2011-11-10 20:30:34 +01003014 if (!bss) {
3015 err = -ENOMEM;
3016 goto CleanUp;
3017 }
3018
Johannes Berg5b112d32013-02-01 01:49:58 +01003019 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01003020
Arend van Spriel5b435de2011-10-05 13:19:03 +02003021CleanUp:
3022
3023 kfree(buf);
3024
Arend van Sprield96b8012012-12-05 15:26:02 +01003025 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003026
3027 return err;
3028}
3029
Hante Meuleman89286dc2013-02-08 15:53:46 +01003030static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
3031 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02003032{
Roland Vossend34bf642011-10-18 14:03:01 +02003033 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01003034 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003035 u16 beacon_interval;
3036 u8 dtim_period;
3037 size_t ie_len;
3038 u8 *ie;
3039 s32 err = 0;
3040
Arend van Sprield96b8012012-12-05 15:26:02 +01003041 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003042 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003043 return err;
3044
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003045 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07003046 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003047 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003048 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003049 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003050 goto update_bss_info_out;
3051 }
3052
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003053 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
3054 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003055 if (err)
3056 goto update_bss_info_out;
3057
3058 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
3059 ie_len = le32_to_cpu(bi->ie_length);
3060 beacon_interval = le16_to_cpu(bi->beacon_period);
3061
Alwin Beukersf8e4b412011-10-12 20:51:28 +02003062 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003063 if (tim)
3064 dtim_period = tim->data[1];
3065 else {
3066 /*
3067 * active scan was done so we could not get dtim
3068 * information out of probe response.
3069 * so we speficially query dtim information to dongle.
3070 */
3071 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07003072 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003073 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003074 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003075 goto update_bss_info_out;
3076 }
3077 dtim_period = (u8)var;
3078 }
3079
Arend van Spriel5b435de2011-10-05 13:19:03 +02003080update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003081 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003082 return err;
3083}
3084
Hante Meuleman18e2f612013-02-08 15:53:49 +01003085void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003086{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003087 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003088
Arend van Sprielc1179032012-10-22 13:55:33 -07003089 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003090 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003091 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003092 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003093 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003094 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3095 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003096}
3097
Hante Meulemane756af52012-09-11 21:18:52 +02003098static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3099{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003100 struct brcmf_cfg80211_info *cfg =
3101 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003102 escan_timeout_work);
3103
Hante Meulemanef8596e2014-09-30 10:23:13 +02003104 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003105 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003106}
3107
3108static void brcmf_escan_timeout(unsigned long data)
3109{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003110 struct brcmf_cfg80211_info *cfg =
3111 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003112
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003113 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003115 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003116 }
3117}
3118
3119static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003120brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3121 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003122 struct brcmf_bss_info_le *bss_info_le)
3123{
Franky Lin83cf17a2013-04-11 13:28:50 +02003124 struct brcmu_chan ch_bss, ch_bss_info_le;
3125
3126 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3127 cfg->d11inf.decchspec(&ch_bss);
3128 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3129 cfg->d11inf.decchspec(&ch_bss_info_le);
3130
Hante Meulemane756af52012-09-11 21:18:52 +02003131 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003132 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003133 bss_info_le->SSID_len == bss->SSID_len &&
3134 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003135 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3136 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003137 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3138 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3139
Hante Meulemane756af52012-09-11 21:18:52 +02003140 /* preserve max RSSI if the measurements are
3141 * both on-channel or both off-channel
3142 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003143 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003144 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003145 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3146 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003147 /* preserve the on-channel rssi measurement
3148 * if the new measurement is off channel
3149 */
3150 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003151 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003152 }
3153 return 1;
3154 }
3155 return 0;
3156}
3157
3158static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003159brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003160 const struct brcmf_event_msg *e, void *data)
3161{
Arend van Spriel19937322012-11-05 16:22:32 -08003162 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003163 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003164 struct brcmf_escan_result_le *escan_result_le;
3165 struct brcmf_bss_info_le *bss_info_le;
3166 struct brcmf_bss_info_le *bss = NULL;
3167 u32 bi_length;
3168 struct brcmf_scan_results *list;
3169 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003170 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003171
Arend van Spriel5c36b992012-11-14 18:46:05 -08003172 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003173
Hans de Goedeb9472a22017-03-08 14:50:17 +01003174 if (status == BRCMF_E_STATUS_ABORT)
3175 goto exit;
3176
Arend van Spriela0f472a2013-04-05 10:57:49 +02003177 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003178 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003179 return -EPERM;
3180 }
3181
3182 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003183 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003184 escan_result_le = (struct brcmf_escan_result_le *) data;
3185 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003186 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003187 goto exit;
3188 }
Hante Meulemane756af52012-09-11 21:18:52 +02003189 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003190 brcmf_err("Invalid bss_count %d: ignoring\n",
3191 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003192 goto exit;
3193 }
3194 bss_info_le = &escan_result_le->bss_info_le;
3195
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003196 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3197 goto exit;
3198
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003199 if (!cfg->int_escan_map && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003200 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3201 goto exit;
3202 }
3203
Hante Meulemane756af52012-09-11 21:18:52 +02003204 bi_length = le32_to_cpu(bss_info_le->length);
3205 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3206 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003207 brcmf_err("Invalid bss_info length %d: ignoring\n",
3208 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003209 goto exit;
3210 }
3211
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003212 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003213 BIT(NL80211_IFTYPE_ADHOC))) {
3214 if (le16_to_cpu(bss_info_le->capability) &
3215 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003216 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003217 goto exit;
3218 }
3219 }
3220
3221 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003222 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003223 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003224 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003225 goto exit;
3226 }
3227
3228 for (i = 0; i < list->count; i++) {
3229 bss = bss ? (struct brcmf_bss_info_le *)
3230 ((unsigned char *)bss +
3231 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003232 if (brcmf_compare_update_same_bss(cfg, bss,
3233 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003234 goto exit;
3235 }
Hante Meulemand5367332016-02-17 11:26:51 +01003236 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3237 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003238 list->version = le32_to_cpu(bss_info_le->version);
3239 list->buflen += bi_length;
3240 list->count++;
3241 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003242 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003243 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3244 goto exit;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003245 if (cfg->int_escan_map || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003246 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003247 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003248 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003249 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003250 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3251 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003252 }
3253exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003254 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003255}
3256
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003257static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003258{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003259 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3260 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003261 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3262 /* Init scan_timeout timer */
3263 init_timer(&cfg->escan_timeout);
3264 cfg->escan_timeout.data = (unsigned long) cfg;
3265 cfg->escan_timeout.function = brcmf_escan_timeout;
3266 INIT_WORK(&cfg->escan_timeout_work,
3267 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003268}
3269
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003270static struct cfg80211_scan_request *
3271brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3272 struct cfg80211_scan_request *req;
3273 size_t req_size;
3274
3275 req_size = sizeof(*req) +
3276 n_netinfo * sizeof(req->channels[0]) +
3277 n_netinfo * sizeof(*req->ssids);
3278
3279 req = kzalloc(req_size, GFP_KERNEL);
3280 if (req) {
3281 req->wiphy = wiphy;
3282 req->ssids = (void *)(&req->channels[0]) +
3283 n_netinfo * sizeof(req->channels[0]);
3284 }
3285 return req;
3286}
3287
3288static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3289 u8 *ssid, u8 ssid_len, u8 channel)
3290{
3291 struct ieee80211_channel *chan;
3292 enum nl80211_band band;
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003293 int freq, i;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003294
3295 if (channel <= CH_MAX_2G_CHANNEL)
3296 band = NL80211_BAND_2GHZ;
3297 else
3298 band = NL80211_BAND_5GHZ;
3299
3300 freq = ieee80211_channel_to_frequency(channel, band);
3301 if (!freq)
3302 return -EINVAL;
3303
3304 chan = ieee80211_get_channel(req->wiphy, freq);
3305 if (!chan)
3306 return -EINVAL;
3307
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003308 for (i = 0; i < req->n_channels; i++) {
3309 if (req->channels[i] == chan)
3310 break;
3311 }
3312 if (i == req->n_channels)
3313 req->channels[req->n_channels++] = chan;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003314
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003315 for (i = 0; i < req->n_ssids; i++) {
3316 if (req->ssids[i].ssid_len == ssid_len &&
3317 !memcmp(req->ssids[i].ssid, ssid, ssid_len))
3318 break;
3319 }
3320 if (i == req->n_ssids) {
3321 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3322 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3323 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003324 return 0;
3325}
3326
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003327static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003328 struct cfg80211_scan_request *request)
3329{
3330 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3331 int err;
3332
3333 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003334 if (cfg->int_escan_map)
3335 brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
3336 cfg->int_escan_map);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003337 /* Abort any on-going scan */
3338 brcmf_abort_scanning(cfg);
3339 }
3340
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003341 brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003342 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3343 cfg->escan_info.run = brcmf_run_escan;
3344 err = brcmf_do_escan(ifp, request);
3345 if (err) {
3346 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3347 return err;
3348 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003349 cfg->int_escan_map = fwmap;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003350 return 0;
3351}
3352
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003353static struct brcmf_pno_net_info_le *
3354brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3355{
3356 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3357 struct brcmf_pno_net_info_le *netinfo;
3358
3359 switch (pfn_v1->version) {
3360 default:
3361 WARN_ON(1);
3362 /* fall-thru */
3363 case cpu_to_le32(1):
3364 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3365 break;
3366 case cpu_to_le32(2):
3367 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3368 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3369 break;
3370 }
3371
3372 return netinfo;
3373}
3374
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003375/* PFN result doesn't have all the info which are required by the supplicant
3376 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3377 * via wl_inform_single_bss in the required format. Escan does require the
3378 * scan request in the form of cfg80211_scan_request. For timebeing, create
3379 * cfg80211_scan_request one out of the received PNO event.
3380 */
3381static s32
3382brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3383 const struct brcmf_event_msg *e, void *data)
3384{
3385 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3386 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3387 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003388 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003389 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003390 struct brcmf_pno_scanresults_le *pfn_result;
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003391 u32 bucket_map;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003392 u32 result_count;
3393 u32 status;
Arend Van Spriel4835f372017-04-06 13:14:40 +01003394 u32 datalen;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003395
3396 brcmf_dbg(SCAN, "Enter\n");
3397
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003398 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3399 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3400 return 0;
3401 }
3402
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003403 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3404 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3405 return 0;
3406 }
3407
3408 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3409 result_count = le32_to_cpu(pfn_result->count);
3410 status = le32_to_cpu(pfn_result->status);
3411
3412 /* PFN event is limited to fit 512 bytes so we may get
3413 * multiple NET_FOUND events. For now place a warning here.
3414 */
3415 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3416 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003417 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003418 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3419 goto out_err;
3420 }
Arend Van Spriel4835f372017-04-06 13:14:40 +01003421
3422 netinfo_start = brcmf_get_netinfo_array(pfn_result);
3423 datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
3424 if (datalen < result_count * sizeof(*netinfo)) {
3425 brcmf_err("insufficient event data\n");
3426 goto out_err;
3427 }
3428
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003429 request = brcmf_alloc_internal_escan_request(wiphy,
3430 result_count);
3431 if (!request) {
3432 err = -ENOMEM;
3433 goto out_err;
3434 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003435
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003436 bucket_map = 0;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003437 for (i = 0; i < result_count; i++) {
3438 netinfo = &netinfo_start[i];
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003439
Arend Van Spriel4835f372017-04-06 13:14:40 +01003440 if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
3441 netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003442 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3443 netinfo->SSID, netinfo->channel);
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003444 bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003445 err = brcmf_internal_escan_add_info(request,
3446 netinfo->SSID,
3447 netinfo->SSID_len,
3448 netinfo->channel);
3449 if (err)
3450 goto out_err;
3451 }
3452
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003453 if (!bucket_map)
3454 goto free_req;
3455
3456 err = brcmf_start_internal_escan(ifp, bucket_map, request);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003457 if (!err)
3458 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003459
3460out_err:
Arend Van Sprielb34939b2017-04-28 13:40:28 +01003461 cfg80211_sched_scan_stopped(wiphy, 0);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003462free_req:
3463 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003464 return err;
3465}
3466
3467static int
3468brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3469 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003470 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003471{
3472 struct brcmf_if *ifp = netdev_priv(ndev);
3473 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003474
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003475 brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003476 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003477
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003478 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003479 brcmf_err("Scanning suppressed: status=%lu\n",
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003480 cfg->scan_status);
3481 return -EAGAIN;
3482 }
3483
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003484 if (req->n_match_sets <= 0) {
3485 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3486 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003487 return -EINVAL;
3488 }
3489
Arend Van Spriel3e486112016-11-23 10:25:27 +00003490 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003491}
3492
3493static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003494 struct net_device *ndev, u64 reqid)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003495{
3496 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003497 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003498
3499 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01003500 brcmf_pno_stop_sched_scan(ifp, reqid);
3501 if (cfg->int_escan_map)
Arend Van Sprielac551362016-11-23 10:25:22 +00003502 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003503 return 0;
3504}
3505
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003506static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003507{
3508 if (ms < 1000 / HZ) {
3509 cond_resched();
3510 mdelay(ms);
3511 } else {
3512 msleep(ms);
3513 }
3514}
3515
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003516static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3517 u8 *pattern, u32 patternsize, u8 *mask,
3518 u32 packet_offset)
3519{
3520 struct brcmf_fil_wowl_pattern_le *filter;
3521 u32 masksize;
3522 u32 patternoffset;
3523 u8 *buf;
3524 u32 bufsize;
3525 s32 ret;
3526
3527 masksize = (patternsize + 7) / 8;
3528 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3529
3530 bufsize = sizeof(*filter) + patternsize + masksize;
3531 buf = kzalloc(bufsize, GFP_KERNEL);
3532 if (!buf)
3533 return -ENOMEM;
3534 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3535
3536 memcpy(filter->cmd, cmd, 4);
3537 filter->masksize = cpu_to_le32(masksize);
3538 filter->offset = cpu_to_le32(packet_offset);
3539 filter->patternoffset = cpu_to_le32(patternoffset);
3540 filter->patternsize = cpu_to_le32(patternsize);
3541 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3542
3543 if ((mask) && (masksize))
3544 memcpy(buf + sizeof(*filter), mask, masksize);
3545 if ((pattern) && (patternsize))
3546 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3547
3548 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3549
3550 kfree(buf);
3551 return ret;
3552}
3553
Hante Meuleman3021ad92016-01-05 11:05:45 +01003554static s32
3555brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3556 void *data)
3557{
3558 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3559 struct brcmf_pno_scanresults_le *pfn_result;
3560 struct brcmf_pno_net_info_le *netinfo;
3561
3562 brcmf_dbg(SCAN, "Enter\n");
3563
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003564 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3565 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3566 return 0;
3567 }
3568
Hante Meuleman3021ad92016-01-05 11:05:45 +01003569 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3570
3571 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3572 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3573 return 0;
3574 }
3575
3576 if (le32_to_cpu(pfn_result->count) < 1) {
3577 brcmf_err("Invalid result count, expected 1 (%d)\n",
3578 le32_to_cpu(pfn_result->count));
3579 return -EINVAL;
3580 }
3581
Arend Van Sprield29afe92017-01-27 12:27:46 +00003582 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003583 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3584 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3585 cfg->wowl.nd->n_channels = 1;
3586 cfg->wowl.nd->channels[0] =
3587 ieee80211_channel_to_frequency(netinfo->channel,
3588 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3589 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3590 cfg->wowl.nd_info->n_matches = 1;
3591 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3592
3593 /* Inform (the resume task) that the net detect information was recvd */
3594 cfg->wowl.nd_data_completed = true;
3595 wake_up(&cfg->wowl.nd_data_wait);
3596
3597 return 0;
3598}
3599
Hante Meulemanaeb64222015-10-29 20:33:19 +01003600#ifdef CONFIG_PM
3601
3602static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3603{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003604 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003605 struct brcmf_wowl_wakeind_le wake_ind_le;
3606 struct cfg80211_wowlan_wakeup wakeup_data;
3607 struct cfg80211_wowlan_wakeup *wakeup;
3608 u32 wakeind;
3609 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003610 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003611
3612 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3613 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003614 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003615 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3616 return;
3617 }
3618
3619 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3620 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003621 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3622 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003623 wakeup = &wakeup_data;
3624 memset(&wakeup_data, 0, sizeof(wakeup_data));
3625 wakeup_data.pattern_idx = -1;
3626
3627 if (wakeind & BRCMF_WOWL_MAGIC) {
3628 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3629 wakeup_data.magic_pkt = true;
3630 }
3631 if (wakeind & BRCMF_WOWL_DIS) {
3632 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3633 wakeup_data.disconnect = true;
3634 }
3635 if (wakeind & BRCMF_WOWL_BCN) {
3636 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3637 wakeup_data.disconnect = true;
3638 }
3639 if (wakeind & BRCMF_WOWL_RETR) {
3640 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3641 wakeup_data.disconnect = true;
3642 }
3643 if (wakeind & BRCMF_WOWL_NET) {
3644 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3645 /* For now always map to pattern 0, no API to get
3646 * correct information available at the moment.
3647 */
3648 wakeup_data.pattern_idx = 0;
3649 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003650 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3651 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3652 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3653 cfg->wowl.nd_data_completed,
3654 BRCMF_ND_INFO_TIMEOUT);
3655 if (!timeout)
3656 brcmf_err("No result for wowl net detect\n");
3657 else
3658 wakeup_data.net_detect = cfg->wowl.nd_info;
3659 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003660 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3661 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3662 wakeup_data.gtk_rekey_failure = true;
3663 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003664 } else {
3665 wakeup = NULL;
3666 }
3667 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3668}
3669
3670#else
3671
3672static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3673{
3674}
3675
3676#endif /* CONFIG_PM */
3677
Arend van Spriel5b435de2011-10-05 13:19:03 +02003678static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3679{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003680 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3681 struct net_device *ndev = cfg_to_ndev(cfg);
3682 struct brcmf_if *ifp = netdev_priv(ndev);
3683
Arend van Sprield96b8012012-12-05 15:26:02 +01003684 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003685
Hante Meuleman3021ad92016-01-05 11:05:45 +01003686 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003687 brcmf_report_wowl_wakeind(wiphy, ifp);
3688 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3689 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003690 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3691 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003692 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003693 cfg->wowl.pre_pmmode);
3694 cfg->wowl.active = false;
3695 if (cfg->wowl.nd_enabled) {
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003696 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003697 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3698 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3699 brcmf_notify_sched_scan_results);
3700 cfg->wowl.nd_enabled = false;
3701 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003702 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003703 return 0;
3704}
3705
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003706static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3707 struct brcmf_if *ifp,
3708 struct cfg80211_wowlan *wowl)
3709{
3710 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003711 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003712 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003713
3714 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3715
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003716 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3717 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003718 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003719 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3720
3721 wowl_config = 0;
3722 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003723 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003724 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003725 wowl_config |= BRCMF_WOWL_MAGIC;
3726 if ((wowl->patterns) && (wowl->n_patterns)) {
3727 wowl_config |= BRCMF_WOWL_NET;
3728 for (i = 0; i < wowl->n_patterns; i++) {
3729 brcmf_config_wowl_pattern(ifp, "add",
3730 (u8 *)wowl->patterns[i].pattern,
3731 wowl->patterns[i].pattern_len,
3732 (u8 *)wowl->patterns[i].mask,
3733 wowl->patterns[i].pkt_offset);
3734 }
3735 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003736 if (wowl->nd_config) {
3737 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3738 wowl->nd_config);
3739 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3740
3741 cfg->wowl.nd_data_completed = false;
3742 cfg->wowl.nd_enabled = true;
3743 /* Now reroute the event for PFN to the wowl function. */
3744 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3745 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3746 brcmf_wowl_nd_results);
3747 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003748 if (wowl->gtk_rekey_failure)
3749 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003750 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3751 wowl_config |= BRCMF_WOWL_UNASSOC;
3752
Hante Meulemana7ed7822016-09-19 12:09:58 +01003753 memcpy(&wowl_wakeind, "clear", 6);
3754 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3755 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003756 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3757 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3758 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003759 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003760}
3761
Arend van Spriel5b435de2011-10-05 13:19:03 +02003762static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003763 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003765 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3766 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003767 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003768 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769
Arend van Sprield96b8012012-12-05 15:26:02 +01003770 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003771
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003772 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003773 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003774 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003775 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003776 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777
Hante Meuleman3021ad92016-01-05 11:05:45 +01003778 /* Stop scheduled scan */
3779 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003780 brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003781
Arend van Spriel7d641072012-10-22 13:55:39 -07003782 /* end any scanning */
3783 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003784 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003785
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003786 if (wowl == NULL) {
3787 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3788 list_for_each_entry(vif, &cfg->vif_list, list) {
3789 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3790 continue;
3791 /* While going to suspend if associated with AP
3792 * disassociate from AP to save power while system is
3793 * in suspended state
3794 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003795 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003796 /* Make sure WPA_Supplicant receives all the event
3797 * generated due to DISASSOC call to the fw to keep
3798 * the state fw and WPA_Supplicant state consistent
3799 */
3800 brcmf_delay(500);
3801 }
3802 /* Configure MPC */
3803 brcmf_set_mpc(ifp, 1);
3804
3805 } else {
3806 /* Configure WOWL paramaters */
3807 brcmf_configure_wowl(cfg, ifp, wowl);
3808 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003809
Arend van Spriel7d641072012-10-22 13:55:39 -07003810exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003811 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003812 /* clear any scanning activity */
3813 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003814 return 0;
3815}
3816
3817static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003818brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003819{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003820 struct brcmf_pmk_list_le *pmk_list;
3821 int i;
3822 u32 npmk;
3823 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003824
Hante Meuleman6c404f32015-12-10 13:43:03 +01003825 pmk_list = &cfg->pmk_list;
3826 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003827
Hante Meuleman6c404f32015-12-10 13:43:03 +01003828 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3829 for (i = 0; i < npmk; i++)
3830 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003831
Hante Meuleman6c404f32015-12-10 13:43:03 +01003832 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3833 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003834
3835 return err;
3836}
3837
3838static s32
3839brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3840 struct cfg80211_pmksa *pmksa)
3841{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003842 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003843 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003844 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3845 s32 err;
3846 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003847
Arend van Sprield96b8012012-12-05 15:26:02 +01003848 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003849 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003850 return -EIO;
3851
Hante Meuleman6c404f32015-12-10 13:43:03 +01003852 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3853 for (i = 0; i < npmk; i++)
3854 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003855 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003856 if (i < BRCMF_MAXPMKID) {
3857 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3858 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3859 if (i == npmk) {
3860 npmk++;
3861 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003862 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003863 } else {
3864 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3865 return -EINVAL;
3866 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003867
Hante Meuleman6c404f32015-12-10 13:43:03 +01003868 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3869 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3870 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3871 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3872 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003873
Hante Meuleman6c404f32015-12-10 13:43:03 +01003874 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003875
Arend van Sprield96b8012012-12-05 15:26:02 +01003876 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003877 return err;
3878}
3879
3880static s32
3881brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003882 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003883{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003884 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003885 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003886 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3887 s32 err;
3888 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003889
Arend van Sprield96b8012012-12-05 15:26:02 +01003890 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003891 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003892 return -EIO;
3893
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003894 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003895
Hante Meuleman6c404f32015-12-10 13:43:03 +01003896 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3897 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003898 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003899 break;
3900
Hante Meuleman6c404f32015-12-10 13:43:03 +01003901 if ((npmk > 0) && (i < npmk)) {
3902 for (; i < (npmk - 1); i++) {
3903 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3904 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003905 WLAN_PMKID_LEN);
3906 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003907 memset(&pmk[i], 0, sizeof(*pmk));
3908 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3909 } else {
3910 brcmf_err("Cache entry not found\n");
3911 return -EINVAL;
3912 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003913
Hante Meuleman6c404f32015-12-10 13:43:03 +01003914 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003915
Arend van Sprield96b8012012-12-05 15:26:02 +01003916 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003917 return err;
3918
3919}
3920
3921static s32
3922brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3923{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003924 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003925 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003926 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003927
Arend van Sprield96b8012012-12-05 15:26:02 +01003928 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003929 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003930 return -EIO;
3931
Hante Meuleman6c404f32015-12-10 13:43:03 +01003932 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3933 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003934
Arend van Sprield96b8012012-12-05 15:26:02 +01003935 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003936 return err;
3937
3938}
3939
Hante Meuleman1f170112013-02-06 18:40:38 +01003940static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003941{
3942 s32 err;
3943
3944 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003945 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003946 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003947 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 return err;
3949 }
3950 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003951 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003952 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003953 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003954 return err;
3955 }
3956 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003957 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003958 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003959 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003960 return err;
3961 }
3962
3963 return 0;
3964}
3965
3966static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3967{
3968 if (is_rsn_ie)
3969 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3970
3971 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3972}
3973
3974static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003975brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003976 const struct brcmf_vs_tlv *wpa_ie,
3977 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003978{
3979 u32 auth = 0; /* d11 open authentication */
3980 u16 count;
3981 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003982 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003983 u32 i;
3984 u32 wsec;
3985 u32 pval = 0;
3986 u32 gval = 0;
3987 u32 wpa_auth = 0;
3988 u32 offset;
3989 u8 *data;
3990 u16 rsn_cap;
3991 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003992 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003993
Arend van Sprield96b8012012-12-05 15:26:02 +01003994 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003995 if (wpa_ie == NULL)
3996 goto exit;
3997
3998 len = wpa_ie->len + TLV_HDR_LEN;
3999 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004000 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004001 if (!is_rsn_ie)
4002 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01004003 else
4004 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004005
4006 /* check for multicast cipher suite */
4007 if (offset + WPA_IE_MIN_OUI_LEN > len) {
4008 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004009 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004010 goto exit;
4011 }
4012
4013 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4014 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004015 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004016 goto exit;
4017 }
4018 offset += TLV_OUI_LEN;
4019
4020 /* pick up multicast cipher */
4021 switch (data[offset]) {
4022 case WPA_CIPHER_NONE:
4023 gval = 0;
4024 break;
4025 case WPA_CIPHER_WEP_40:
4026 case WPA_CIPHER_WEP_104:
4027 gval = WEP_ENABLED;
4028 break;
4029 case WPA_CIPHER_TKIP:
4030 gval = TKIP_ENABLED;
4031 break;
4032 case WPA_CIPHER_AES_CCM:
4033 gval = AES_ENABLED;
4034 break;
4035 default:
4036 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004037 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004038 goto exit;
4039 }
4040
4041 offset++;
4042 /* walk thru unicast cipher list and pick up what we recognize */
4043 count = data[offset] + (data[offset + 1] << 8);
4044 offset += WPA_IE_SUITE_COUNT_LEN;
4045 /* Check for unicast suite(s) */
4046 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4047 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004048 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004049 goto exit;
4050 }
4051 for (i = 0; i < count; i++) {
4052 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4053 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004054 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004055 goto exit;
4056 }
4057 offset += TLV_OUI_LEN;
4058 switch (data[offset]) {
4059 case WPA_CIPHER_NONE:
4060 break;
4061 case WPA_CIPHER_WEP_40:
4062 case WPA_CIPHER_WEP_104:
4063 pval |= WEP_ENABLED;
4064 break;
4065 case WPA_CIPHER_TKIP:
4066 pval |= TKIP_ENABLED;
4067 break;
4068 case WPA_CIPHER_AES_CCM:
4069 pval |= AES_ENABLED;
4070 break;
4071 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004072 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004073 }
4074 offset++;
4075 }
4076 /* walk thru auth management suite list and pick up what we recognize */
4077 count = data[offset] + (data[offset + 1] << 8);
4078 offset += WPA_IE_SUITE_COUNT_LEN;
4079 /* Check for auth key management suite(s) */
4080 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4081 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004082 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004083 goto exit;
4084 }
4085 for (i = 0; i < count; i++) {
4086 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4087 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004088 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004089 goto exit;
4090 }
4091 offset += TLV_OUI_LEN;
4092 switch (data[offset]) {
4093 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004094 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004095 wpa_auth |= WPA_AUTH_NONE;
4096 break;
4097 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004098 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004099 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4100 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4101 break;
4102 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004103 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004104 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4105 (wpa_auth |= WPA_AUTH_PSK);
4106 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004107 case RSN_AKM_SHA256_PSK:
4108 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4109 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4110 break;
4111 case RSN_AKM_SHA256_1X:
4112 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4113 wpa_auth |= WPA2_AUTH_1X_SHA256;
4114 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004115 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004116 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004117 }
4118 offset++;
4119 }
4120
Hante Meuleman240d61a2016-02-17 11:27:10 +01004121 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004122 if (is_rsn_ie) {
4123 wme_bss_disable = 1;
4124 if ((offset + RSN_CAP_LEN) <= len) {
4125 rsn_cap = data[offset] + (data[offset + 1] << 8);
4126 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4127 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004128 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4129 brcmf_dbg(TRACE, "MFP Required\n");
4130 mfp = BRCMF_MFP_REQUIRED;
4131 /* Firmware only supports mfp required in
4132 * combination with WPA2_AUTH_PSK_SHA256 or
4133 * WPA2_AUTH_1X_SHA256.
4134 */
4135 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4136 WPA2_AUTH_1X_SHA256))) {
4137 err = -EINVAL;
4138 goto exit;
4139 }
4140 /* Firmware has requirement that WPA2_AUTH_PSK/
4141 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4142 * is to be included in the rsn ie.
4143 */
4144 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4145 wpa_auth |= WPA2_AUTH_PSK;
4146 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4147 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4148 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4149 brcmf_dbg(TRACE, "MFP Capable\n");
4150 mfp = BRCMF_MFP_CAPABLE;
4151 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004152 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004153 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004154 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004155 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004156 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004157 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004158 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004159 goto exit;
4160 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004161
4162 /* Skip PMKID cnt as it is know to be 0 for AP. */
4163 offset += RSN_PMKID_COUNT_LEN;
4164
4165 /* See if there is BIP wpa suite left for MFP */
4166 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4167 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4168 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4169 &data[offset],
4170 WPA_IE_MIN_OUI_LEN);
4171 if (err < 0) {
4172 brcmf_err("bip error %d\n", err);
4173 goto exit;
4174 }
4175 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004176 }
4177 /* FOR WPS , set SES_OW_ENABLED */
4178 wsec = (pval | gval | SES_OW_ENABLED);
4179
4180 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004181 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004182 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004183 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004184 goto exit;
4185 }
4186 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004187 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004188 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004189 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004190 goto exit;
4191 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004192 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4193 * will overwrite the values set by MFP
4194 */
4195 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4196 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4197 if (err < 0) {
4198 brcmf_err("mfp error %d\n", err);
4199 goto exit;
4200 }
4201 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004202 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004203 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004204 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004205 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004206 goto exit;
4207 }
4208
4209exit:
4210 return err;
4211}
4212
4213static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004214brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004215 struct parsed_vndr_ies *vndr_ies)
4216{
Hante Meuleman1a873342012-09-27 14:17:54 +02004217 struct brcmf_vs_tlv *vndrie;
4218 struct brcmf_tlv *ie;
4219 struct parsed_vndr_ie_info *parsed_info;
4220 s32 remaining_len;
4221
4222 remaining_len = (s32)vndr_ie_len;
4223 memset(vndr_ies, 0, sizeof(*vndr_ies));
4224
4225 ie = (struct brcmf_tlv *)vndr_ie_buf;
4226 while (ie) {
4227 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4228 goto next;
4229 vndrie = (struct brcmf_vs_tlv *)ie;
4230 /* len should be bigger than OUI length + one */
4231 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004232 brcmf_err("invalid vndr ie. length is too small %d\n",
4233 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004234 goto next;
4235 }
4236 /* if wpa or wme ie, do not add ie */
4237 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4238 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4239 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004240 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004241 goto next;
4242 }
4243
4244 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4245
4246 /* save vndr ie information */
4247 parsed_info->ie_ptr = (char *)vndrie;
4248 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4249 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4250
4251 vndr_ies->count++;
4252
Arend van Sprield96b8012012-12-05 15:26:02 +01004253 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4254 parsed_info->vndrie.oui[0],
4255 parsed_info->vndrie.oui[1],
4256 parsed_info->vndrie.oui[2],
4257 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004258
Arend van Spriel9f440b72013-02-08 15:53:36 +01004259 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004260 break;
4261next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004262 remaining_len -= (ie->len + TLV_HDR_LEN);
4263 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004264 ie = NULL;
4265 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004266 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4267 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004268 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004269 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004270}
4271
4272static u32
4273brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4274{
4275
Hante Meuleman1a873342012-09-27 14:17:54 +02004276 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4277 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4278
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304279 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004280
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304281 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004282
4283 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4284
4285 return ie_len + VNDR_IE_HDR_SIZE;
4286}
4287
Arend van Spriel1332e262012-11-05 16:22:18 -08004288s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4289 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004290{
Arend van Spriel1332e262012-11-05 16:22:18 -08004291 struct brcmf_if *ifp;
4292 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004293 s32 err = 0;
4294 u8 *iovar_ie_buf;
4295 u8 *curr_ie_buf;
4296 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004297 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004298 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004299 u32 del_add_ie_buf_len = 0;
4300 u32 total_ie_buf_len = 0;
4301 u32 parsed_ie_buf_len = 0;
4302 struct parsed_vndr_ies old_vndr_ies;
4303 struct parsed_vndr_ies new_vndr_ies;
4304 struct parsed_vndr_ie_info *vndrie_info;
4305 s32 i;
4306 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004307 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004308
Arend van Spriel1332e262012-11-05 16:22:18 -08004309 if (!vif)
4310 return -ENODEV;
4311 ifp = vif->ifp;
4312 saved_ie = &vif->saved_ie;
4313
Hante Meuleman37a869e2015-10-29 20:33:17 +01004314 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4315 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004316 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4317 if (!iovar_ie_buf)
4318 return -ENOMEM;
4319 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004320 switch (pktflag) {
4321 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4322 mgmt_ie_buf = saved_ie->probe_req_ie;
4323 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4324 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4325 break;
4326 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4327 mgmt_ie_buf = saved_ie->probe_res_ie;
4328 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4329 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4330 break;
4331 case BRCMF_VNDR_IE_BEACON_FLAG:
4332 mgmt_ie_buf = saved_ie->beacon_ie;
4333 mgmt_ie_len = &saved_ie->beacon_ie_len;
4334 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4335 break;
4336 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4337 mgmt_ie_buf = saved_ie->assoc_req_ie;
4338 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4339 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4340 break;
4341 default:
4342 err = -EPERM;
4343 brcmf_err("not suitable type\n");
4344 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004345 }
4346
4347 if (vndr_ie_len > mgmt_ie_buf_len) {
4348 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004349 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004350 goto exit;
4351 }
4352
4353 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4354 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4355 ptr = curr_ie_buf;
4356 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4357 for (i = 0; i < new_vndr_ies.count; i++) {
4358 vndrie_info = &new_vndr_ies.ie_info[i];
4359 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4360 vndrie_info->ie_len);
4361 parsed_ie_buf_len += vndrie_info->ie_len;
4362 }
4363 }
4364
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004365 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004366 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4367 (memcmp(mgmt_ie_buf, curr_ie_buf,
4368 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004369 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004370 goto exit;
4371 }
4372
4373 /* parse old vndr_ie */
4374 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4375
4376 /* make a command to delete old ie */
4377 for (i = 0; i < old_vndr_ies.count; i++) {
4378 vndrie_info = &old_vndr_ies.ie_info[i];
4379
Arend van Sprield96b8012012-12-05 15:26:02 +01004380 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4381 vndrie_info->vndrie.id,
4382 vndrie_info->vndrie.len,
4383 vndrie_info->vndrie.oui[0],
4384 vndrie_info->vndrie.oui[1],
4385 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004386
4387 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4388 vndrie_info->ie_ptr,
4389 vndrie_info->ie_len,
4390 "del");
4391 curr_ie_buf += del_add_ie_buf_len;
4392 total_ie_buf_len += del_add_ie_buf_len;
4393 }
4394 }
4395
4396 *mgmt_ie_len = 0;
4397 /* Add if there is any extra IE */
4398 if (mgmt_ie_buf && parsed_ie_buf_len) {
4399 ptr = mgmt_ie_buf;
4400
4401 remained_buf_len = mgmt_ie_buf_len;
4402
4403 /* make a command to add new ie */
4404 for (i = 0; i < new_vndr_ies.count; i++) {
4405 vndrie_info = &new_vndr_ies.ie_info[i];
4406
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004407 /* verify remained buf size before copy data */
4408 if (remained_buf_len < (vndrie_info->vndrie.len +
4409 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004410 brcmf_err("no space in mgmt_ie_buf: len left %d",
4411 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004412 break;
4413 }
4414 remained_buf_len -= (vndrie_info->ie_len +
4415 VNDR_IE_VSIE_OFFSET);
4416
Arend van Sprield96b8012012-12-05 15:26:02 +01004417 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4418 vndrie_info->vndrie.id,
4419 vndrie_info->vndrie.len,
4420 vndrie_info->vndrie.oui[0],
4421 vndrie_info->vndrie.oui[1],
4422 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004423
4424 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4425 vndrie_info->ie_ptr,
4426 vndrie_info->ie_len,
4427 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004428
4429 /* save the parsed IE in wl struct */
4430 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4431 vndrie_info->ie_len);
4432 *mgmt_ie_len += vndrie_info->ie_len;
4433
4434 curr_ie_buf += del_add_ie_buf_len;
4435 total_ie_buf_len += del_add_ie_buf_len;
4436 }
4437 }
4438 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004439 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004440 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004441 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004442 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004443 }
4444
4445exit:
4446 kfree(iovar_ie_buf);
4447 return err;
4448}
4449
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004450s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4451{
4452 s32 pktflags[] = {
4453 BRCMF_VNDR_IE_PRBREQ_FLAG,
4454 BRCMF_VNDR_IE_PRBRSP_FLAG,
4455 BRCMF_VNDR_IE_BEACON_FLAG
4456 };
4457 int i;
4458
4459 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4460 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4461
4462 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4463 return 0;
4464}
4465
Hante Meuleman1a873342012-09-27 14:17:54 +02004466static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004467brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4468 struct cfg80211_beacon_data *beacon)
4469{
4470 s32 err;
4471
4472 /* Set Beacon IEs to FW */
4473 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4474 beacon->tail, beacon->tail_len);
4475 if (err) {
4476 brcmf_err("Set Beacon IE Failed\n");
4477 return err;
4478 }
4479 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4480
4481 /* Set Probe Response IEs to FW */
4482 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4483 beacon->proberesp_ies,
4484 beacon->proberesp_ies_len);
4485 if (err)
4486 brcmf_err("Set Probe Resp IE Failed\n");
4487 else
4488 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4489
4490 return err;
4491}
4492
4493static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004494brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4495 struct cfg80211_ap_settings *settings)
4496{
4497 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004498 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004499 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004500 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004501 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004502 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004503 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004504 const struct brcmf_tlv *rsn_ie;
4505 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004506 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004507 enum nl80211_iftype dev_role;
4508 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004509 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004510 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004511 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004512 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004513
Arend van Spriel06c01582014-05-12 10:47:37 +02004514 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4515 settings->chandef.chan->hw_value,
4516 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004517 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004518 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4519 settings->ssid, settings->ssid_len, settings->auth_type,
4520 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004521 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004522 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004523
Arend van Spriel98027762014-12-21 12:43:53 +01004524 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004525 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4526 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004527 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004528 } else {
4529 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4530 settings->beacon.tail_len,
4531 WLAN_EID_COUNTRY);
4532 is_11d = country_ie ? 1 : 0;
4533 supports_11d = true;
4534 }
Arend van Spriel98027762014-12-21 12:43:53 +01004535
Hante Meuleman1a873342012-09-27 14:17:54 +02004536 memset(&ssid_le, 0, sizeof(ssid_le));
4537 if (settings->ssid == NULL || settings->ssid_len == 0) {
4538 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4539 ssid_ie = brcmf_parse_tlvs(
4540 (u8 *)&settings->beacon.head[ie_offset],
4541 settings->beacon.head_len - ie_offset,
4542 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004543 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004544 return -EINVAL;
4545
4546 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4547 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004548 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004549 } else {
4550 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4551 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4552 }
4553
Hante Meulemana44aa402014-12-03 21:05:33 +01004554 if (!mbss) {
4555 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004556 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004557 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004558
4559 /* find the RSN_IE */
4560 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4561 settings->beacon.tail_len, WLAN_EID_RSN);
4562
4563 /* find the WPA_IE */
4564 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4565 settings->beacon.tail_len);
4566
Hante Meuleman1a873342012-09-27 14:17:54 +02004567 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004568 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004569 if (wpa_ie != NULL) {
4570 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004571 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004572 if (err < 0)
4573 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004575 struct brcmf_vs_tlv *tmp_ie;
4576
4577 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4578
Hante Meuleman1a873342012-09-27 14:17:54 +02004579 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004580 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004581 if (err < 0)
4582 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004583 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004584 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004585 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004586 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004587 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004588
Rafał Miłecki8707e082016-05-27 21:07:19 +02004589 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004590 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004591 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004592 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4593 is_11d);
4594 if (err < 0) {
4595 brcmf_err("Regulatory Set Error, %d\n", err);
4596 goto exit;
4597 }
4598 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004599 if (settings->beacon_interval) {
4600 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4601 settings->beacon_interval);
4602 if (err < 0) {
4603 brcmf_err("Beacon Interval Set Error, %d\n",
4604 err);
4605 goto exit;
4606 }
4607 }
4608 if (settings->dtim_period) {
4609 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4610 settings->dtim_period);
4611 if (err < 0) {
4612 brcmf_err("DTIM Interval Set Error, %d\n", err);
4613 goto exit;
4614 }
4615 }
4616
Hante Meuleman8abffd82015-10-29 20:33:16 +01004617 if ((dev_role == NL80211_IFTYPE_AP) &&
4618 ((ifp->ifidx == 0) ||
4619 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004620 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4621 if (err < 0) {
4622 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4623 goto exit;
4624 }
4625 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4626 }
4627
4628 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004629 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004630 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004631 goto exit;
4632 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004633 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004634 /* Multiple-BSS should use same 11d configuration */
4635 err = -EINVAL;
4636 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004637 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004638
4639 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004640 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004641 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4642 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4643
Hante Meulemana0f07952013-02-08 15:53:47 +01004644 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4645 if (err < 0) {
4646 brcmf_err("setting AP mode failed %d\n", err);
4647 goto exit;
4648 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004649 if (!mbss) {
4650 /* Firmware 10.x requires setting channel after enabling
4651 * AP and before bringing interface up.
4652 */
4653 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4654 if (err < 0) {
4655 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4656 chanspec, err);
4657 goto exit;
4658 }
4659 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004660 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4661 if (err < 0) {
4662 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4663 goto exit;
4664 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004665 /* On DOWN the firmware removes the WEP keys, reconfigure
4666 * them if they were set.
4667 */
4668 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004669
4670 memset(&join_params, 0, sizeof(join_params));
4671 /* join parameters starts with ssid */
4672 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4673 /* create softap */
4674 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4675 &join_params, sizeof(join_params));
4676 if (err < 0) {
4677 brcmf_err("SET SSID error (%d)\n", err);
4678 goto exit;
4679 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004680
4681 if (settings->hidden_ssid) {
4682 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4683 if (err) {
4684 brcmf_err("closednet error (%d)\n", err);
4685 goto exit;
4686 }
4687 }
4688
Hante Meulemana0f07952013-02-08 15:53:47 +01004689 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004690 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4691 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4692 if (err < 0) {
4693 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4694 chanspec, err);
4695 goto exit;
4696 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004697 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4698 sizeof(ssid_le));
4699 if (err < 0) {
4700 brcmf_err("setting ssid failed %d\n", err);
4701 goto exit;
4702 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004703 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004704 bss_enable.enable = cpu_to_le32(1);
4705 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4706 sizeof(bss_enable));
4707 if (err < 0) {
4708 brcmf_err("bss_enable config failed %d\n", err);
4709 goto exit;
4710 }
4711
4712 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004713 } else {
4714 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004715 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004716
Wright Fengf25ba692016-11-18 09:59:52 +08004717 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004718 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004719 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004720
4721exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004722 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004723 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004724 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004725 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004726 return err;
4727}
4728
4729static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4730{
Arend van Sprielc1179032012-10-22 13:55:33 -07004731 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004732 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004733 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004734 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004735
Arend van Sprield96b8012012-12-05 15:26:02 +01004736 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004737
Hante Meuleman426d0a52013-02-08 15:53:53 +01004738 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004739 /* Due to most likely deauths outstanding we sleep */
4740 /* first to make sure they get processed by fw. */
4741 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004742
Hante Meulemana44aa402014-12-03 21:05:33 +01004743 if (ifp->vif->mbss) {
4744 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4745 return err;
4746 }
4747
Rafał Miłeckic940de12016-07-06 12:22:54 +02004748 /* First BSS doesn't get a full reset */
4749 if (ifp->bsscfgidx == 0)
4750 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4751
Hante Meuleman5c33a942013-04-02 21:06:18 +02004752 memset(&join_params, 0, sizeof(join_params));
4753 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4754 &join_params, sizeof(join_params));
4755 if (err < 0)
4756 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004757 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004758 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004759 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004760 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4761 if (err < 0)
4762 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004763 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4764 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004765 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4766 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004767 /* Bring device back up so it can be used again */
4768 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4769 if (err < 0)
4770 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004771
4772 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004773 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004774 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004775 bss_enable.enable = cpu_to_le32(0);
4776 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4777 sizeof(bss_enable));
4778 if (err < 0)
4779 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004780 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004781 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004782 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004783 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004784 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004785
Hante Meuleman1a873342012-09-27 14:17:54 +02004786 return err;
4787}
4788
Hante Meulemana0f07952013-02-08 15:53:47 +01004789static s32
4790brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4791 struct cfg80211_beacon_data *info)
4792{
Hante Meulemana0f07952013-02-08 15:53:47 +01004793 struct brcmf_if *ifp = netdev_priv(ndev);
4794 s32 err;
4795
4796 brcmf_dbg(TRACE, "Enter\n");
4797
Hante Meulemana0f07952013-02-08 15:53:47 +01004798 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4799
4800 return err;
4801}
4802
Hante Meuleman1a873342012-09-27 14:17:54 +02004803static int
4804brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004805 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004806{
Hante Meulemana0f07952013-02-08 15:53:47 +01004807 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004808 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004809 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004810 s32 err;
4811
Jouni Malinen89c771e2014-10-10 20:52:40 +03004812 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004813 return -EFAULT;
4814
Jouni Malinen89c771e2014-10-10 20:52:40 +03004815 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004816
Hante Meulemana0f07952013-02-08 15:53:47 +01004817 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4818 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004819 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004820 return -EIO;
4821
Jouni Malinen89c771e2014-10-10 20:52:40 +03004822 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004823 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004824 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004825 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004826 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004827 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004828
Arend van Sprield96b8012012-12-05 15:26:02 +01004829 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004830 return err;
4831}
4832
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004833static int
4834brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4835 const u8 *mac, struct station_parameters *params)
4836{
4837 struct brcmf_if *ifp = netdev_priv(ndev);
4838 s32 err;
4839
4840 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4841 params->sta_flags_mask, params->sta_flags_set);
4842
4843 /* Ignore all 00 MAC */
4844 if (is_zero_ether_addr(mac))
4845 return 0;
4846
4847 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4848 return 0;
4849
4850 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4852 (void *)mac, ETH_ALEN);
4853 else
4854 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4855 (void *)mac, ETH_ALEN);
4856 if (err < 0)
4857 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4858
4859 return err;
4860}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004861
4862static void
4863brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4864 struct wireless_dev *wdev,
4865 u16 frame_type, bool reg)
4866{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004867 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004868 u16 mgmt_type;
4869
4870 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4871
4872 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004873 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004874 if (reg)
4875 vif->mgmt_rx_reg |= BIT(mgmt_type);
4876 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004877 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004878}
4879
4880
4881static int
4882brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004883 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004884{
4885 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004886 struct ieee80211_channel *chan = params->chan;
4887 const u8 *buf = params->buf;
4888 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004889 const struct ieee80211_mgmt *mgmt;
4890 struct brcmf_cfg80211_vif *vif;
4891 s32 err = 0;
4892 s32 ie_offset;
4893 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004894 struct brcmf_fil_action_frame_le *action_frame;
4895 struct brcmf_fil_af_params_le *af_params;
4896 bool ack;
4897 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004898 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004899
4900 brcmf_dbg(TRACE, "Enter\n");
4901
4902 *cookie = 0;
4903
4904 mgmt = (const struct ieee80211_mgmt *)buf;
4905
Hante Meulemana0f07952013-02-08 15:53:47 +01004906 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4907 brcmf_err("Driver only allows MGMT packet type\n");
4908 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004909 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004910
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004911 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4912
Hante Meulemana0f07952013-02-08 15:53:47 +01004913 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4914 /* Right now the only reason to get a probe response */
4915 /* is for p2p listen response or for p2p GO from */
4916 /* wpa_supplicant. Unfortunately the probe is send */
4917 /* on primary ndev, while dongle wants it on the p2p */
4918 /* vif. Since this is only reason for a probe */
4919 /* response to be sent, the vif is taken from cfg. */
4920 /* If ever desired to send proberesp for non p2p */
4921 /* response then data should be checked for */
4922 /* "DIRECT-". Note in future supplicant will take */
4923 /* dedicated p2p wdev to do this and then this 'hack'*/
4924 /* is not needed anymore. */
4925 ie_offset = DOT11_MGMT_HDR_LEN +
4926 DOT11_BCN_PRB_FIXED_LEN;
4927 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004928 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4929 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4930 err = brcmf_vif_set_mgmt_ie(vif,
4931 BRCMF_VNDR_IE_PRBRSP_FLAG,
4932 &buf[ie_offset],
4933 ie_len);
4934 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4935 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004936 } else if (ieee80211_is_action(mgmt->frame_control)) {
Arend van Spriel8f44c9a2017-07-07 21:09:06 +01004937 if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
4938 brcmf_err("invalid action frame length\n");
4939 err = -EINVAL;
4940 goto exit;
4941 }
Hante Meuleman18e2f612013-02-08 15:53:49 +01004942 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4943 if (af_params == NULL) {
4944 brcmf_err("unable to allocate frame\n");
4945 err = -ENOMEM;
4946 goto exit;
4947 }
4948 action_frame = &af_params->action_frame;
4949 /* Add the packet Id */
4950 action_frame->packet_id = cpu_to_le32(*cookie);
4951 /* Add BSSID */
4952 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4953 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4954 /* Add the length exepted for 802.11 header */
4955 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004956 /* Add the channel. Use the one specified as parameter if any or
4957 * the current one (got from the firmware) otherwise
4958 */
4959 if (chan)
4960 freq = chan->center_freq;
4961 else
4962 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4963 &freq);
4964 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004965 af_params->channel = cpu_to_le32(chan_nr);
4966
4967 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4968 le16_to_cpu(action_frame->len));
4969
4970 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004971 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004972
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004973 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004974 af_params);
4975
4976 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4977 GFP_KERNEL);
4978 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004979 } else {
4980 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004981 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004982 }
4983
Hante Meuleman18e2f612013-02-08 15:53:49 +01004984exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004985 return err;
4986}
4987
4988
4989static int
4990brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4991 struct wireless_dev *wdev,
4992 u64 cookie)
4993{
4994 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4995 struct brcmf_cfg80211_vif *vif;
4996 int err = 0;
4997
4998 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4999
5000 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
5001 if (vif == NULL) {
5002 brcmf_err("No p2p device available for probe response\n");
5003 err = -ENODEV;
5004 goto exit;
5005 }
5006 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
5007exit:
5008 return err;
5009}
5010
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005011static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
5012 struct wireless_dev *wdev,
5013 struct cfg80211_chan_def *chandef)
5014{
5015 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5016 struct net_device *ndev = wdev->netdev;
5017 struct brcmf_if *ifp;
5018 struct brcmu_chan ch;
5019 enum nl80211_band band = 0;
5020 enum nl80211_chan_width width = 0;
5021 u32 chanspec;
5022 int freq, err;
5023
5024 if (!ndev)
5025 return -ENODEV;
5026 ifp = netdev_priv(ndev);
5027
5028 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
5029 if (err) {
5030 brcmf_err("chanspec failed (%d)\n", err);
5031 return err;
5032 }
5033
5034 ch.chspec = chanspec;
5035 cfg->d11inf.decchspec(&ch);
5036
5037 switch (ch.band) {
5038 case BRCMU_CHAN_BAND_2G:
5039 band = NL80211_BAND_2GHZ;
5040 break;
5041 case BRCMU_CHAN_BAND_5G:
5042 band = NL80211_BAND_5GHZ;
5043 break;
5044 }
5045
5046 switch (ch.bw) {
5047 case BRCMU_CHAN_BW_80:
5048 width = NL80211_CHAN_WIDTH_80;
5049 break;
5050 case BRCMU_CHAN_BW_40:
5051 width = NL80211_CHAN_WIDTH_40;
5052 break;
5053 case BRCMU_CHAN_BW_20:
5054 width = NL80211_CHAN_WIDTH_20;
5055 break;
5056 case BRCMU_CHAN_BW_80P80:
5057 width = NL80211_CHAN_WIDTH_80P80;
5058 break;
5059 case BRCMU_CHAN_BW_160:
5060 width = NL80211_CHAN_WIDTH_160;
5061 break;
5062 }
5063
5064 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
5065 chandef->chan = ieee80211_get_channel(wiphy, freq);
5066 chandef->width = width;
5067 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
5068 chandef->center_freq2 = 0;
5069
5070 return 0;
5071}
5072
Piotr Haber61730d42013-04-23 12:53:12 +02005073static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
5074 struct wireless_dev *wdev,
5075 enum nl80211_crit_proto_id proto,
5076 u16 duration)
5077{
5078 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5079 struct brcmf_cfg80211_vif *vif;
5080
5081 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5082
5083 /* only DHCP support for now */
5084 if (proto != NL80211_CRIT_PROTO_DHCP)
5085 return -EINVAL;
5086
5087 /* suppress and abort scanning */
5088 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5089 brcmf_abort_scanning(cfg);
5090
5091 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5092}
5093
5094static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5095 struct wireless_dev *wdev)
5096{
5097 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5098 struct brcmf_cfg80211_vif *vif;
5099
5100 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5101
5102 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5103 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5104}
5105
Hante Meuleman70b7d942014-07-30 13:20:07 +02005106static s32
5107brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5108 const struct brcmf_event_msg *e, void *data)
5109{
5110 switch (e->reason) {
5111 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5112 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5113 break;
5114 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5115 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5116 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5117 break;
5118 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5119 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5120 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5121 break;
5122 }
5123
5124 return 0;
5125}
5126
Arend van Spriel89c2f382013-08-10 12:27:25 +02005127static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5128{
5129 int ret;
5130
5131 switch (oper) {
5132 case NL80211_TDLS_DISCOVERY_REQ:
5133 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5134 break;
5135 case NL80211_TDLS_SETUP:
5136 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5137 break;
5138 case NL80211_TDLS_TEARDOWN:
5139 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5140 break;
5141 default:
5142 brcmf_err("unsupported operation: %d\n", oper);
5143 ret = -EOPNOTSUPP;
5144 }
5145 return ret;
5146}
5147
5148static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005149 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005150 enum nl80211_tdls_operation oper)
5151{
5152 struct brcmf_if *ifp;
5153 struct brcmf_tdls_iovar_le info;
5154 int ret = 0;
5155
5156 ret = brcmf_convert_nl80211_tdls_oper(oper);
5157 if (ret < 0)
5158 return ret;
5159
5160 ifp = netdev_priv(ndev);
5161 memset(&info, 0, sizeof(info));
5162 info.mode = (u8)ret;
5163 if (peer)
5164 memcpy(info.ea, peer, ETH_ALEN);
5165
5166 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5167 &info, sizeof(info));
5168 if (ret < 0)
5169 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5170
5171 return ret;
5172}
5173
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005174static int
5175brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5176 struct net_device *ndev,
5177 struct cfg80211_connect_params *sme,
5178 u32 changed)
5179{
5180 struct brcmf_if *ifp;
5181 int err;
5182
5183 if (!(changed & UPDATE_ASSOC_IES))
5184 return 0;
5185
5186 ifp = netdev_priv(ndev);
5187 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5188 sme->ie, sme->ie_len);
5189 if (err)
5190 brcmf_err("Set Assoc REQ IE Failed\n");
5191 else
5192 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5193
5194 return err;
5195}
5196
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005197#ifdef CONFIG_PM
5198static int
5199brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5200 struct cfg80211_gtk_rekey_data *gtk)
5201{
5202 struct brcmf_if *ifp = netdev_priv(ndev);
5203 struct brcmf_gtk_keyinfo_le gtk_le;
5204 int ret;
5205
5206 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5207
5208 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5209 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5210 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5211 sizeof(gtk_le.replay_counter));
5212
5213 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5214 sizeof(gtk_le));
5215 if (ret < 0)
5216 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5217
5218 return ret;
5219}
5220#endif
5221
Arend van Spriel2526ff22017-06-09 13:08:48 +01005222static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
5223 const struct cfg80211_pmk_conf *conf)
5224{
5225 struct brcmf_if *ifp;
5226
5227 brcmf_dbg(TRACE, "enter\n");
5228
5229 /* expect using firmware supplicant for 1X */
5230 ifp = netdev_priv(dev);
5231 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5232 return -EINVAL;
5233
5234 return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
5235}
5236
5237static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
5238 const u8 *aa)
5239{
5240 struct brcmf_if *ifp;
5241
5242 brcmf_dbg(TRACE, "enter\n");
5243 ifp = netdev_priv(dev);
5244 if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
5245 return -EINVAL;
5246
5247 return brcmf_set_pmk(ifp, NULL, 0);
5248}
5249
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005250static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005251 .add_virtual_intf = brcmf_cfg80211_add_iface,
5252 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005253 .change_virtual_intf = brcmf_cfg80211_change_iface,
5254 .scan = brcmf_cfg80211_scan,
5255 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5256 .join_ibss = brcmf_cfg80211_join_ibss,
5257 .leave_ibss = brcmf_cfg80211_leave_ibss,
5258 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005259 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005260 .set_tx_power = brcmf_cfg80211_set_tx_power,
5261 .get_tx_power = brcmf_cfg80211_get_tx_power,
5262 .add_key = brcmf_cfg80211_add_key,
5263 .del_key = brcmf_cfg80211_del_key,
5264 .get_key = brcmf_cfg80211_get_key,
5265 .set_default_key = brcmf_cfg80211_config_default_key,
5266 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5267 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 .connect = brcmf_cfg80211_connect,
5269 .disconnect = brcmf_cfg80211_disconnect,
5270 .suspend = brcmf_cfg80211_suspend,
5271 .resume = brcmf_cfg80211_resume,
5272 .set_pmksa = brcmf_cfg80211_set_pmksa,
5273 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005274 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005275 .start_ap = brcmf_cfg80211_start_ap,
5276 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005277 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005278 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005279 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005280 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5281 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005282 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5283 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5284 .remain_on_channel = brcmf_p2p_remain_on_channel,
5285 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005286 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005287 .start_p2p_device = brcmf_p2p_start_device,
5288 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005289 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5290 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005291 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005292 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel2526ff22017-06-09 13:08:48 +01005293 .set_pmk = brcmf_cfg80211_set_pmk,
5294 .del_pmk = brcmf_cfg80211_del_pmk,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005295};
5296
Arend van Spriel3eacf862012-10-22 13:55:30 -07005297struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005298 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005299{
Hante Meulemana44aa402014-12-03 21:05:33 +01005300 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005301 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005302 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005303
Arend van Spriel33a6b152013-02-08 15:53:39 +01005304 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005305 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005306 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5307 if (!vif)
5308 return ERR_PTR(-ENOMEM);
5309
5310 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005311 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005312
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005313 brcmf_init_prof(&vif->profile);
5314
Hante Meulemana44aa402014-12-03 21:05:33 +01005315 if (type == NL80211_IFTYPE_AP) {
5316 mbss = false;
5317 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5318 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5319 mbss = true;
5320 break;
5321 }
5322 }
5323 vif->mbss = mbss;
5324 }
5325
Arend van Spriel3eacf862012-10-22 13:55:30 -07005326 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005327 return vif;
5328}
5329
Arend van Spriel427dec52014-01-06 12:40:47 +01005330void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005331{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005332 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005333 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005334}
5335
Arend van Spriel9df4d542014-01-06 12:40:49 +01005336void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5337{
5338 struct brcmf_cfg80211_vif *vif;
5339 struct brcmf_if *ifp;
5340
5341 ifp = netdev_priv(ndev);
5342 vif = ifp->vif;
5343
Arend van Spriel95ef1232015-08-26 22:15:04 +02005344 if (vif)
5345 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005346}
5347
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005348static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
5349 const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005350{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005351 u32 event = e->event_code;
5352 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005353
Arend van Spriel2526ff22017-06-09 13:08:48 +01005354 if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
5355 event == BRCMF_E_PSK_SUP &&
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005356 status == BRCMF_E_STATUS_FWSUP_COMPLETED)
5357 set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005358 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005359 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005360 memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
5361 if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
5362 return true;
5363
5364 set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005365 }
5366
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005367 if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
5368 test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
5369 clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
5370 clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
5371 return true;
5372 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005373 return false;
5374}
5375
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005376static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005377{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005378 u32 event = e->event_code;
5379 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005380
Hante Meuleman68ca3952014-02-25 20:30:26 +01005381 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5382 (event == BRCMF_E_DISASSOC_IND) ||
5383 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005384 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005385 return true;
5386 }
5387 return false;
5388}
5389
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005390static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005391 const struct brcmf_event_msg *e)
5392{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005393 u32 event = e->event_code;
5394 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005395
5396 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005397 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5398 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005399 return true;
5400 }
5401
5402 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005403 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005404 return true;
5405 }
5406
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005407 if (event == BRCMF_E_PSK_SUP &&
5408 status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
5409 brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
5410 status);
5411 return true;
5412 }
5413
Arend van Spriel5b435de2011-10-05 13:19:03 +02005414 return false;
5415}
5416
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005417static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005418{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005419 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005420
5421 kfree(conn_info->req_ie);
5422 conn_info->req_ie = NULL;
5423 conn_info->req_ie_len = 0;
5424 kfree(conn_info->resp_ie);
5425 conn_info->resp_ie = NULL;
5426 conn_info->resp_ie_len = 0;
5427}
5428
Hante Meuleman89286dc2013-02-08 15:53:46 +01005429static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5430 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005431{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005432 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005433 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434 u32 req_len;
5435 u32 resp_len;
5436 s32 err = 0;
5437
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005438 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439
Arend van Sprielac24be62012-10-22 10:36:23 -07005440 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5441 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005442 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005443 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005444 return err;
5445 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005446 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005447 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005448 req_len = le32_to_cpu(assoc_info->req_len);
5449 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005450 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005451 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005452 cfg->extra_buf,
5453 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005454 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005455 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005456 return err;
5457 }
5458 conn_info->req_ie_len = req_len;
5459 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005460 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005461 GFP_KERNEL);
5462 } else {
5463 conn_info->req_ie_len = 0;
5464 conn_info->req_ie = NULL;
5465 }
5466 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005467 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005468 cfg->extra_buf,
5469 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005470 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005471 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005472 return err;
5473 }
5474 conn_info->resp_ie_len = resp_len;
5475 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005476 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005477 GFP_KERNEL);
5478 } else {
5479 conn_info->resp_ie_len = 0;
5480 conn_info->resp_ie = NULL;
5481 }
Arend van Spriel16886732012-12-05 15:26:04 +01005482 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5483 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005484
5485 return err;
5486}
5487
5488static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005489brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005490 struct net_device *ndev,
5491 const struct brcmf_event_msg *e)
5492{
Arend van Sprielc1179032012-10-22 13:55:33 -07005493 struct brcmf_if *ifp = netdev_priv(ndev);
5494 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005495 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5496 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005497 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005498 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005499 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005500 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005501 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005502 u32 freq;
5503 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005504 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005505
Arend van Sprield96b8012012-12-05 15:26:02 +01005506 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005507
Hante Meuleman89286dc2013-02-08 15:53:46 +01005508 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005509 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005510 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005511
Franky Lina180b832012-10-10 11:13:09 -07005512 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5513 if (buf == NULL) {
5514 err = -ENOMEM;
5515 goto done;
5516 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005517
Franky Lina180b832012-10-10 11:13:09 -07005518 /* data sent to dongle has to be little endian */
5519 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005520 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005521 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005522
5523 if (err)
5524 goto done;
5525
5526 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005527 ch.chspec = le16_to_cpu(bi->chanspec);
5528 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005529
Franky Lin83cf17a2013-04-11 13:28:50 +02005530 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005531 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005532 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005533 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005534
Rafał Miłecki4712d882016-05-20 13:38:57 +02005535 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005536 notify_channel = ieee80211_get_channel(wiphy, freq);
5537
Franky Lina180b832012-10-10 11:13:09 -07005538done:
5539 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005540
5541 roam_info.channel = notify_channel;
5542 roam_info.bssid = profile->bssid;
5543 roam_info.req_ie = conn_info->req_ie;
5544 roam_info.req_ie_len = conn_info->req_ie_len;
5545 roam_info.resp_ie = conn_info->resp_ie;
5546 roam_info.resp_ie_len = conn_info->resp_ie_len;
5547
5548 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005549 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005550
Arend van Sprielc1179032012-10-22 13:55:33 -07005551 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005552 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005553 return err;
5554}
5555
5556static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005557brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005558 struct net_device *ndev, const struct brcmf_event_msg *e,
5559 bool completed)
5560{
Arend van Sprielc1179032012-10-22 13:55:33 -07005561 struct brcmf_if *ifp = netdev_priv(ndev);
5562 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005563 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel123fef32017-06-09 13:08:49 +01005564 struct cfg80211_connect_resp_params conn_params;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005565
Arend van Sprield96b8012012-12-05 15:26:02 +01005566 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005567
Arend van Sprielc1179032012-10-22 13:55:33 -07005568 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5569 &ifp->vif->sme_state)) {
Arend van Spriel123fef32017-06-09 13:08:49 +01005570 memset(&conn_params, 0, sizeof(conn_params));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005571 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005572 brcmf_get_assoc_ies(cfg, ifp);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005573 brcmf_update_bss_info(cfg, ifp);
5574 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5575 &ifp->vif->sme_state);
Arend van Spriel123fef32017-06-09 13:08:49 +01005576 conn_params.status = WLAN_STATUS_SUCCESS;
5577 } else {
5578 conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005579 }
Arend van Spriel123fef32017-06-09 13:08:49 +01005580 conn_params.bssid = profile->bssid;
5581 conn_params.req_ie = conn_info->req_ie;
5582 conn_params.req_ie_len = conn_info->req_ie_len;
5583 conn_params.resp_ie = conn_info->resp_ie;
5584 conn_params.resp_ie_len = conn_info->resp_ie_len;
5585 cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005586 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5587 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005588 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005589 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005590 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005591}
5592
5593static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005594brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005595 struct net_device *ndev,
5596 const struct brcmf_event_msg *e, void *data)
5597{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005598 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005599 u32 event = e->event_code;
5600 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005601 struct station_info sinfo;
5602
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005603 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5604 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005605 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5606 ndev != cfg_to_ndev(cfg)) {
5607 brcmf_dbg(CONN, "AP mode link down\n");
5608 complete(&cfg->vif_disabled);
5609 return 0;
5610 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005611
Hante Meuleman1a873342012-09-27 14:17:54 +02005612 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005613 (reason == BRCMF_E_STATUS_SUCCESS)) {
5614 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005615 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005616 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005617 return -EINVAL;
5618 }
5619 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005620 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005621 generation++;
5622 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005623 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005624 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5625 (event == BRCMF_E_DEAUTH_IND) ||
5626 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005627 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005628 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005629 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005630}
5631
5632static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005633brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005634 const struct brcmf_event_msg *e, void *data)
5635{
Arend van Spriel19937322012-11-05 16:22:32 -08005636 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5637 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005638 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005639 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005640 s32 err = 0;
5641
Hante Meuleman8851cce2014-07-30 13:20:02 +02005642 if ((e->event_code == BRCMF_E_DEAUTH) ||
5643 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5644 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5645 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5646 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5647 }
5648
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005649 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005650 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005651 } else if (brcmf_is_linkup(ifp->vif, e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005652 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005653 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005654 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005655 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005656 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005657 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005658 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5659 &ifp->vif->sme_state);
5660 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5661 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005662 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005663 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005664 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005665 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005666 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005667 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005668 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005669 brcmf_link_down(ifp->vif,
5670 brcmf_map_fw_linkdown_reason(e));
5671 brcmf_init_prof(ndev_to_prof(ndev));
5672 if (ndev != cfg_to_ndev(cfg))
5673 complete(&cfg->vif_disabled);
5674 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005675 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005676 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005677 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005678 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5679 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005680 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005681 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005682 }
5683
5684 return err;
5685}
5686
5687static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005688brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005689 const struct brcmf_event_msg *e, void *data)
5690{
Arend van Spriel19937322012-11-05 16:22:32 -08005691 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005692 u32 event = e->event_code;
5693 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005694
5695 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005696 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005697 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005698 else
Arend van Spriel19937322012-11-05 16:22:32 -08005699 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005700 }
5701
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005702 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005703}
5704
5705static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005706brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005707 const struct brcmf_event_msg *e, void *data)
5708{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005709 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005710 enum nl80211_key_type key_type;
5711
5712 if (flags & BRCMF_EVENT_MSG_GROUP)
5713 key_type = NL80211_KEYTYPE_GROUP;
5714 else
5715 key_type = NL80211_KEYTYPE_PAIRWISE;
5716
Arend van Spriel19937322012-11-05 16:22:32 -08005717 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005718 NULL, GFP_KERNEL);
5719
5720 return 0;
5721}
5722
Arend van Sprield3c0b632013-02-08 15:53:37 +01005723static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5724 const struct brcmf_event_msg *e, void *data)
5725{
5726 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5727 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5728 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5729 struct brcmf_cfg80211_vif *vif;
5730
Hante Meuleman37a869e2015-10-29 20:33:17 +01005731 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005732 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005733 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005734
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005735 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005736 event->action = ifevent->action;
5737 vif = event->vif;
5738
5739 switch (ifevent->action) {
5740 case BRCMF_E_IF_ADD:
5741 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005742 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005743 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005744 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005745 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005746
5747 ifp->vif = vif;
5748 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005749 if (ifp->ndev) {
5750 vif->wdev.netdev = ifp->ndev;
5751 ifp->ndev->ieee80211_ptr = &vif->wdev;
5752 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5753 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005754 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005755 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005756 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005757
5758 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005759 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005760 /* event may not be upon user request */
5761 if (brcmf_cfg80211_vif_event_armed(cfg))
5762 wake_up(&event->vif_wq);
5763 return 0;
5764
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005765 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005766 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005767 wake_up(&event->vif_wq);
5768 return 0;
5769
Arend van Sprield3c0b632013-02-08 15:53:37 +01005770 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005771 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005772 break;
5773 }
5774 return -EINVAL;
5775}
5776
Arend van Spriel5b435de2011-10-05 13:19:03 +02005777static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5778{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005779 conf->frag_threshold = (u32)-1;
5780 conf->rts_threshold = (u32)-1;
5781 conf->retry_short = (u32)-1;
5782 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005783}
5784
Arend van Spriel5c36b992012-11-14 18:46:05 -08005785static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005786{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005787 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5788 brcmf_notify_connect_status);
5789 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5790 brcmf_notify_connect_status);
5791 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5792 brcmf_notify_connect_status);
5793 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5794 brcmf_notify_connect_status);
5795 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5796 brcmf_notify_connect_status);
5797 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5798 brcmf_notify_connect_status);
5799 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5800 brcmf_notify_roaming_status);
5801 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5802 brcmf_notify_mic_status);
5803 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5804 brcmf_notify_connect_status);
5805 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5806 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005807 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5808 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005809 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005810 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005811 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5812 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005813 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5814 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005815 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5816 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005817 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5818 brcmf_p2p_notify_action_tx_complete);
Arend van Sprielb8a64f02017-06-09 13:08:47 +01005819 brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
5820 brcmf_notify_connect_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005821}
5822
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005823static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005824{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005825 kfree(cfg->conf);
5826 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005827 kfree(cfg->extra_buf);
5828 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005829 kfree(cfg->wowl.nd);
5830 cfg->wowl.nd = NULL;
5831 kfree(cfg->wowl.nd_info);
5832 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005833 kfree(cfg->escan_info.escan_buf);
5834 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005835}
5836
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005837static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005838{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005839 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5840 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005841 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005842 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5843 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005844 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005845 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5846 if (!cfg->wowl.nd)
5847 goto init_priv_mem_out;
5848 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5849 sizeof(struct cfg80211_wowlan_nd_match *),
5850 GFP_KERNEL);
5851 if (!cfg->wowl.nd_info)
5852 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005853 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5854 if (!cfg->escan_info.escan_buf)
5855 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005856
5857 return 0;
5858
5859init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005860 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005861
5862 return -ENOMEM;
5863}
5864
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005865static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005866{
5867 s32 err = 0;
5868
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005869 cfg->scan_request = NULL;
5870 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005871 cfg->active_scan = true; /* we do active scan per default */
5872 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005873 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005874 if (err)
5875 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005876 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005877 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005878 brcmf_init_escan(cfg);
5879 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005880 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005881 return err;
5882}
5883
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005884static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005885{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005886 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005887 brcmf_abort_scanning(cfg);
5888 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005889}
5890
Arend van Sprield3c0b632013-02-08 15:53:37 +01005891static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5892{
5893 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005894 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005895}
5896
Hante Meuleman1119e232015-11-25 11:32:42 +01005897static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005898{
Hante Meuleman1119e232015-11-25 11:32:42 +01005899 s32 err;
5900 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005901 __le32 roamtrigger[2];
5902 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005903
Hante Meuleman1119e232015-11-25 11:32:42 +01005904 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005905 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005906 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5907 else
5908 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5909 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5910 if (err) {
5911 brcmf_err("bcn_timeout error (%d)\n", err);
5912 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005913 }
5914
Hante Meuleman1119e232015-11-25 11:32:42 +01005915 /* Enable/Disable built-in roaming to allow supplicant to take care of
5916 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005917 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005918 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005919 ifp->drvr->settings->roamoff ? "Off" : "On");
5920 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5921 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005922 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005923 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005924 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005925 }
5926
Arend van Sprielf588bc02011-10-12 20:51:22 +02005927 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5928 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005929 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005930 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005931 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005932 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005933 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005934 }
5935
Arend van Sprielf588bc02011-10-12 20:51:22 +02005936 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5937 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005938 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005939 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005940 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005941 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005942 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005943 }
5944
Hante Meuleman1119e232015-11-25 11:32:42 +01005945roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005946 return err;
5947}
5948
5949static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005950brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005951{
5952 s32 err = 0;
5953
Arend van Sprielac24be62012-10-22 10:36:23 -07005954 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005955 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005956 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005957 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005958 goto dongle_scantime_out;
5959 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005960 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005961 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005962 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005963 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005964 goto dongle_scantime_out;
5965 }
5966
Arend van Sprielac24be62012-10-22 10:36:23 -07005967 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005968 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005969 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005970 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005971 goto dongle_scantime_out;
5972 }
5973
5974dongle_scantime_out:
5975 return err;
5976}
5977
Arend van Sprielb48d8912014-07-12 08:49:41 +02005978static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5979 struct brcmu_chan *ch)
5980{
5981 u32 ht40_flag;
5982
5983 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5984 if (ch->sb == BRCMU_CHAN_SB_U) {
5985 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5986 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5987 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5988 } else {
5989 /* It should be one of
5990 * IEEE80211_CHAN_NO_HT40 or
5991 * IEEE80211_CHAN_NO_HT40PLUS
5992 */
5993 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5994 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5995 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5996 }
5997}
5998
5999static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
6000 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02006001{
6002 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006003 struct ieee80211_supported_band *band;
6004 struct ieee80211_channel *channel;
6005 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02006006 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02006007 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006008 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006009 u8 *pbuf;
6010 u32 i, j;
6011 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006012 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02006013
6014 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6015
6016 if (pbuf == NULL)
6017 return -ENOMEM;
6018
6019 list = (struct brcmf_chanspec_list *)pbuf;
6020
6021 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6022 BRCMF_DCMD_MEDLEN);
6023 if (err) {
6024 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006025 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02006026 }
6027
Arend van Sprielb48d8912014-07-12 08:49:41 +02006028 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006029 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006030 if (band)
6031 for (i = 0; i < band->n_channels; i++)
6032 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006033 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02006034 if (band)
6035 for (i = 0; i < band->n_channels; i++)
6036 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02006037
6038 total = le32_to_cpu(list->count);
6039 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02006040 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6041 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02006042
Franky Lin83cf17a2013-04-11 13:28:50 +02006043 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006044 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02006045 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006046 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02006047 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006048 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02006049 continue;
6050 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02006051 if (!band)
6052 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006053 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01006054 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02006055 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006056 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02006057 ch.bw == BRCMU_CHAN_BW_80)
6058 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006059
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006060 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006061 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006062 if (band->channels[j].hw_value == ch.control_ch_num) {
6063 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02006064 break;
6065 }
6066 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006067 if (!channel) {
6068 /* It seems firmware supports some channel we never
6069 * considered. Something new in IEEE standard?
6070 */
6071 brcmf_err("Ignoring unexpected firmware channel %d\n",
6072 ch.control_ch_num);
6073 continue;
6074 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006075
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006076 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
6077 continue;
6078
Arend van Sprielb48d8912014-07-12 08:49:41 +02006079 /* assuming the chanspecs order is HT20,
6080 * HT40 upper, HT40 lower, and VHT80.
6081 */
6082 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006083 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006084 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006085 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006086 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02006087 /* enable the channel and disable other bandwidths
6088 * for now as mentioned order assure they are enabled
6089 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02006090 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006091 channel->flags = IEEE80211_CHAN_NO_HT40 |
6092 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006093 ch.bw = BRCMU_CHAN_BW_20;
6094 cfg->d11inf.encchspec(&ch);
6095 chaninfo = ch.chspec;
6096 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
6097 &chaninfo);
6098 if (!err) {
6099 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006100 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006101 (IEEE80211_CHAN_RADAR |
6102 IEEE80211_CHAN_NO_IR);
6103 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01006104 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006105 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006106 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006107 }
6108 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006109
Arend van Sprielb48d8912014-07-12 08:49:41 +02006110fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006111 kfree(pbuf);
6112 return err;
6113}
6114
Arend van Sprielb48d8912014-07-12 08:49:41 +02006115static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006116{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006117 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6118 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006119 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006120 struct brcmf_chanspec_list *list;
6121 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006122 u32 val;
6123 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006124 struct brcmu_chan ch;
6125 u32 num_chan;
6126 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006127
6128 /* verify support for bw_cap command */
6129 val = WLC_BAND_5G;
6130 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6131
6132 if (!err) {
6133 /* only set 2G bandwidth using bw_cap command */
6134 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6135 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6136 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6137 sizeof(band_bwcap));
6138 } else {
6139 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6140 val = WLC_N_BW_40ALL;
6141 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6142 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006143
6144 if (!err) {
6145 /* update channel info in 2G band */
6146 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6147
6148 if (pbuf == NULL)
6149 return -ENOMEM;
6150
6151 ch.band = BRCMU_CHAN_BAND_2G;
6152 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006153 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006154 ch.chnum = 0;
6155 cfg->d11inf.encchspec(&ch);
6156
6157 /* pass encoded chanspec in query */
6158 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6159
6160 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6161 BRCMF_DCMD_MEDLEN);
6162 if (err) {
6163 brcmf_err("get chanspecs error (%d)\n", err);
6164 kfree(pbuf);
6165 return err;
6166 }
6167
Johannes Berg57fbcce2016-04-12 15:56:15 +02006168 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006169 list = (struct brcmf_chanspec_list *)pbuf;
6170 num_chan = le32_to_cpu(list->count);
6171 for (i = 0; i < num_chan; i++) {
6172 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6173 cfg->d11inf.decchspec(&ch);
6174 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6175 continue;
6176 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6177 continue;
6178 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006179 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006180 break;
6181 }
6182 if (WARN_ON(j == band->n_channels))
6183 continue;
6184
6185 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6186 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006187 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006188 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006189 return err;
6190}
6191
Arend van Spriel2375d972014-01-06 12:40:41 +01006192static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6193{
6194 u32 band, mimo_bwcap;
6195 int err;
6196
6197 band = WLC_BAND_2G;
6198 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6199 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006200 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006201 band = WLC_BAND_5G;
6202 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6203 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006204 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006205 return;
6206 }
6207 WARN_ON(1);
6208 return;
6209 }
6210 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6211 mimo_bwcap = 0;
6212 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6213 if (err)
6214 /* assume 20MHz if firmware does not give a clue */
6215 mimo_bwcap = WLC_N_BW_20ALL;
6216
6217 switch (mimo_bwcap) {
6218 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006219 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006220 /* fall-thru */
6221 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006222 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006223 /* fall-thru */
6224 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006225 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6226 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006227 break;
6228 default:
6229 brcmf_err("invalid mimo_bw_cap value\n");
6230 }
6231}
Hante Meulemand48200b2013-04-03 12:40:29 +02006232
Arend van Spriel18d6c532014-05-12 10:47:35 +02006233static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6234 u32 bw_cap[2], u32 nchain)
6235{
6236 band->ht_cap.ht_supported = true;
6237 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6238 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6239 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6240 }
6241 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6242 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6243 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6244 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6245 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6246 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6247}
6248
6249static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6250{
6251 u16 mcs_map;
6252 int i;
6253
6254 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6255 mcs_map = (mcs_map << 2) | supp;
6256
6257 return cpu_to_le16(mcs_map);
6258}
6259
6260static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006261 u32 bw_cap[2], u32 nchain, u32 txstreams,
6262 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006263{
6264 __le16 mcs_map;
6265
6266 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006267 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006268 return;
6269
6270 band->vht_cap.vht_supported = true;
6271 /* 80MHz is mandatory */
6272 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6273 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6274 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6275 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6276 }
6277 /* all support 256-QAM */
6278 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6279 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6280 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006281
6282 /* Beamforming support information */
6283 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6284 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6285 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6286 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6287 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6288 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6289 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6290 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6291
6292 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6293 band->vht_cap.cap |=
6294 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6295 band->vht_cap.cap |= ((txstreams - 1) <<
6296 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6297 band->vht_cap.cap |=
6298 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6299 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006300}
6301
Arend van Sprielb48d8912014-07-12 08:49:41 +02006302static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006303{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006304 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006305 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006306 u32 nmode = 0;
6307 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006308 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006309 u32 rxchain;
6310 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006311 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006312 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006313 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006314 u32 txstreams = 0;
6315 u32 txbf_bfe_cap = 0;
6316 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006317
Arend van Spriel18d6c532014-05-12 10:47:35 +02006318 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006319 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6320 if (err) {
6321 brcmf_err("nmode error (%d)\n", err);
6322 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006323 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006324 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006325 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006326 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6327 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006328
Daniel Kim4aca7a12014-02-25 20:30:36 +01006329 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6330 if (err) {
6331 brcmf_err("rxchain error (%d)\n", err);
6332 nchain = 1;
6333 } else {
6334 for (nchain = 0; rxchain; nchain++)
6335 rxchain = rxchain & (rxchain - 1);
6336 }
6337 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6338
Arend van Sprielb48d8912014-07-12 08:49:41 +02006339 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006340 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006341 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006342 return err;
6343 }
6344
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006345 if (vhtmode) {
6346 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6347 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6348 &txbf_bfe_cap);
6349 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6350 &txbf_bfr_cap);
6351 }
6352
Arend van Sprielb48d8912014-07-12 08:49:41 +02006353 wiphy = cfg_to_wiphy(cfg);
6354 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6355 band = wiphy->bands[i];
6356 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006357 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006358
Arend van Spriel18d6c532014-05-12 10:47:35 +02006359 if (nmode)
6360 brcmf_update_ht_cap(band, bw_cap, nchain);
6361 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006362 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6363 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006364 }
6365
Arend van Sprielb48d8912014-07-12 08:49:41 +02006366 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006367}
6368
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006369static const struct ieee80211_txrx_stypes
6370brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6371 [NL80211_IFTYPE_STATION] = {
6372 .tx = 0xffff,
6373 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6374 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6375 },
6376 [NL80211_IFTYPE_P2P_CLIENT] = {
6377 .tx = 0xffff,
6378 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6379 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6380 },
6381 [NL80211_IFTYPE_P2P_GO] = {
6382 .tx = 0xffff,
6383 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6384 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6385 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6386 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6387 BIT(IEEE80211_STYPE_AUTH >> 4) |
6388 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6389 BIT(IEEE80211_STYPE_ACTION >> 4)
6390 },
6391 [NL80211_IFTYPE_P2P_DEVICE] = {
6392 .tx = 0xffff,
6393 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6394 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6395 }
6396};
6397
Arend van Spriel0882dda2015-08-20 22:06:03 +02006398/**
6399 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6400 *
6401 * @wiphy: wiphy object.
6402 * @ifp: interface object needed for feat module api.
6403 *
6404 * The interface modes and combinations are determined dynamically here
6405 * based on firmware functionality.
6406 *
6407 * no p2p and no mbss:
6408 *
6409 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6410 *
6411 * no p2p and mbss:
6412 *
6413 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6414 * #AP <= 4, matching BI, channels = 1, 4 total
6415 *
6416 * p2p, no mchan, and mbss:
6417 *
6418 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6419 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6420 * #AP <= 4, matching BI, channels = 1, 4 total
6421 *
6422 * p2p, mchan, and mbss:
6423 *
6424 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6425 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6426 * #AP <= 4, matching BI, channels = 1, 4 total
6427 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006428static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6429{
6430 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006431 struct ieee80211_iface_limit *c0_limits = NULL;
6432 struct ieee80211_iface_limit *p2p_limits = NULL;
6433 struct ieee80211_iface_limit *mbss_limits = NULL;
6434 bool mbss, p2p;
6435 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006436
Arend van Spriel0882dda2015-08-20 22:06:03 +02006437 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6438 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6439
6440 n_combos = 1 + !!p2p + !!mbss;
6441 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006442 if (!combo)
6443 goto err;
6444
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006445 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6446 BIT(NL80211_IFTYPE_ADHOC) |
6447 BIT(NL80211_IFTYPE_AP);
6448
Arend van Spriel0882dda2015-08-20 22:06:03 +02006449 c = 0;
6450 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006451 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6452 if (!c0_limits)
6453 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006454 c0_limits[i].max = 1;
6455 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6456 if (p2p) {
6457 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6458 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006459 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6460 BIT(NL80211_IFTYPE_P2P_GO) |
6461 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006462 c0_limits[i].max = 1;
6463 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6464 c0_limits[i].max = 1;
6465 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6466 BIT(NL80211_IFTYPE_P2P_GO);
6467 } else {
6468 c0_limits[i].max = 1;
6469 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006470 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006471 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006472 combo[c].max_interfaces = i;
6473 combo[c].n_limits = i;
6474 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006475
Arend van Spriel0882dda2015-08-20 22:06:03 +02006476 if (p2p) {
6477 c++;
6478 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006479 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6480 if (!p2p_limits)
6481 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006482 p2p_limits[i].max = 1;
6483 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6484 p2p_limits[i].max = 1;
6485 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6486 p2p_limits[i].max = 1;
6487 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6488 p2p_limits[i].max = 1;
6489 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006490 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006491 combo[c].max_interfaces = i;
6492 combo[c].n_limits = i;
6493 combo[c].limits = p2p_limits;
6494 }
6495
6496 if (mbss) {
6497 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006498 i = 0;
6499 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6500 if (!mbss_limits)
6501 goto err;
6502 mbss_limits[i].max = 4;
6503 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006504 combo[c].beacon_int_infra_match = true;
6505 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006506 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006507 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006508 combo[c].limits = mbss_limits;
6509 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006510
Arend van Spriel0882dda2015-08-20 22:06:03 +02006511 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006512 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006513 return 0;
6514
6515err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006516 kfree(c0_limits);
6517 kfree(p2p_limits);
6518 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006519 kfree(combo);
6520 return -ENOMEM;
6521}
6522
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006523#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006524static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006525 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006526 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6527 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6528 .pattern_min_len = 1,
6529 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006530};
6531#endif
6532
Hante Meuleman3021ad92016-01-05 11:05:45 +01006533static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006534{
6535#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006536 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006537 struct wiphy_wowlan_support *wowl;
6538
6539 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6540 GFP_KERNEL);
6541 if (!wowl) {
6542 brcmf_err("only support basic wowlan features\n");
6543 wiphy->wowlan = &brcmf_wowlan_support;
6544 return;
6545 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006546
6547 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006548 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006549 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6550 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006551 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006552 }
6553 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006554 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006555 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6556 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006557 }
6558
Arend Van Spriel0b570102017-01-27 12:27:47 +00006559 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006560#endif
6561}
6562
Arend van Sprielb48d8912014-07-12 08:49:41 +02006563static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006564{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006565 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006566 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006567 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006568 u16 max_interfaces = 0;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006569 bool gscan;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006570 __le32 bandlist[3];
6571 u32 n_bands;
6572 int err, i;
6573
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006574 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6575 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006576 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006577
6578 err = brcmf_setup_ifmodes(wiphy, ifp);
6579 if (err)
6580 return err;
6581
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006582 for (i = 0, combo = wiphy->iface_combinations;
6583 i < wiphy->n_iface_combinations; i++, combo++) {
6584 max_interfaces = max(max_interfaces, combo->max_interfaces);
6585 }
6586
6587 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6588 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006589 u8 *addr = drvr->addresses[i].addr;
6590
6591 memcpy(addr, drvr->mac, ETH_ALEN);
6592 if (i) {
6593 addr[0] |= BIT(1);
6594 addr[ETH_ALEN - 1] ^= i;
6595 }
6596 }
6597 wiphy->addresses = drvr->addresses;
6598 wiphy->n_addresses = i;
6599
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006600 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006601 wiphy->cipher_suites = brcmf_cipher_suites;
6602 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6603 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6604 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006605 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6606 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6607 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6608
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006609 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6610 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006611 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006612 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6613 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6614 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006615 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006616 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
Arend van Spriel2526ff22017-06-09 13:08:48 +01006617 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
Arend van Sprielb8a64f02017-06-09 13:08:47 +01006618 wiphy_ext_feature_set(wiphy,
6619 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
Arend van Spriel2526ff22017-06-09 13:08:48 +01006620 wiphy_ext_feature_set(wiphy,
6621 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
6622 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006623 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6624 wiphy->max_remain_on_channel_duration = 5000;
Arend Van Spriel94ed6ff2017-04-21 13:05:05 +01006625 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
6626 gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
6627 brcmf_pno_wiphy_params(wiphy, gscan);
6628 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006629 /* vendor commands/events support */
6630 wiphy->vendor_commands = brcmf_vendor_cmds;
6631 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6632
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006633 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006634 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006635 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6636 sizeof(bandlist));
6637 if (err) {
6638 brcmf_err("could not obtain band info: err=%d\n", err);
6639 return err;
6640 }
6641 /* first entry in bandlist is number of bands */
6642 n_bands = le32_to_cpu(bandlist[0]);
6643 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6644 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6645 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6646 GFP_KERNEL);
6647 if (!band)
6648 return -ENOMEM;
6649
6650 band->channels = kmemdup(&__wl_2ghz_channels,
6651 sizeof(__wl_2ghz_channels),
6652 GFP_KERNEL);
6653 if (!band->channels) {
6654 kfree(band);
6655 return -ENOMEM;
6656 }
6657
6658 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006659 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006660 }
6661 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6662 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6663 GFP_KERNEL);
6664 if (!band)
6665 return -ENOMEM;
6666
6667 band->channels = kmemdup(&__wl_5ghz_channels,
6668 sizeof(__wl_5ghz_channels),
6669 GFP_KERNEL);
6670 if (!band->channels) {
6671 kfree(band);
6672 return -ENOMEM;
6673 }
6674
6675 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006676 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006677 }
6678 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006679
6680 wiphy_read_of_freq_limits(wiphy);
6681
Rafał Miłeckiab990632017-01-07 21:36:05 +01006682 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006683}
6684
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006685static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006686{
6687 struct net_device *ndev;
6688 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006689 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006690 s32 power_mode;
6691 s32 err = 0;
6692
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006693 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006694 return err;
6695
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006696 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006697 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006698 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006699
Hante Meuleman40a23292013-01-02 15:22:51 +01006700 /* make sure RF is ready for work */
6701 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6702
Hante Meuleman1678ba82015-12-10 13:43:00 +01006703 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006704
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006705 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006706 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006707 if (err)
6708 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006709 brcmf_dbg(INFO, "power save set to %s\n",
6710 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006711
Hante Meuleman1119e232015-11-25 11:32:42 +01006712 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006713 if (err)
6714 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006715 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006716 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006717 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006718 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006719
Franky Lin52f22fb2016-02-17 11:26:55 +01006720 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006721
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006722 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006723default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006724
6725 return err;
6726
6727}
6728
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006729static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006730{
Arend van Sprielc1179032012-10-22 13:55:33 -07006731 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006732
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006733 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006734}
6735
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006736static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006737{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006738 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006739
Arend van Spriel5b435de2011-10-05 13:19:03 +02006740 /*
6741 * While going down, if associated with AP disassociate
6742 * from AP to save power
6743 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006744 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006745 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006746
6747 /* Make sure WPA_Supplicant receives all the event
6748 generated due to DISASSOC call to the fw to keep
6749 the state fw and WPA_Supplicant state consistent
6750 */
6751 brcmf_delay(500);
6752 }
6753
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006754 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006755 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006756
Arend van Spriel5b435de2011-10-05 13:19:03 +02006757 return 0;
6758}
6759
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006760s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006761{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006762 struct brcmf_if *ifp = netdev_priv(ndev);
6763 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006764 s32 err = 0;
6765
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006766 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006767 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006768 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006769
6770 return err;
6771}
6772
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006773s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006774{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006775 struct brcmf_if *ifp = netdev_priv(ndev);
6776 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006777 s32 err = 0;
6778
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006779 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006780 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006781 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006782
6783 return err;
6784}
6785
Arend van Spriela7965fb2013-04-11 17:08:37 +02006786enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6787{
6788 struct wireless_dev *wdev = &ifp->vif->wdev;
6789
6790 return wdev->iftype;
6791}
6792
Hante Meulemanbfe81972014-10-28 14:56:16 +01006793bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6794 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006795{
6796 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006797
6798 list_for_each_entry(vif, &cfg->vif_list, list) {
6799 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006800 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006801 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006802 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006803}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006804
6805static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6806 u8 action)
6807{
6808 u8 evt_action;
6809
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006810 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006811 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006812 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006813 return evt_action == action;
6814}
6815
6816void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6817 struct brcmf_cfg80211_vif *vif)
6818{
6819 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6820
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006821 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006822 event->vif = vif;
6823 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006824 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006825}
6826
6827bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6828{
6829 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6830 bool armed;
6831
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006832 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006833 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006834 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006835
6836 return armed;
6837}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006838
6839int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6840 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006841{
6842 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6843
6844 return wait_event_timeout(event->vif_wq,
6845 vif_event_equals(event, action), timeout);
6846}
6847
Hante Meuleman73345fd2016-02-17 11:26:53 +01006848static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6849 struct brcmf_fil_country_le *ccreq)
6850{
Hante Meuleman4d792892016-02-17 11:27:07 +01006851 struct brcmfmac_pd_cc *country_codes;
6852 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006853 s32 found_index;
6854 int i;
6855
6856 country_codes = drvr->settings->country_codes;
6857 if (!country_codes) {
6858 brcmf_dbg(TRACE, "No country codes configured for device\n");
6859 return -EINVAL;
6860 }
6861
6862 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6863 (alpha2[1] == ccreq->country_abbrev[1])) {
6864 brcmf_dbg(TRACE, "Country code already set\n");
6865 return -EAGAIN;
6866 }
6867
6868 found_index = -1;
6869 for (i = 0; i < country_codes->table_size; i++) {
6870 cc = &country_codes->table[i];
6871 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6872 found_index = i;
6873 if ((cc->iso3166[0] == alpha2[0]) &&
6874 (cc->iso3166[1] == alpha2[1])) {
6875 found_index = i;
6876 break;
6877 }
6878 }
6879 if (found_index == -1) {
6880 brcmf_dbg(TRACE, "No country code match found\n");
6881 return -EINVAL;
6882 }
6883 memset(ccreq, 0, sizeof(*ccreq));
6884 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6885 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6886 BRCMF_COUNTRY_BUF_SZ);
6887 ccreq->country_abbrev[0] = alpha2[0];
6888 ccreq->country_abbrev[1] = alpha2[1];
6889 ccreq->country_abbrev[2] = 0;
6890
6891 return 0;
6892}
6893
Arend van Spriel63db1a42014-12-21 12:43:51 +01006894static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6895 struct regulatory_request *req)
6896{
6897 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6898 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6899 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006900 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006901 int i;
6902
Hans de Goede26e537882017-03-08 14:50:16 +01006903 /* The country code gets set to "00" by default at boot, ignore */
6904 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6905 return;
6906
Arend van Spriel63db1a42014-12-21 12:43:51 +01006907 /* ignore non-ISO3166 country codes */
6908 for (i = 0; i < sizeof(req->alpha2); i++)
6909 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Martin Michlmayra9507d52017-06-10 11:40:04 +02006910 brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
Hante Meuleman73345fd2016-02-17 11:26:53 +01006911 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006912 return;
6913 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006914
6915 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6916 req->alpha2[0], req->alpha2[1]);
6917
6918 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6919 if (err) {
6920 brcmf_err("Country code iovar returned err = %d\n", err);
6921 return;
6922 }
6923
6924 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6925 if (err)
6926 return;
6927
6928 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6929 if (err) {
6930 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006931 return;
6932 }
6933 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006934}
6935
Arend van Sprielb48d8912014-07-12 08:49:41 +02006936static void brcmf_free_wiphy(struct wiphy *wiphy)
6937{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006938 int i;
6939
Arend van Spriel58de92d2015-04-14 20:10:24 +02006940 if (!wiphy)
6941 return;
6942
Arend van Spriel0882dda2015-08-20 22:06:03 +02006943 if (wiphy->iface_combinations) {
6944 for (i = 0; i < wiphy->n_iface_combinations; i++)
6945 kfree(wiphy->iface_combinations[i].limits);
6946 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006947 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006948 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6949 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6950 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006951 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006952 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6953 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6954 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006955 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006956#if IS_ENABLED(CONFIG_PM)
6957 if (wiphy->wowlan != &brcmf_wowlan_support)
6958 kfree(wiphy->wowlan);
6959#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006960 wiphy_free(wiphy);
6961}
6962
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006963struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006964 struct device *busdev,
6965 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006966{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006967 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006968 struct brcmf_cfg80211_info *cfg;
6969 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006970 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006971 struct brcmf_cfg80211_vif *vif;
6972 struct brcmf_if *ifp;
6973 s32 err = 0;
6974 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006975 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006976
6977 if (!ndev) {
6978 brcmf_err("ndev is invalid\n");
6979 return NULL;
6980 }
6981
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306982 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006983 if (!ops)
6984 return NULL;
6985
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006986 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006987#ifdef CONFIG_PM
6988 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6989 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6990#endif
6991 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006992 if (!wiphy) {
6993 brcmf_err("Could not allocate wiphy device\n");
Christophe Jaillet57c00f22017-06-21 07:45:53 +02006994 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006995 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006996 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006997 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006998
6999 cfg = wiphy_priv(wiphy);
7000 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007001 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007002 cfg->pub = drvr;
7003 init_vif_event(&cfg->vif_event);
7004 INIT_LIST_HEAD(&cfg->vif_list);
7005
Rafał Miłecki26072332016-06-06 23:03:55 +02007006 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007007 if (IS_ERR(vif))
7008 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007009
7010 vif->ifp = ifp;
7011 vif->wdev.netdev = ndev;
7012 ndev->ieee80211_ptr = &vif->wdev;
7013 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
7014
7015 err = wl_init_priv(cfg);
7016 if (err) {
7017 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007018 brcmf_free_vif(vif);
7019 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007020 }
7021 ifp->vif = vif;
7022
Arend van Sprielb48d8912014-07-12 08:49:41 +02007023 /* determine d11 io type before wiphy setup */
7024 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007025 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02007026 brcmf_err("Failed to get D11 version (%d)\n", err);
7027 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007028 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007029 cfg->d11inf.io_type = (u8)io_type;
7030 brcmu_d11_attach(&cfg->d11inf);
7031
7032 err = brcmf_setup_wiphy(wiphy, ifp);
7033 if (err < 0)
7034 goto priv_out;
7035
7036 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01007037 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007038 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
7039 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
7040
7041 /* firmware defaults to 40MHz disabled in 2G band. We signal
7042 * cfg80211 here that we do and have it decide we can enable
7043 * it. But first check if device does support 2G operation.
7044 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007045 if (wiphy->bands[NL80211_BAND_2GHZ]) {
7046 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007047 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
7048 }
7049 err = wiphy_register(wiphy);
7050 if (err < 0) {
7051 brcmf_err("Could not register wiphy device (%d)\n", err);
7052 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007053 }
7054
Rafał Miłeckiab990632017-01-07 21:36:05 +01007055 err = brcmf_setup_wiphybands(wiphy);
7056 if (err) {
7057 brcmf_err("Setting wiphy bands failed (%d)\n", err);
7058 goto wiphy_unreg_out;
7059 }
7060
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007061 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
7062 * setup 40MHz in 2GHz band and enable OBSS scanning.
7063 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02007064 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
7065 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007066 if (!err)
7067 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
7068 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007069 else
7070 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007071 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007072 /* p2p might require that "if-events" get processed by fweh. So
7073 * activate the already registered event handlers now and activate
7074 * the rest when initialization has completed. drvr->config needs to
7075 * be assigned before activating events.
7076 */
7077 drvr->config = cfg;
7078 err = brcmf_fweh_activate_events(ifp);
7079 if (err) {
7080 brcmf_err("FWEH activation failed (%d)\n", err);
7081 goto wiphy_unreg_out;
7082 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02007083
Hante Meulemanae7c03f2015-09-18 22:08:08 +02007084 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007085 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007086 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007087 goto wiphy_unreg_out;
7088 }
7089 err = brcmf_btcoex_attach(cfg);
7090 if (err) {
7091 brcmf_err("BT-coex initialisation failed (%d)\n", err);
7092 brcmf_p2p_detach(&cfg->p2p);
7093 goto wiphy_unreg_out;
7094 }
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007095 err = brcmf_pno_attach(cfg);
7096 if (err) {
7097 brcmf_err("PNO initialisation failed (%d)\n", err);
7098 brcmf_btcoex_detach(cfg);
7099 brcmf_p2p_detach(&cfg->p2p);
7100 goto wiphy_unreg_out;
7101 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007102
Hante Meulemana7b82d42015-12-10 13:43:04 +01007103 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
7104 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
7105 if (err) {
7106 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
7107 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
7108 } else {
7109 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
7110 brcmf_notify_tdls_peer_event);
7111 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007112 }
7113
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007114 /* (re-) activate FWEH event handling */
7115 err = brcmf_fweh_activate_events(ifp);
7116 if (err) {
7117 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007118 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02007119 }
7120
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007121 /* Fill in some of the advertised nl80211 supported features */
7122 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7123 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7124#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007125 if (wiphy->wowlan &&
7126 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007127 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7128#endif
7129 }
7130
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007131 return cfg;
7132
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007133detach:
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007134 brcmf_pno_detach(cfg);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00007135 brcmf_btcoex_detach(cfg);
7136 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007137wiphy_unreg_out:
7138 wiphy_unregister(cfg->wiphy);
7139priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007140 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007141 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007142 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007143wiphy_out:
7144 brcmf_free_wiphy(wiphy);
Christophe Jaillet57c00f22017-06-21 07:45:53 +02007145ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007146 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007147 return NULL;
7148}
7149
7150void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7151{
7152 if (!cfg)
7153 return;
7154
Arend Van Sprielefc2c1f2017-06-09 12:19:20 +01007155 brcmf_pno_detach(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007156 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007157 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007158 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007159 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007160 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007161}