blob: cd1d6730eab73d514db5a1b88d442607c7834e3d [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");
628 goto fail;
629 }
630
631 return &ifp->vif->wdev;
632
633fail:
634 brcmf_free_vif(vif);
635 return ERR_PTR(err);
636}
637
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100638static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
639{
640 enum nl80211_iftype iftype;
641
642 iftype = vif->wdev.iftype;
643 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
644}
645
646static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
647{
648 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
649}
650
Arend van Spriel9f440b72013-02-08 15:53:36 +0100651static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
652 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100653 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100654 enum nl80211_iftype type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100655 struct vif_params *params)
656{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200657 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200658 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200659
Arend van Spriel9f440b72013-02-08 15:53:36 +0100660 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200661 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
662 if (err) {
663 brcmf_err("iface validation failed: err=%d\n", err);
664 return ERR_PTR(err);
665 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100666 switch (type) {
667 case NL80211_IFTYPE_ADHOC:
668 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100669 case NL80211_IFTYPE_AP_VLAN:
670 case NL80211_IFTYPE_WDS:
671 case NL80211_IFTYPE_MONITOR:
672 case NL80211_IFTYPE_MESH_POINT:
673 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100674 case NL80211_IFTYPE_AP:
Johannes Berg818a9862017-04-12 11:23:28 +0200675 wdev = brcmf_ap_add_vif(wiphy, name, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200676 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100677 case NL80211_IFTYPE_P2P_CLIENT:
678 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200679 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg818a9862017-04-12 11:23:28 +0200680 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200681 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100682 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100683 default:
684 return ERR_PTR(-EINVAL);
685 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200686
687 if (IS_ERR(wdev))
688 brcmf_err("add iface %s type %d failed: err=%d\n",
689 name, type, (int)PTR_ERR(wdev));
690 else
691 brcmf_cfg80211_update_proto_addr_mode(wdev);
692
693 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100694}
695
Daniel Kim5e787f72014-06-21 12:11:18 +0200696static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
697{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200698 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200699 brcmf_set_mpc(ifp, mpc);
700}
701
Arend van Sprielf96aa072013-04-05 10:57:48 +0200702void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100703{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100704 s32 err = 0;
705
706 if (check_vif_up(ifp->vif)) {
707 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
708 if (err) {
709 brcmf_err("fail to set mpc\n");
710 return;
711 }
712 brcmf_dbg(INFO, "MPC : %d\n", mpc);
713 }
714}
715
Arend van Spriela0f472a2013-04-05 10:57:49 +0200716s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
717 struct brcmf_if *ifp, bool aborted,
718 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100719{
720 struct brcmf_scan_params_le params_le;
721 struct cfg80211_scan_request *scan_request;
722 s32 err = 0;
723
724 brcmf_dbg(SCAN, "Enter\n");
725
726 /* clear scan request, because the FW abort can cause a second call */
727 /* to this functon and might cause a double cfg80211_scan_done */
728 scan_request = cfg->scan_request;
729 cfg->scan_request = NULL;
730
731 if (timer_pending(&cfg->escan_timeout))
732 del_timer_sync(&cfg->escan_timeout);
733
734 if (fw_abort) {
735 /* Do a scan abort to stop the driver's scan engine */
736 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
737 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800738 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100739 params_le.bss_type = DOT11_BSSTYPE_ANY;
740 params_le.scan_type = 0;
741 params_le.channel_num = cpu_to_le32(1);
742 params_le.nprobes = cpu_to_le32(1);
743 params_le.active_time = cpu_to_le32(-1);
744 params_le.passive_time = cpu_to_le32(-1);
745 params_le.home_time = cpu_to_le32(-1);
746 /* Scan is aborted by setting channel_list[0] to -1 */
747 params_le.channel_list[0] = cpu_to_le16(-1);
748 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200749 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100750 &params_le, sizeof(params_le));
751 if (err)
752 brcmf_err("Scan abort failed\n");
753 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200754
Daniel Kim5e787f72014-06-21 12:11:18 +0200755 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200756
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100757 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000758 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100759 * which takes precedence.
760 */
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000761 if (cfg->internal_escan) {
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100762 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000763 cfg->internal_escan = false;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100764 if (!aborted)
Arend Van Sprielb34939b2017-04-28 13:40:28 +0100765 cfg80211_sched_scan_results(cfg_to_wiphy(cfg), 0);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100766 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300767 struct cfg80211_scan_info info = {
768 .aborted = aborted,
769 };
770
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100771 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
772 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300773 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100774 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100775 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
776 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100777
778 return err;
779}
780
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200781static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
782 struct wireless_dev *wdev)
783{
784 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
785 struct net_device *ndev = wdev->netdev;
786 struct brcmf_if *ifp = netdev_priv(ndev);
787 int ret;
788 int err;
789
790 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
791
792 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
793 if (err) {
794 brcmf_err("interface_remove failed %d\n", err);
795 goto err_unarm;
796 }
797
798 /* wait for firmware event */
799 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
800 BRCMF_VIF_EVENT_TIMEOUT);
801 if (!ret) {
802 brcmf_err("timeout occurred\n");
803 err = -EIO;
804 goto err_unarm;
805 }
806
807 brcmf_remove_interface(ifp, true);
808
809err_unarm:
810 brcmf_cfg80211_arm_vif_event(cfg, NULL);
811 return err;
812}
813
Arend van Spriel9f440b72013-02-08 15:53:36 +0100814static
815int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
816{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100817 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
818 struct net_device *ndev = wdev->netdev;
819
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200820 if (ndev && ndev == cfg_to_ndev(cfg))
821 return -ENOTSUPP;
822
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100823 /* vif event pending in firmware */
824 if (brcmf_cfg80211_vif_event_armed(cfg))
825 return -EBUSY;
826
827 if (ndev) {
828 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200829 cfg->escan_info.ifp == netdev_priv(ndev))
830 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
831 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100832
833 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
834 }
835
Arend van Spriel9f440b72013-02-08 15:53:36 +0100836 switch (wdev->iftype) {
837 case NL80211_IFTYPE_ADHOC:
838 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100839 case NL80211_IFTYPE_AP_VLAN:
840 case NL80211_IFTYPE_WDS:
841 case NL80211_IFTYPE_MONITOR:
842 case NL80211_IFTYPE_MESH_POINT:
843 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200844 case NL80211_IFTYPE_AP:
845 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100846 case NL80211_IFTYPE_P2P_CLIENT:
847 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200848 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100849 return brcmf_p2p_del_vif(wiphy, wdev);
850 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100851 default:
852 return -EINVAL;
853 }
854 return -EOPNOTSUPP;
855}
856
Arend van Spriel5b435de2011-10-05 13:19:03 +0200857static s32
858brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +0200859 enum nl80211_iftype type,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860 struct vif_params *params)
861{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100862 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700863 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100864 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200865 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200866 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200867 s32 err = 0;
868
Hante Meuleman37a869e2015-10-29 20:33:17 +0100869 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
870 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200871
872 /* WAR: There are a number of p2p interface related problems which
873 * need to be handled initially (before doing the validate).
874 * wpa_supplicant tends to do iface changes on p2p device/client/go
875 * which are not always possible/allowed. However we need to return
876 * OK otherwise the wpa_supplicant wont start. The situation differs
877 * on configuration and setup (p2pon=1 module param). The first check
878 * is to see if the request is a change to station for p2p iface.
879 */
880 if ((type == NL80211_IFTYPE_STATION) &&
881 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
882 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
883 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
884 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
885 /* Now depending on whether module param p2pon=1 was used the
886 * response needs to be either 0 or EOPNOTSUPP. The reason is
887 * that if p2pon=1 is used, but a newer supplicant is used then
888 * we should return an error, as this combination wont work.
889 * In other situations 0 is returned and supplicant will start
890 * normally. It will give a trace in cfg80211, but it is the
891 * only way to get it working. Unfortunately this will result
892 * in situation where we wont support new supplicant in
893 * combination with module param p2pon=1, but that is the way
894 * it is. If the user tries this then unloading of driver might
895 * fail/lock.
896 */
897 if (cfg->p2p.p2pdev_dynamically)
898 return -EOPNOTSUPP;
899 else
900 return 0;
901 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200902 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
903 if (err) {
904 brcmf_err("iface validation failed: err=%d\n", err);
905 return err;
906 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200907 switch (type) {
908 case NL80211_IFTYPE_MONITOR:
909 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100910 brcmf_err("type (%d) : currently we do not support this type\n",
911 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200912 return -EOPNOTSUPP;
913 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200914 infra = 0;
915 break;
916 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200917 infra = 1;
918 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200919 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100920 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200921 ap = 1;
922 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200923 default:
924 err = -EINVAL;
925 goto done;
926 }
927
Hante Meuleman1a873342012-09-27 14:17:54 +0200928 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100929 if (type == NL80211_IFTYPE_P2P_GO) {
930 brcmf_dbg(INFO, "IF Type = P2P GO\n");
931 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
932 }
933 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100934 brcmf_dbg(INFO, "IF Type = AP\n");
935 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200936 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100937 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200938 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100939 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200940 err = -EAGAIN;
941 goto done;
942 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100943 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100944 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200945 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200946 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200947
Hante Meuleman8851cce2014-07-30 13:20:02 +0200948 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
949
Arend van Spriel5b435de2011-10-05 13:19:03 +0200950done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100951 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200952
953 return err;
954}
955
Franky Lin83cf17a2013-04-11 13:28:50 +0200956static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
957 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200958 struct cfg80211_scan_request *request)
959{
960 u32 n_ssids;
961 u32 n_channels;
962 s32 i;
963 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200964 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200965 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200966 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200967
Joe Perches93803b32015-03-02 19:54:49 -0800968 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200969 params_le->bss_type = DOT11_BSSTYPE_ANY;
970 params_le->scan_type = 0;
971 params_le->channel_num = 0;
972 params_le->nprobes = cpu_to_le32(-1);
973 params_le->active_time = cpu_to_le32(-1);
974 params_le->passive_time = cpu_to_le32(-1);
975 params_le->home_time = cpu_to_le32(-1);
976 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
977
978 /* if request is null exit so it will be all channel broadcast scan */
979 if (!request)
980 return;
981
982 n_ssids = request->n_ssids;
983 n_channels = request->n_channels;
984 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100985 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
986 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200987 if (n_channels > 0) {
988 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200989 chanspec = channel_to_chanspec(&cfg->d11inf,
990 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100991 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
992 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200993 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200994 }
995 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100996 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200997 }
998 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100999 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001000 if (n_ssids > 0) {
1001 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1002 n_channels * sizeof(u16);
1003 offset = roundup(offset, sizeof(u32));
1004 ptr = (char *)params_le + offset;
1005 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001006 memset(&ssid_le, 0, sizeof(ssid_le));
1007 ssid_le.SSID_len =
1008 cpu_to_le32(request->ssids[i].ssid_len);
1009 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1010 request->ssids[i].ssid_len);
1011 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001012 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001013 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001014 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
1015 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001016 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1017 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001018 }
1019 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001020 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001021 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001022 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1023 params_le->ssid_le.SSID,
1024 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001025 params_le->ssid_le.SSID_len =
1026 cpu_to_le32(request->ssids->ssid_len);
1027 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1028 request->ssids->ssid_len);
1029 }
1030 }
1031 /* Adding mask to channel numbers */
1032 params_le->channel_num =
1033 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1034 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1035}
1036
1037static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001038brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001039 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001040{
1041 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1042 offsetof(struct brcmf_escan_params_le, params_le);
1043 struct brcmf_escan_params_le *params;
1044 s32 err = 0;
1045
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001046 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001047
1048 if (request != NULL) {
1049 /* Allocate space for populating ssids in struct */
1050 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1051
1052 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001053 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001054 }
1055
1056 params = kzalloc(params_size, GFP_KERNEL);
1057 if (!params) {
1058 err = -ENOMEM;
1059 goto exit;
1060 }
1061 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001062 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001063 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001064 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001065 params->sync_id = cpu_to_le16(0x1234);
1066
Arend van Spriela0f472a2013-04-05 10:57:49 +02001067 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001068 if (err) {
1069 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001070 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001071 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001072 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001073 }
1074
1075 kfree(params);
1076exit:
1077 return err;
1078}
1079
1080static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001081brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001082{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001083 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001084 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001085 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001086 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001087 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001088
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001089 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001090 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001091 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001092 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001093 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001094 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001095 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001096 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001097 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001098 return err;
1099 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001100 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001101 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001102 results->version = 0;
1103 results->count = 0;
1104 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1105
Hante Meulemanc4958102015-11-25 11:32:41 +01001106 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001107 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001108 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 return err;
1110}
1111
1112static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001113brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001114 struct cfg80211_scan_request *request,
1115 struct cfg80211_ssid *this_ssid)
1116{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001117 struct brcmf_if *ifp = vif->ifp;
1118 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001119 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001120 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001121 bool escan_req;
1122 bool spec_scan;
1123 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001124 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001125 u32 SSID_len;
1126
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001127 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001128
Arend van Sprielc1179032012-10-22 13:55:33 -07001129 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001130 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001131 return -EAGAIN;
1132 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001133 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001134 brcmf_err("Scanning being aborted: status (%lu)\n",
1135 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001136 return -EAGAIN;
1137 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001138 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1139 brcmf_err("Scanning suppressed: status (%lu)\n",
1140 cfg->scan_status);
1141 return -EAGAIN;
1142 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001143 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001144 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001145 return -EAGAIN;
1146 }
1147
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001148 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001149 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1150 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001151
Hante Meulemane756af52012-09-11 21:18:52 +02001152 escan_req = false;
1153 if (request) {
1154 /* scan bss */
1155 ssids = request->ssids;
1156 escan_req = true;
1157 } else {
1158 /* scan in ibss */
1159 /* we don't do escan in ibss */
1160 ssids = this_ssid;
1161 }
1162
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001163 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001164 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001165 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001166 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001167 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001168 if (err)
1169 goto scan_out;
1170
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001171 err = brcmf_do_escan(vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001172 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001173 goto scan_out;
1174 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001175 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1176 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001177 memset(&ssid_le, 0, sizeof(ssid_le));
1178 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1179 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001180 spec_scan = false;
1181 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001182 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1183 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001184 spec_scan = true;
1185 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001186 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001187
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001188 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001189 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001190 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001191 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001192 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001193 goto scan_out;
1194 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001195 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001196 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1197 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001198 if (err) {
1199 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001200 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001201 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001202 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001203 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001204
Daniel Kim5e787f72014-06-21 12:11:18 +02001205 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001206 goto scan_out;
1207 }
1208 }
1209
Hante Meuleman661fa952015-02-06 18:36:47 +01001210 /* Arm scan timeout timer */
1211 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001212 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001213
Hante Meulemane756af52012-09-11 21:18:52 +02001214 return 0;
1215
1216scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001217 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001218 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001219 return err;
1220}
1221
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001223brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001224{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001225 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226 s32 err = 0;
1227
Arend van Sprield96b8012012-12-05 15:26:02 +01001228 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001229 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1230 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001231 return -EIO;
1232
Arend van Spriela0f472a2013-04-05 10:57:49 +02001233 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001234
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001236 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237
Arend van Sprield96b8012012-12-05 15:26:02 +01001238 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 return err;
1240}
1241
1242static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1243{
1244 s32 err = 0;
1245
Arend van Sprielac24be62012-10-22 10:36:23 -07001246 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1247 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001249 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250
1251 return err;
1252}
1253
1254static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1255{
1256 s32 err = 0;
1257
Arend van Sprielac24be62012-10-22 10:36:23 -07001258 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1259 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001260 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001261 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262
1263 return err;
1264}
1265
1266static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1267{
1268 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001269 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001270
Arend van Sprielac24be62012-10-22 10:36:23 -07001271 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001273 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001274 return err;
1275 }
1276 return err;
1277}
1278
1279static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1280{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001281 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1282 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001283 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001284 s32 err = 0;
1285
Arend van Sprield96b8012012-12-05 15:26:02 +01001286 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001287 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288 return -EIO;
1289
1290 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001291 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1292 cfg->conf->rts_threshold = wiphy->rts_threshold;
1293 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001294 if (!err)
1295 goto done;
1296 }
1297 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001298 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1299 cfg->conf->frag_threshold = wiphy->frag_threshold;
1300 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301 if (!err)
1302 goto done;
1303 }
1304 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001305 && (cfg->conf->retry_long != wiphy->retry_long)) {
1306 cfg->conf->retry_long = wiphy->retry_long;
1307 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001308 if (!err)
1309 goto done;
1310 }
1311 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001312 && (cfg->conf->retry_short != wiphy->retry_short)) {
1313 cfg->conf->retry_short = wiphy->retry_short;
1314 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001315 if (!err)
1316 goto done;
1317 }
1318
1319done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001320 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 return err;
1322}
1323
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1325{
1326 memset(prof, 0, sizeof(*prof));
1327}
1328
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001329static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1330{
1331 u16 reason;
1332
1333 switch (e->event_code) {
1334 case BRCMF_E_DEAUTH:
1335 case BRCMF_E_DEAUTH_IND:
1336 case BRCMF_E_DISASSOC_IND:
1337 reason = e->reason;
1338 break;
1339 case BRCMF_E_LINK:
1340 default:
1341 reason = 0;
1342 break;
1343 }
1344 return reason;
1345}
1346
1347static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001348{
Piotr Haber61730d42013-04-23 12:53:12 +02001349 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350 s32 err = 0;
1351
Arend van Sprield96b8012012-12-05 15:26:02 +01001352 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353
Hante Meulemanb0a79082015-12-10 13:43:07 +01001354 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001355 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001356 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001357 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001358 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001359 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001360 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001361 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1362 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1363 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1364 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001365 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001366 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001367 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1368 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001369 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001370}
1371
1372static s32
1373brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1374 struct cfg80211_ibss_params *params)
1375{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001376 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001377 struct brcmf_if *ifp = netdev_priv(ndev);
1378 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001379 struct brcmf_join_params join_params;
1380 size_t join_params_size = 0;
1381 s32 err = 0;
1382 s32 wsec = 0;
1383 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001384 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001385 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001386
Arend van Sprield96b8012012-12-05 15:26:02 +01001387 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001388 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001389 return -EIO;
1390
1391 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001392 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001393 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001394 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001395 return -EOPNOTSUPP;
1396 }
1397
Arend van Sprielc1179032012-10-22 13:55:33 -07001398 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399
1400 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001401 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 else
Arend van Spriel16886732012-12-05 15:26:04 +01001403 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404
Johannes Berg683b6d32012-11-08 21:25:48 +01001405 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001406 brcmf_dbg(CONN, "channel: %d\n",
1407 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 else
Arend van Spriel16886732012-12-05 15:26:04 +01001409 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410
1411 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001412 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001413 else
Arend van Spriel16886732012-12-05 15:26:04 +01001414 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415
1416 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001417 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418 else
Arend van Spriel16886732012-12-05 15:26:04 +01001419 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001420
1421 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001422 brcmf_dbg(CONN, "beacon interval: %d\n",
1423 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 else
Arend van Spriel16886732012-12-05 15:26:04 +01001425 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001426
1427 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001428 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 else
Arend van Spriel16886732012-12-05 15:26:04 +01001430 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431
1432 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001433 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001434 else
Arend van Spriel16886732012-12-05 15:26:04 +01001435 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436
1437 /* Configure Privacy for starter */
1438 if (params->privacy)
1439 wsec |= WEP_ENABLED;
1440
Arend van Sprielc1179032012-10-22 13:55:33 -07001441 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001443 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001444 goto done;
1445 }
1446
1447 /* Configure Beacon Interval for starter */
1448 if (params->beacon_interval)
1449 bcnprd = params->beacon_interval;
1450 else
1451 bcnprd = 100;
1452
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001453 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001454 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001455 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 goto done;
1457 }
1458
1459 /* Configure required join parameter */
1460 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1461
1462 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001463 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1464 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1465 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467
1468 /* BSSID */
1469 if (params->bssid) {
1470 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001471 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001472 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001474 eth_broadcast_addr(join_params.params_le.bssid);
1475 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001476 }
1477
Arend van Spriel5b435de2011-10-05 13:19:03 +02001478 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001479 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 u32 target_channel;
1481
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001482 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001483 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001484 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001485 if (params->channel_fixed) {
1486 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001487 chanspec = chandef_to_chanspec(&cfg->d11inf,
1488 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001489 join_params.params_le.chanspec_list[0] =
1490 cpu_to_le16(chanspec);
1491 join_params.params_le.chanspec_num = cpu_to_le32(1);
1492 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001493 }
1494
1495 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001496 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001497 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001498 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001499 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001500 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501 goto done;
1502 }
1503 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001504 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001506 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001507
1508
Arend van Sprielc1179032012-10-22 13:55:33 -07001509 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001510 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001512 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001513 goto done;
1514 }
1515
1516done:
1517 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001518 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001519 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001520 return err;
1521}
1522
1523static s32
1524brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1525{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001526 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001527
Arend van Sprield96b8012012-12-05 15:26:02 +01001528 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001529 if (!check_vif_up(ifp->vif)) {
1530 /* When driver is being unloaded, it can end up here. If an
1531 * error is returned then later on a debug trace in the wireless
1532 * core module will be printed. To avoid this 0 is returned.
1533 */
1534 return 0;
1535 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001536
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001537 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001538 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539
Arend van Sprield96b8012012-12-05 15:26:02 +01001540 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001541
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001542 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543}
1544
1545static s32 brcmf_set_wpa_version(struct net_device *ndev,
1546 struct cfg80211_connect_params *sme)
1547{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001548 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549 struct brcmf_cfg80211_security *sec;
1550 s32 val = 0;
1551 s32 err = 0;
1552
1553 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1554 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1555 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1556 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1557 else
1558 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001559 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001560 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001561 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001562 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001563 return err;
1564 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001565 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001566 sec->wpa_versions = sme->crypto.wpa_versions;
1567 return err;
1568}
1569
1570static s32 brcmf_set_auth_type(struct net_device *ndev,
1571 struct cfg80211_connect_params *sme)
1572{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001573 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 struct brcmf_cfg80211_security *sec;
1575 s32 val = 0;
1576 s32 err = 0;
1577
1578 switch (sme->auth_type) {
1579 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1580 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001581 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 break;
1583 case NL80211_AUTHTYPE_SHARED_KEY:
1584 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001585 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587 default:
1588 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001589 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001590 break;
1591 }
1592
Hante Meuleman89286dc2013-02-08 15:53:46 +01001593 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001594 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001595 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001596 return err;
1597 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001598 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 sec->auth_type = sme->auth_type;
1600 return err;
1601}
1602
1603static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001604brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001605 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001606{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001607 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001608 struct brcmf_cfg80211_security *sec;
1609 s32 pval = 0;
1610 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001611 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612 s32 err = 0;
1613
1614 if (sme->crypto.n_ciphers_pairwise) {
1615 switch (sme->crypto.ciphers_pairwise[0]) {
1616 case WLAN_CIPHER_SUITE_WEP40:
1617 case WLAN_CIPHER_SUITE_WEP104:
1618 pval = WEP_ENABLED;
1619 break;
1620 case WLAN_CIPHER_SUITE_TKIP:
1621 pval = TKIP_ENABLED;
1622 break;
1623 case WLAN_CIPHER_SUITE_CCMP:
1624 pval = AES_ENABLED;
1625 break;
1626 case WLAN_CIPHER_SUITE_AES_CMAC:
1627 pval = AES_ENABLED;
1628 break;
1629 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001630 brcmf_err("invalid cipher pairwise (%d)\n",
1631 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 return -EINVAL;
1633 }
1634 }
1635 if (sme->crypto.cipher_group) {
1636 switch (sme->crypto.cipher_group) {
1637 case WLAN_CIPHER_SUITE_WEP40:
1638 case WLAN_CIPHER_SUITE_WEP104:
1639 gval = WEP_ENABLED;
1640 break;
1641 case WLAN_CIPHER_SUITE_TKIP:
1642 gval = TKIP_ENABLED;
1643 break;
1644 case WLAN_CIPHER_SUITE_CCMP:
1645 gval = AES_ENABLED;
1646 break;
1647 case WLAN_CIPHER_SUITE_AES_CMAC:
1648 gval = AES_ENABLED;
1649 break;
1650 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001651 brcmf_err("invalid cipher group (%d)\n",
1652 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 return -EINVAL;
1654 }
1655 }
1656
Arend van Spriel16886732012-12-05 15:26:04 +01001657 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001658 /* In case of privacy, but no security and WPS then simulate */
1659 /* setting AES. WPS-2.0 allows no security */
1660 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1661 sme->privacy)
1662 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001663
Hante Meuleman240d61a2016-02-17 11:27:10 +01001664 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001665 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001666 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001667 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001668 return err;
1669 }
1670
Arend van Spriel06bb1232012-09-27 14:17:56 +02001671 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1673 sec->cipher_group = sme->crypto.cipher_group;
1674
1675 return err;
1676}
1677
1678static s32
1679brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1680{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001681 struct brcmf_if *ifp = netdev_priv(ndev);
1682 s32 val;
1683 s32 err;
1684 const struct brcmf_tlv *rsn_ie;
1685 const u8 *ie;
1686 u32 ie_len;
1687 u32 offset;
1688 u16 rsn_cap;
1689 u32 mfp;
1690 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001691
Hante Meuleman240d61a2016-02-17 11:27:10 +01001692 if (!sme->crypto.n_akm_suites)
1693 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001694
Hante Meuleman240d61a2016-02-17 11:27:10 +01001695 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1696 if (err) {
1697 brcmf_err("could not get wpa_auth (%d)\n", err);
1698 return err;
1699 }
1700 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1701 switch (sme->crypto.akm_suites[0]) {
1702 case WLAN_AKM_SUITE_8021X:
1703 val = WPA_AUTH_UNSPECIFIED;
1704 break;
1705 case WLAN_AKM_SUITE_PSK:
1706 val = WPA_AUTH_PSK;
1707 break;
1708 default:
1709 brcmf_err("invalid cipher group (%d)\n",
1710 sme->crypto.cipher_group);
1711 return -EINVAL;
1712 }
1713 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1714 switch (sme->crypto.akm_suites[0]) {
1715 case WLAN_AKM_SUITE_8021X:
1716 val = WPA2_AUTH_UNSPECIFIED;
1717 break;
1718 case WLAN_AKM_SUITE_8021X_SHA256:
1719 val = WPA2_AUTH_1X_SHA256;
1720 break;
1721 case WLAN_AKM_SUITE_PSK_SHA256:
1722 val = WPA2_AUTH_PSK_SHA256;
1723 break;
1724 case WLAN_AKM_SUITE_PSK:
1725 val = WPA2_AUTH_PSK;
1726 break;
1727 default:
1728 brcmf_err("invalid cipher group (%d)\n",
1729 sme->crypto.cipher_group);
1730 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001731 }
1732 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001733
1734 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1735 goto skip_mfp_config;
1736 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1737 * IE will not be verified, just a quick search for MFP config
1738 */
1739 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1740 WLAN_EID_RSN);
1741 if (!rsn_ie)
1742 goto skip_mfp_config;
1743 ie = (const u8 *)rsn_ie;
1744 ie_len = rsn_ie->len + TLV_HDR_LEN;
1745 /* Skip unicast suite */
1746 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1747 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1748 goto skip_mfp_config;
1749 /* Skip multicast suite */
1750 count = ie[offset] + (ie[offset + 1] << 8);
1751 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1752 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1753 goto skip_mfp_config;
1754 /* Skip auth key management suite(s) */
1755 count = ie[offset] + (ie[offset + 1] << 8);
1756 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1757 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1758 goto skip_mfp_config;
1759 /* Ready to read capabilities */
1760 mfp = BRCMF_MFP_NONE;
1761 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1762 if (rsn_cap & RSN_CAP_MFPR_MASK)
1763 mfp = BRCMF_MFP_REQUIRED;
1764 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1765 mfp = BRCMF_MFP_CAPABLE;
1766 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1767
1768skip_mfp_config:
1769 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1770 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1771 if (err) {
1772 brcmf_err("could not set wpa_auth (%d)\n", err);
1773 return err;
1774 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001775
1776 return err;
1777}
1778
1779static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001780brcmf_set_sharedkey(struct net_device *ndev,
1781 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001782{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001783 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001784 struct brcmf_cfg80211_security *sec;
1785 struct brcmf_wsec_key key;
1786 s32 val;
1787 s32 err = 0;
1788
Arend van Spriel16886732012-12-05 15:26:04 +01001789 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001790
Roland Vossena718e2f2011-10-12 20:51:24 +02001791 if (sme->key_len == 0)
1792 return 0;
1793
Arend van Spriel06bb1232012-09-27 14:17:56 +02001794 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001795 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1796 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001797
1798 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1799 return 0;
1800
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001801 if (!(sec->cipher_pairwise &
1802 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1803 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001804
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001805 memset(&key, 0, sizeof(key));
1806 key.len = (u32) sme->key_len;
1807 key.index = (u32) sme->key_idx;
1808 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001809 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001810 return -EINVAL;
1811 }
1812 memcpy(key.data, sme->key, key.len);
1813 key.flags = BRCMF_PRIMARY_KEY;
1814 switch (sec->cipher_pairwise) {
1815 case WLAN_CIPHER_SUITE_WEP40:
1816 key.algo = CRYPTO_ALGO_WEP1;
1817 break;
1818 case WLAN_CIPHER_SUITE_WEP104:
1819 key.algo = CRYPTO_ALGO_WEP128;
1820 break;
1821 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001822 brcmf_err("Invalid algorithm (%d)\n",
1823 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001824 return -EINVAL;
1825 }
1826 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001827 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1828 key.len, key.index, key.algo);
1829 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001830 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001831 if (err)
1832 return err;
1833
1834 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001835 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001836 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001837 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001838 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001839 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 }
1841 return err;
1842}
1843
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001844static
1845enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1846 enum nl80211_auth_type type)
1847{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001848 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1849 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1850 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1851 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001852 }
1853 return type;
1854}
1855
Arend van Spriel7705ba62016-04-17 16:44:58 +02001856static void brcmf_set_join_pref(struct brcmf_if *ifp,
1857 struct cfg80211_bss_selection *bss_select)
1858{
1859 struct brcmf_join_pref_params join_pref_params[2];
1860 enum nl80211_band band;
1861 int err, i = 0;
1862
1863 join_pref_params[i].len = 2;
1864 join_pref_params[i].rssi_gain = 0;
1865
1866 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1867 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1868
1869 switch (bss_select->behaviour) {
1870 case __NL80211_BSS_SELECT_ATTR_INVALID:
1871 brcmf_c_set_joinpref_default(ifp);
1872 return;
1873 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1874 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1875 band = bss_select->param.band_pref;
1876 join_pref_params[i].band = nl80211_band_to_fwil(band);
1877 i++;
1878 break;
1879 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1880 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1881 band = bss_select->param.adjust.band;
1882 join_pref_params[i].band = nl80211_band_to_fwil(band);
1883 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1884 i++;
1885 break;
1886 case NL80211_BSS_SELECT_ATTR_RSSI:
1887 default:
1888 break;
1889 }
1890 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1891 join_pref_params[i].len = 2;
1892 join_pref_params[i].rssi_gain = 0;
1893 join_pref_params[i].band = 0;
1894 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1895 sizeof(join_pref_params));
1896 if (err)
1897 brcmf_err("Set join_pref error (%d)\n", err);
1898}
1899
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900static s32
1901brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001902 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001904 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001905 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001906 struct ieee80211_channel *chan = sme->channel;
1907 struct brcmf_join_params join_params;
1908 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001909 const struct brcmf_tlv *rsn_ie;
1910 const struct brcmf_vs_tlv *wpa_ie;
1911 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001912 u32 ie_len;
1913 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001914 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001915 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001916 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917
Arend van Sprield96b8012012-12-05 15:26:02 +01001918 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001919 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001920 return -EIO;
1921
1922 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001923 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001924 return -EOPNOTSUPP;
1925 }
1926
Hante Meuleman89286dc2013-02-08 15:53:46 +01001927 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1928 /* A normal (non P2P) connection request setup. */
1929 ie = NULL;
1930 ie_len = 0;
1931 /* find the WPA_IE */
1932 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1933 if (wpa_ie) {
1934 ie = wpa_ie;
1935 ie_len = wpa_ie->len + TLV_HDR_LEN;
1936 } else {
1937 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001938 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1939 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001940 WLAN_EID_RSN);
1941 if (rsn_ie) {
1942 ie = rsn_ie;
1943 ie_len = rsn_ie->len + TLV_HDR_LEN;
1944 }
1945 }
1946 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1947 }
1948
1949 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1950 sme->ie, sme->ie_len);
1951 if (err)
1952 brcmf_err("Set Assoc REQ IE Failed\n");
1953 else
1954 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1955
Arend van Sprielc1179032012-10-22 13:55:33 -07001956 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957
1958 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001959 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001960 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001961 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001962 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1963 cfg->channel, chan->center_freq, chanspec);
1964 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001965 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001966 chanspec = 0;
1967 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001969 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001970
1971 err = brcmf_set_wpa_version(ndev, sme);
1972 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001973 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001974 goto done;
1975 }
1976
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001977 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001978 err = brcmf_set_auth_type(ndev, sme);
1979 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001980 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981 goto done;
1982 }
1983
Hante Meuleman240d61a2016-02-17 11:27:10 +01001984 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001986 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001987 goto done;
1988 }
1989
1990 err = brcmf_set_key_mgmt(ndev, sme);
1991 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001992 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001993 goto done;
1994 }
1995
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001996 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001997 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001998 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999 goto done;
2000 }
2001
Hante Meuleman89286dc2013-02-08 15:53:46 +01002002 /* Join with specific BSSID and cached SSID
2003 * If SSID is zero join based on BSSID only
2004 */
2005 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2006 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2007 if (cfg->channel)
2008 join_params_size += sizeof(u16);
2009 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2010 if (ext_join_params == NULL) {
2011 err = -ENOMEM;
2012 goto done;
2013 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002014 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2015 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2016 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2017 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2018 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2019 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002020
Hante Meuleman89286dc2013-02-08 15:53:46 +01002021 /* Set up join scan parameters */
2022 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002023 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2024
2025 if (sme->bssid)
2026 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2027 else
Joe Perches93803b32015-03-02 19:54:49 -08002028 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002029
2030 if (cfg->channel) {
2031 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2032
2033 ext_join_params->assoc_le.chanspec_list[0] =
2034 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002035 /* Increase dwell time to receive probe response or detect
2036 * beacon from target AP at a noisy air only during connect
2037 * command.
2038 */
2039 ext_join_params->scan_le.active_time =
2040 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2041 ext_join_params->scan_le.passive_time =
2042 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2043 /* To sync with presence period of VSDB GO send probe request
2044 * more frequently. Probe request will be stopped when it gets
2045 * probe response from target AP/GO.
2046 */
2047 ext_join_params->scan_le.nprobes =
2048 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2049 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2050 } else {
2051 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2052 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2053 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002054 }
2055
Arend van Spriel7705ba62016-04-17 16:44:58 +02002056 brcmf_set_join_pref(ifp, &sme->bss_select);
2057
Hante Meuleman89286dc2013-02-08 15:53:46 +01002058 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2059 join_params_size);
2060 kfree(ext_join_params);
2061 if (!err)
2062 /* This is it. join command worked, we are done */
2063 goto done;
2064
2065 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066 memset(&join_params, 0, sizeof(join_params));
2067 join_params_size = sizeof(join_params.ssid_le);
2068
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002069 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2070 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002071
Hante Meuleman89286dc2013-02-08 15:53:46 +01002072 if (sme->bssid)
2073 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2074 else
Joe Perches93803b32015-03-02 19:54:49 -08002075 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002076
Hante Meuleman17012612013-02-06 18:40:44 +01002077 if (cfg->channel) {
2078 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2079 join_params.params_le.chanspec_num = cpu_to_le32(1);
2080 join_params_size += sizeof(join_params.params_le);
2081 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002082 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002083 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002084 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002085 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002086
2087done:
2088 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002089 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002090 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002091 return err;
2092}
2093
2094static s32
2095brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2096 u16 reason_code)
2097{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002098 struct brcmf_if *ifp = netdev_priv(ndev);
2099 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 struct brcmf_scb_val_le scbval;
2101 s32 err = 0;
2102
Arend van Sprield96b8012012-12-05 15:26:02 +01002103 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002104 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105 return -EIO;
2106
Arend van Sprielc1179032012-10-22 13:55:33 -07002107 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002108 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002109 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002110
Arend van Spriel06bb1232012-09-27 14:17:56 +02002111 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002113 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002114 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002116 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117
Arend van Sprield96b8012012-12-05 15:26:02 +01002118 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119 return err;
2120}
2121
2122static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002123brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002124 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002125{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002126 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002127 struct net_device *ndev = cfg_to_ndev(cfg);
2128 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002129 s32 err;
2130 s32 disable;
2131 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002133 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002134 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 return -EIO;
2136
2137 switch (type) {
2138 case NL80211_TX_POWER_AUTOMATIC:
2139 break;
2140 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002142 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002143 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 err = -EINVAL;
2145 goto done;
2146 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002147 qdbm = MBM_TO_DBM(4 * mbm);
2148 if (qdbm > 127)
2149 qdbm = 127;
2150 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002152 default:
2153 brcmf_err("Unsupported type %d\n", type);
2154 err = -EINVAL;
2155 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002156 }
2157 /* Make sure radio is off or on as far as software is concerned */
2158 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002159 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002161 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002163 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002165 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166
2167done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002168 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 return err;
2170}
2171
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002172static s32
2173brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2174 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002175{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002176 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002177 struct net_device *ndev = cfg_to_ndev(cfg);
2178 struct brcmf_if *ifp = netdev_priv(ndev);
2179 s32 qdbm = 0;
2180 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181
Arend van Sprield96b8012012-12-05 15:26:02 +01002182 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002183 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002184 return -EIO;
2185
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002186 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002187 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002188 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 goto done;
2190 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002191 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002192
2193done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002194 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 return err;
2196}
2197
2198static s32
2199brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002200 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002202 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002203 u32 index;
2204 u32 wsec;
2205 s32 err = 0;
2206
Arend van Sprield96b8012012-12-05 15:26:02 +01002207 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002208 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002209 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002210 return -EIO;
2211
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002212 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002213 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002214 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002215 goto done;
2216 }
2217
2218 if (wsec & WEP_ENABLED) {
2219 /* Just select a new current key */
2220 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002221 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002222 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002224 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002225 }
2226done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002227 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002228 return err;
2229}
2230
2231static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002232brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2233 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002234{
Hante Meuleman992f6062013-04-02 21:06:17 +02002235 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002236 struct brcmf_wsec_key *key;
2237 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002238
2239 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002240 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2241
Hante Meuleman219e0f72016-02-17 11:27:09 +01002242 if (!check_vif_up(ifp->vif))
2243 return -EIO;
2244
2245 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2246 /* we ignore this key index in this case */
2247 return -EINVAL;
2248 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002249
Hante Meuleman240d61a2016-02-17 11:27:10 +01002250 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251
Hante Meuleman240d61a2016-02-17 11:27:10 +01002252 if (key->algo == CRYPTO_ALGO_OFF) {
2253 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2254 return -EINVAL;
2255 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002256
Hante Meuleman240d61a2016-02-17 11:27:10 +01002257 memset(key, 0, sizeof(*key));
2258 key->index = (u32)key_idx;
2259 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Hante Meuleman240d61a2016-02-17 11:27:10 +01002261 /* Clear the key/index */
2262 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263
Hante Meuleman219e0f72016-02-17 11:27:09 +01002264 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 return err;
2266}
2267
2268static s32
2269brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002270 u8 key_idx, bool pairwise, const u8 *mac_addr,
2271 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002272{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002273 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002274 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275 s32 val;
2276 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002277 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002278 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002279 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002280
Arend van Sprield96b8012012-12-05 15:26:02 +01002281 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002282 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002283 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284 return -EIO;
2285
Hante Meuleman118eb302014-12-21 12:43:49 +01002286 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2287 /* we ignore this key index in this case */
2288 brcmf_err("invalid key index (%d)\n", key_idx);
2289 return -EINVAL;
2290 }
2291
Hante Meuleman219e0f72016-02-17 11:27:09 +01002292 if (params->key_len == 0)
2293 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2294 mac_addr);
2295
2296 if (params->key_len > sizeof(key->data)) {
2297 brcmf_err("Too long key length (%u)\n", params->key_len);
2298 return -EINVAL;
2299 }
2300
2301 ext_key = false;
2302 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2303 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2304 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2305 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307
Hante Meuleman118eb302014-12-21 12:43:49 +01002308 key = &ifp->vif->profile.key[key_idx];
2309 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002310 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2311 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002312 key->len = params->key_len;
2313 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002314 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002315 if (!ext_key)
2316 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002317
Arend van Spriel5b435de2011-10-05 13:19:03 +02002318 switch (params->cipher) {
2319 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002320 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002321 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002322 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 break;
2324 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002325 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002326 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002327 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002328 break;
2329 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002330 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002331 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002332 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2333 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2334 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002335 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002336 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002337 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002338 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339 break;
2340 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002341 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002342 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002343 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344 break;
2345 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002346 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002347 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002348 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002349 break;
2350 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002351 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352 err = -EINVAL;
2353 goto done;
2354 }
2355
Hante Meuleman118eb302014-12-21 12:43:49 +01002356 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002357 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002358 goto done;
2359
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002360 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002361 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002362 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 goto done;
2364 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002366 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002367 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002368 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 goto done;
2370 }
2371
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002373 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002374 return err;
2375}
2376
2377static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002378brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2379 bool pairwise, const u8 *mac_addr, void *cookie,
2380 void (*callback)(void *cookie,
2381 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382{
2383 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002384 struct brcmf_if *ifp = netdev_priv(ndev);
2385 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 struct brcmf_cfg80211_security *sec;
2387 s32 wsec;
2388 s32 err = 0;
2389
Arend van Sprield96b8012012-12-05 15:26:02 +01002390 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002391 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002392 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002393 return -EIO;
2394
2395 memset(&params, 0, sizeof(params));
2396
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002397 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002398 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002399 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400 /* Ignore this error, may happen during DISASSOC */
2401 err = -EAGAIN;
2402 goto done;
2403 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002404 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002405 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002406 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2407 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002408 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002409 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2410 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002411 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002412 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002413 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002414 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002415 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002416 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002417 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002418 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002419 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002420 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002421 err = -EINVAL;
2422 goto done;
2423 }
2424 callback(cookie, &params);
2425
2426done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002427 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 return err;
2429}
2430
2431static s32
2432brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002433 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002435 struct brcmf_if *ifp = netdev_priv(ndev);
2436
2437 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2438
2439 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2440 return 0;
2441
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002442 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002443
2444 return -EOPNOTSUPP;
2445}
2446
Hante Meuleman118eb302014-12-21 12:43:49 +01002447static void
2448brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2449{
2450 s32 err;
2451 u8 key_idx;
2452 struct brcmf_wsec_key *key;
2453 s32 wsec;
2454
2455 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2456 key = &ifp->vif->profile.key[key_idx];
2457 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2458 (key->algo == CRYPTO_ALGO_WEP128))
2459 break;
2460 }
2461 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2462 return;
2463
2464 err = send_key_to_dongle(ifp, key);
2465 if (err) {
2466 brcmf_err("Setting WEP key failed (%d)\n", err);
2467 return;
2468 }
2469 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2470 if (err) {
2471 brcmf_err("get wsec error (%d)\n", err);
2472 return;
2473 }
2474 wsec |= WEP_ENABLED;
2475 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2476 if (err)
2477 brcmf_err("set wsec error (%d)\n", err);
2478}
2479
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002480static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2481{
2482 struct nl80211_sta_flag_update *sfu;
2483
2484 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2485 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2486 sfu = &si->sta_flags;
2487 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2488 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2489 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2490 BIT(NL80211_STA_FLAG_AUTHORIZED);
2491 if (fw_sta_flags & BRCMF_STA_WME)
2492 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2493 if (fw_sta_flags & BRCMF_STA_AUTHE)
2494 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2495 if (fw_sta_flags & BRCMF_STA_ASSOC)
2496 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2497 if (fw_sta_flags & BRCMF_STA_AUTHO)
2498 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2499}
2500
2501static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2502{
2503 struct {
2504 __le32 len;
2505 struct brcmf_bss_info_le bss_le;
2506 } *buf;
2507 u16 capability;
2508 int err;
2509
2510 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2511 if (!buf)
2512 return;
2513
2514 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2515 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2516 WL_BSS_INFO_MAX);
2517 if (err) {
2518 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002519 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002520 }
2521 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2522 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2523 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2524 capability = le16_to_cpu(buf->bss_le.capability);
2525 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2526 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2527 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2528 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2529 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2530 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002531
2532out_kfree:
2533 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002534}
2535
Arend van Spriel5b435de2011-10-05 13:19:03 +02002536static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002537brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2538 struct station_info *sinfo)
2539{
2540 struct brcmf_scb_val_le scbval;
2541 struct brcmf_pktcnt_le pktcnt;
2542 s32 err;
2543 u32 rate;
2544 u32 rssi;
2545
2546 /* Get the current tx rate */
2547 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2548 if (err < 0) {
2549 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2550 return err;
2551 }
2552 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2553 sinfo->txrate.legacy = rate * 5;
2554
2555 memset(&scbval, 0, sizeof(scbval));
2556 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2557 sizeof(scbval));
2558 if (err) {
2559 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2560 return err;
2561 }
2562 rssi = le32_to_cpu(scbval.val);
2563 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2564 sinfo->signal = rssi;
2565
2566 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2567 sizeof(pktcnt));
2568 if (err) {
2569 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2570 return err;
2571 }
2572 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2573 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2574 BIT(NL80211_STA_INFO_TX_PACKETS) |
2575 BIT(NL80211_STA_INFO_TX_FAILED);
2576 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2577 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2578 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2579 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2580
2581 return 0;
2582}
2583
2584static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002585brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002586 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002587{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002588 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002589 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002590 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002591 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002592 u32 sta_flags;
2593 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002594 s32 total_rssi;
2595 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002596 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002597 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002598
Arend van Sprield96b8012012-12-05 15:26:02 +01002599 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002600 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002601 return -EIO;
2602
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002603 if (brcmf_is_ibssmode(ifp->vif))
2604 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2605
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002606 memset(&sta_info_le, 0, sizeof(sta_info_le));
2607 memcpy(&sta_info_le, mac, ETH_ALEN);
2608 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2609 &sta_info_le,
2610 sizeof(sta_info_le));
2611 is_tdls_peer = !err;
2612 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002613 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002614 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002615 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002616 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002617 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002618 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002619 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002620 }
2621 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2622 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2623 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2624 sta_flags = le32_to_cpu(sta_info_le.flags);
2625 brcmf_convert_sta_flags(sta_flags, sinfo);
2626 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2627 if (is_tdls_peer)
2628 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2629 else
2630 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2631 if (sta_flags & BRCMF_STA_ASSOC) {
2632 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2633 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2634 brcmf_fill_bss_param(ifp, sinfo);
2635 }
2636 if (sta_flags & BRCMF_STA_SCBSTATS) {
2637 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2638 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2639 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2640 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2641 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2642 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2643 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2644 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2645 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002646 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002647 sinfo->txrate.legacy =
2648 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002649 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002650 if (sinfo->rx_packets) {
2651 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002652 sinfo->rxrate.legacy =
2653 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002654 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002655 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2656 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2657 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2658 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2659 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2660 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002661 total_rssi = 0;
2662 count_rssi = 0;
2663 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2664 if (sta_info_le.rssi[i]) {
2665 sinfo->chain_signal_avg[count_rssi] =
2666 sta_info_le.rssi[i];
2667 sinfo->chain_signal[count_rssi] =
2668 sta_info_le.rssi[i];
2669 total_rssi += sta_info_le.rssi[i];
2670 count_rssi++;
2671 }
2672 }
2673 if (count_rssi) {
2674 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2675 sinfo->chains = count_rssi;
2676
2677 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2678 total_rssi /= count_rssi;
2679 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002680 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2681 &ifp->vif->sme_state)) {
2682 memset(&scb_val, 0, sizeof(scb_val));
2683 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2684 &scb_val, sizeof(scb_val));
2685 if (err) {
2686 brcmf_err("Could not get rssi (%d)\n", err);
2687 goto done;
2688 } else {
2689 rssi = le32_to_cpu(scb_val.val);
2690 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2691 sinfo->signal = rssi;
2692 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2693 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002694 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002695 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002696done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002697 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002698 return err;
2699}
2700
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002701static int
2702brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2703 int idx, u8 *mac, struct station_info *sinfo)
2704{
2705 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2706 struct brcmf_if *ifp = netdev_priv(ndev);
2707 s32 err;
2708
2709 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2710
2711 if (idx == 0) {
2712 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2713 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2714 &cfg->assoclist,
2715 sizeof(cfg->assoclist));
2716 if (err) {
2717 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2718 err);
2719 cfg->assoclist.count = 0;
2720 return -EOPNOTSUPP;
2721 }
2722 }
2723 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2724 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2725 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2726 }
2727 return -ENOENT;
2728}
2729
Arend van Spriel5b435de2011-10-05 13:19:03 +02002730static s32
2731brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2732 bool enabled, s32 timeout)
2733{
2734 s32 pm;
2735 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002736 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002737 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002738
Arend van Sprield96b8012012-12-05 15:26:02 +01002739 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002740
2741 /*
2742 * Powersave enable/disable request is coming from the
2743 * cfg80211 even before the interface is up. In that
2744 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002745 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002746 * FW later while initializing the dongle
2747 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002748 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002749 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002750
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002751 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002752 goto done;
2753 }
2754
2755 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002756 /* Do not enable the power save after assoc if it is a p2p interface */
2757 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2758 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2759 pm = PM_OFF;
2760 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002761 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002762
Arend van Sprielc1179032012-10-22 13:55:33 -07002763 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002764 if (err) {
2765 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002766 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002767 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002768 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002769 }
2770done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002771 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772 return err;
2773}
2774
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002775static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002776 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002777{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002778 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002779 struct ieee80211_channel *notify_channel;
2780 struct cfg80211_bss *bss;
2781 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002782 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002783 u16 channel;
2784 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002785 u16 notify_capability;
2786 u16 notify_interval;
2787 u8 *notify_ie;
2788 size_t notify_ielen;
2789 s32 notify_signal;
2790
2791 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002792 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002793 return 0;
2794 }
2795
Franky Lin83cf17a2013-04-11 13:28:50 +02002796 if (!bi->ctl_ch) {
2797 ch.chspec = le16_to_cpu(bi->chanspec);
2798 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002799 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002800 }
2801 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002802
2803 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002804 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002805 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002806 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807
2808 freq = ieee80211_channel_to_frequency(channel, band->band);
2809 notify_channel = ieee80211_get_channel(wiphy, freq);
2810
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811 notify_capability = le16_to_cpu(bi->capability);
2812 notify_interval = le16_to_cpu(bi->beacon_period);
2813 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2814 notify_ielen = le32_to_cpu(bi->ie_length);
2815 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2816
Arend van Spriel16886732012-12-05 15:26:04 +01002817 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2818 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2819 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2820 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2821 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002823 bss = cfg80211_inform_bss(wiphy, notify_channel,
2824 CFG80211_BSS_FTYPE_UNKNOWN,
2825 (const u8 *)bi->BSSID,
2826 0, notify_capability,
2827 notify_interval, notify_ie,
2828 notify_ielen, notify_signal,
2829 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830
Franky Line78946e2011-11-10 20:30:34 +01002831 if (!bss)
2832 return -ENOMEM;
2833
Johannes Berg5b112d32013-02-01 01:49:58 +01002834 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002835
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002836 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837}
2838
Roland Vossen6f09be02011-10-18 14:03:02 +02002839static struct brcmf_bss_info_le *
2840next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2841{
2842 if (bss == NULL)
2843 return list->bss_info_le;
2844 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2845 le32_to_cpu(bss->length));
2846}
2847
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002848static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002849{
2850 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002851 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002852 s32 err = 0;
2853 int i;
2854
Hante Meulemanef8596e2014-09-30 10:23:13 +02002855 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002856 if (bss_list->count != 0 &&
2857 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002858 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2859 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 return -EOPNOTSUPP;
2861 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002862 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002863 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002864 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002865 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002866 if (err)
2867 break;
2868 }
2869 return err;
2870}
2871
Hante Meulemanb0a79082015-12-10 13:43:07 +01002872static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2873 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002874{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002875 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002876 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002877 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002879 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002880 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 u8 *buf = NULL;
2882 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002883 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002884 u16 notify_capability;
2885 u16 notify_interval;
2886 u8 *notify_ie;
2887 size_t notify_ielen;
2888 s32 notify_signal;
2889
Arend van Sprield96b8012012-12-05 15:26:02 +01002890 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891
2892 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2893 if (buf == NULL) {
2894 err = -ENOMEM;
2895 goto CleanUp;
2896 }
2897
2898 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2899
Arend van Sprielac24be62012-10-22 10:36:23 -07002900 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2901 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002902 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002903 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002904 goto CleanUp;
2905 }
2906
Roland Vossend34bf642011-10-18 14:03:01 +02002907 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002908
Franky Lin83cf17a2013-04-11 13:28:50 +02002909 ch.chspec = le16_to_cpu(bi->chanspec);
2910 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002911
Franky Lin83cf17a2013-04-11 13:28:50 +02002912 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002913 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002914 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002915 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002916
Rafał Miłecki4712d882016-05-20 13:38:57 +02002917 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002918 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002919 notify_channel = ieee80211_get_channel(wiphy, freq);
2920
Arend van Spriel5b435de2011-10-05 13:19:03 +02002921 notify_capability = le16_to_cpu(bi->capability);
2922 notify_interval = le16_to_cpu(bi->beacon_period);
2923 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2924 notify_ielen = le32_to_cpu(bi->ie_length);
2925 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2926
Rafał Miłecki4712d882016-05-20 13:38:57 +02002927 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002928 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2929 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2930 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002931
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002932 bss = cfg80211_inform_bss(wiphy, notify_channel,
2933 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2934 notify_capability, notify_interval,
2935 notify_ie, notify_ielen, notify_signal,
2936 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002937
Franky Line78946e2011-11-10 20:30:34 +01002938 if (!bss) {
2939 err = -ENOMEM;
2940 goto CleanUp;
2941 }
2942
Johannes Berg5b112d32013-02-01 01:49:58 +01002943 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002944
Arend van Spriel5b435de2011-10-05 13:19:03 +02002945CleanUp:
2946
2947 kfree(buf);
2948
Arend van Sprield96b8012012-12-05 15:26:02 +01002949 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002950
2951 return err;
2952}
2953
Hante Meuleman89286dc2013-02-08 15:53:46 +01002954static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2955 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002956{
Roland Vossend34bf642011-10-18 14:03:01 +02002957 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002958 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002959 u16 beacon_interval;
2960 u8 dtim_period;
2961 size_t ie_len;
2962 u8 *ie;
2963 s32 err = 0;
2964
Arend van Sprield96b8012012-12-05 15:26:02 +01002965 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002966 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002967 return err;
2968
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002969 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002970 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002971 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002972 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002973 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974 goto update_bss_info_out;
2975 }
2976
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002977 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2978 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002979 if (err)
2980 goto update_bss_info_out;
2981
2982 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2983 ie_len = le32_to_cpu(bi->ie_length);
2984 beacon_interval = le16_to_cpu(bi->beacon_period);
2985
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002986 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002987 if (tim)
2988 dtim_period = tim->data[1];
2989 else {
2990 /*
2991 * active scan was done so we could not get dtim
2992 * information out of probe response.
2993 * so we speficially query dtim information to dongle.
2994 */
2995 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002996 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002998 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002999 goto update_bss_info_out;
3000 }
3001 dtim_period = (u8)var;
3002 }
3003
Arend van Spriel5b435de2011-10-05 13:19:03 +02003004update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003005 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003006 return err;
3007}
3008
Hante Meuleman18e2f612013-02-08 15:53:49 +01003009void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003010{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003011 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003012
Arend van Sprielc1179032012-10-22 13:55:33 -07003013 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003014 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003015 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003016 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003017 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003018 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3019 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003020}
3021
Hante Meulemane756af52012-09-11 21:18:52 +02003022static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3023{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003024 struct brcmf_cfg80211_info *cfg =
3025 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003026 escan_timeout_work);
3027
Hante Meulemanef8596e2014-09-30 10:23:13 +02003028 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003029 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003030}
3031
3032static void brcmf_escan_timeout(unsigned long data)
3033{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003034 struct brcmf_cfg80211_info *cfg =
3035 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003036
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003037 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003038 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003039 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003040 }
3041}
3042
3043static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003044brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3045 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003046 struct brcmf_bss_info_le *bss_info_le)
3047{
Franky Lin83cf17a2013-04-11 13:28:50 +02003048 struct brcmu_chan ch_bss, ch_bss_info_le;
3049
3050 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3051 cfg->d11inf.decchspec(&ch_bss);
3052 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3053 cfg->d11inf.decchspec(&ch_bss_info_le);
3054
Hante Meulemane756af52012-09-11 21:18:52 +02003055 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003056 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003057 bss_info_le->SSID_len == bss->SSID_len &&
3058 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003059 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3060 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003061 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3062 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3063
Hante Meulemane756af52012-09-11 21:18:52 +02003064 /* preserve max RSSI if the measurements are
3065 * both on-channel or both off-channel
3066 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003067 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003068 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003069 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3070 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003071 /* preserve the on-channel rssi measurement
3072 * if the new measurement is off channel
3073 */
3074 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003075 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003076 }
3077 return 1;
3078 }
3079 return 0;
3080}
3081
3082static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003083brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003084 const struct brcmf_event_msg *e, void *data)
3085{
Arend van Spriel19937322012-11-05 16:22:32 -08003086 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003087 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003088 struct brcmf_escan_result_le *escan_result_le;
3089 struct brcmf_bss_info_le *bss_info_le;
3090 struct brcmf_bss_info_le *bss = NULL;
3091 u32 bi_length;
3092 struct brcmf_scan_results *list;
3093 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003094 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003095
Arend van Spriel5c36b992012-11-14 18:46:05 -08003096 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003097
Hans de Goedeb9472a22017-03-08 14:50:17 +01003098 if (status == BRCMF_E_STATUS_ABORT)
3099 goto exit;
3100
Arend van Spriela0f472a2013-04-05 10:57:49 +02003101 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003102 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003103 return -EPERM;
3104 }
3105
3106 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003107 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003108 escan_result_le = (struct brcmf_escan_result_le *) data;
3109 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003110 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003111 goto exit;
3112 }
Hante Meulemane756af52012-09-11 21:18:52 +02003113 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 brcmf_err("Invalid bss_count %d: ignoring\n",
3115 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003116 goto exit;
3117 }
3118 bss_info_le = &escan_result_le->bss_info_le;
3119
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003120 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3121 goto exit;
3122
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003123 if (!cfg->internal_escan && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003124 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3125 goto exit;
3126 }
3127
Hante Meulemane756af52012-09-11 21:18:52 +02003128 bi_length = le32_to_cpu(bss_info_le->length);
3129 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3130 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003131 brcmf_err("Invalid bss_info length %d: ignoring\n",
3132 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003133 goto exit;
3134 }
3135
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003136 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003137 BIT(NL80211_IFTYPE_ADHOC))) {
3138 if (le16_to_cpu(bss_info_le->capability) &
3139 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003140 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003141 goto exit;
3142 }
3143 }
3144
3145 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003146 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003147 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003148 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003149 goto exit;
3150 }
3151
3152 for (i = 0; i < list->count; i++) {
3153 bss = bss ? (struct brcmf_bss_info_le *)
3154 ((unsigned char *)bss +
3155 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003156 if (brcmf_compare_update_same_bss(cfg, bss,
3157 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003158 goto exit;
3159 }
Hante Meulemand5367332016-02-17 11:26:51 +01003160 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3161 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003162 list->version = le32_to_cpu(bss_info_le->version);
3163 list->buflen += bi_length;
3164 list->count++;
3165 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003166 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003167 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3168 goto exit;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003169 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003170 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003171 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003172 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003173 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003174 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3175 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003176 }
3177exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003178 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003179}
3180
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003181static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003182{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003183 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3184 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003185 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3186 /* Init scan_timeout timer */
3187 init_timer(&cfg->escan_timeout);
3188 cfg->escan_timeout.data = (unsigned long) cfg;
3189 cfg->escan_timeout.function = brcmf_escan_timeout;
3190 INIT_WORK(&cfg->escan_timeout_work,
3191 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003192}
3193
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003194static struct cfg80211_scan_request *
3195brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3196 struct cfg80211_scan_request *req;
3197 size_t req_size;
3198
3199 req_size = sizeof(*req) +
3200 n_netinfo * sizeof(req->channels[0]) +
3201 n_netinfo * sizeof(*req->ssids);
3202
3203 req = kzalloc(req_size, GFP_KERNEL);
3204 if (req) {
3205 req->wiphy = wiphy;
3206 req->ssids = (void *)(&req->channels[0]) +
3207 n_netinfo * sizeof(req->channels[0]);
3208 }
3209 return req;
3210}
3211
3212static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3213 u8 *ssid, u8 ssid_len, u8 channel)
3214{
3215 struct ieee80211_channel *chan;
3216 enum nl80211_band band;
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003217 int freq, i;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003218
3219 if (channel <= CH_MAX_2G_CHANNEL)
3220 band = NL80211_BAND_2GHZ;
3221 else
3222 band = NL80211_BAND_5GHZ;
3223
3224 freq = ieee80211_channel_to_frequency(channel, band);
3225 if (!freq)
3226 return -EINVAL;
3227
3228 chan = ieee80211_get_channel(req->wiphy, freq);
3229 if (!chan)
3230 return -EINVAL;
3231
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003232 for (i = 0; i < req->n_channels; i++) {
3233 if (req->channels[i] == chan)
3234 break;
3235 }
3236 if (i == req->n_channels)
3237 req->channels[req->n_channels++] = chan;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003238
Arend Van Spriel6ea51fc2017-04-06 13:14:42 +01003239 for (i = 0; i < req->n_ssids; i++) {
3240 if (req->ssids[i].ssid_len == ssid_len &&
3241 !memcmp(req->ssids[i].ssid, ssid, ssid_len))
3242 break;
3243 }
3244 if (i == req->n_ssids) {
3245 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3246 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3247 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003248 return 0;
3249}
3250
3251static int brcmf_start_internal_escan(struct brcmf_if *ifp,
3252 struct cfg80211_scan_request *request)
3253{
3254 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3255 int err;
3256
3257 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3258 /* Abort any on-going scan */
3259 brcmf_abort_scanning(cfg);
3260 }
3261
3262 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3263 cfg->escan_info.run = brcmf_run_escan;
3264 err = brcmf_do_escan(ifp, request);
3265 if (err) {
3266 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3267 return err;
3268 }
3269 cfg->internal_escan = true;
3270 return 0;
3271}
3272
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003273static struct brcmf_pno_net_info_le *
3274brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3275{
3276 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3277 struct brcmf_pno_net_info_le *netinfo;
3278
3279 switch (pfn_v1->version) {
3280 default:
3281 WARN_ON(1);
3282 /* fall-thru */
3283 case cpu_to_le32(1):
3284 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3285 break;
3286 case cpu_to_le32(2):
3287 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3288 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3289 break;
3290 }
3291
3292 return netinfo;
3293}
3294
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003295/* PFN result doesn't have all the info which are required by the supplicant
3296 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3297 * via wl_inform_single_bss in the required format. Escan does require the
3298 * scan request in the form of cfg80211_scan_request. For timebeing, create
3299 * cfg80211_scan_request one out of the received PNO event.
3300 */
3301static s32
3302brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3303 const struct brcmf_event_msg *e, void *data)
3304{
3305 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3306 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3307 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003308 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003309 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003310 struct brcmf_pno_scanresults_le *pfn_result;
3311 u32 result_count;
3312 u32 status;
Arend Van Spriel4835f372017-04-06 13:14:40 +01003313 u32 datalen;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003314
3315 brcmf_dbg(SCAN, "Enter\n");
3316
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003317 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3318 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3319 return 0;
3320 }
3321
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003322 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3323 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3324 return 0;
3325 }
3326
3327 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3328 result_count = le32_to_cpu(pfn_result->count);
3329 status = le32_to_cpu(pfn_result->status);
3330
3331 /* PFN event is limited to fit 512 bytes so we may get
3332 * multiple NET_FOUND events. For now place a warning here.
3333 */
3334 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3335 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003336 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003337 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3338 goto out_err;
3339 }
Arend Van Spriel4835f372017-04-06 13:14:40 +01003340
3341 netinfo_start = brcmf_get_netinfo_array(pfn_result);
3342 datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
3343 if (datalen < result_count * sizeof(*netinfo)) {
3344 brcmf_err("insufficient event data\n");
3345 goto out_err;
3346 }
3347
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003348 request = brcmf_alloc_internal_escan_request(wiphy,
3349 result_count);
3350 if (!request) {
3351 err = -ENOMEM;
3352 goto out_err;
3353 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003354
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003355 for (i = 0; i < result_count; i++) {
3356 netinfo = &netinfo_start[i];
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003357
Arend Van Spriel4835f372017-04-06 13:14:40 +01003358 if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
3359 netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003360 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3361 netinfo->SSID, netinfo->channel);
3362 err = brcmf_internal_escan_add_info(request,
3363 netinfo->SSID,
3364 netinfo->SSID_len,
3365 netinfo->channel);
3366 if (err)
3367 goto out_err;
3368 }
3369
3370 err = brcmf_start_internal_escan(ifp, request);
3371 if (!err)
3372 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003373
3374out_err:
Arend Van Sprielb34939b2017-04-28 13:40:28 +01003375 cfg80211_sched_scan_stopped(wiphy, 0);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003376free_req:
3377 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003378 return err;
3379}
3380
3381static int
3382brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3383 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003384 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003385{
3386 struct brcmf_if *ifp = netdev_priv(ndev);
3387 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003388
3389 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003390 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003391
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003392 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3393 brcmf_err("Scanning suppressed: status (%lu)\n",
3394 cfg->scan_status);
3395 return -EAGAIN;
3396 }
3397
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003398 if (req->n_match_sets <= 0) {
3399 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3400 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003401 return -EINVAL;
3402 }
3403
Arend Van Spriel3e486112016-11-23 10:25:27 +00003404 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003405}
3406
3407static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003408 struct net_device *ndev, u64 reqid)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003409{
3410 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003411 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003412
3413 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielac551362016-11-23 10:25:22 +00003414 brcmf_pno_clean(ifp);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003415 if (cfg->internal_escan)
Arend Van Sprielac551362016-11-23 10:25:22 +00003416 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003417 return 0;
3418}
3419
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003420static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003421{
3422 if (ms < 1000 / HZ) {
3423 cond_resched();
3424 mdelay(ms);
3425 } else {
3426 msleep(ms);
3427 }
3428}
3429
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003430static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3431 u8 *pattern, u32 patternsize, u8 *mask,
3432 u32 packet_offset)
3433{
3434 struct brcmf_fil_wowl_pattern_le *filter;
3435 u32 masksize;
3436 u32 patternoffset;
3437 u8 *buf;
3438 u32 bufsize;
3439 s32 ret;
3440
3441 masksize = (patternsize + 7) / 8;
3442 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3443
3444 bufsize = sizeof(*filter) + patternsize + masksize;
3445 buf = kzalloc(bufsize, GFP_KERNEL);
3446 if (!buf)
3447 return -ENOMEM;
3448 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3449
3450 memcpy(filter->cmd, cmd, 4);
3451 filter->masksize = cpu_to_le32(masksize);
3452 filter->offset = cpu_to_le32(packet_offset);
3453 filter->patternoffset = cpu_to_le32(patternoffset);
3454 filter->patternsize = cpu_to_le32(patternsize);
3455 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3456
3457 if ((mask) && (masksize))
3458 memcpy(buf + sizeof(*filter), mask, masksize);
3459 if ((pattern) && (patternsize))
3460 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3461
3462 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3463
3464 kfree(buf);
3465 return ret;
3466}
3467
Hante Meuleman3021ad92016-01-05 11:05:45 +01003468static s32
3469brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3470 void *data)
3471{
3472 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3473 struct brcmf_pno_scanresults_le *pfn_result;
3474 struct brcmf_pno_net_info_le *netinfo;
3475
3476 brcmf_dbg(SCAN, "Enter\n");
3477
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003478 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3479 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3480 return 0;
3481 }
3482
Hante Meuleman3021ad92016-01-05 11:05:45 +01003483 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3484
3485 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3486 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3487 return 0;
3488 }
3489
3490 if (le32_to_cpu(pfn_result->count) < 1) {
3491 brcmf_err("Invalid result count, expected 1 (%d)\n",
3492 le32_to_cpu(pfn_result->count));
3493 return -EINVAL;
3494 }
3495
Arend Van Sprield29afe92017-01-27 12:27:46 +00003496 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003497 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3498 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3499 cfg->wowl.nd->n_channels = 1;
3500 cfg->wowl.nd->channels[0] =
3501 ieee80211_channel_to_frequency(netinfo->channel,
3502 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3503 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3504 cfg->wowl.nd_info->n_matches = 1;
3505 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3506
3507 /* Inform (the resume task) that the net detect information was recvd */
3508 cfg->wowl.nd_data_completed = true;
3509 wake_up(&cfg->wowl.nd_data_wait);
3510
3511 return 0;
3512}
3513
Hante Meulemanaeb64222015-10-29 20:33:19 +01003514#ifdef CONFIG_PM
3515
3516static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3517{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003518 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003519 struct brcmf_wowl_wakeind_le wake_ind_le;
3520 struct cfg80211_wowlan_wakeup wakeup_data;
3521 struct cfg80211_wowlan_wakeup *wakeup;
3522 u32 wakeind;
3523 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003524 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003525
3526 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3527 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003528 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003529 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3530 return;
3531 }
3532
3533 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3534 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003535 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3536 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003537 wakeup = &wakeup_data;
3538 memset(&wakeup_data, 0, sizeof(wakeup_data));
3539 wakeup_data.pattern_idx = -1;
3540
3541 if (wakeind & BRCMF_WOWL_MAGIC) {
3542 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3543 wakeup_data.magic_pkt = true;
3544 }
3545 if (wakeind & BRCMF_WOWL_DIS) {
3546 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3547 wakeup_data.disconnect = true;
3548 }
3549 if (wakeind & BRCMF_WOWL_BCN) {
3550 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3551 wakeup_data.disconnect = true;
3552 }
3553 if (wakeind & BRCMF_WOWL_RETR) {
3554 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3555 wakeup_data.disconnect = true;
3556 }
3557 if (wakeind & BRCMF_WOWL_NET) {
3558 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3559 /* For now always map to pattern 0, no API to get
3560 * correct information available at the moment.
3561 */
3562 wakeup_data.pattern_idx = 0;
3563 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003564 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3565 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3566 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3567 cfg->wowl.nd_data_completed,
3568 BRCMF_ND_INFO_TIMEOUT);
3569 if (!timeout)
3570 brcmf_err("No result for wowl net detect\n");
3571 else
3572 wakeup_data.net_detect = cfg->wowl.nd_info;
3573 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003574 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3575 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3576 wakeup_data.gtk_rekey_failure = true;
3577 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003578 } else {
3579 wakeup = NULL;
3580 }
3581 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3582}
3583
3584#else
3585
3586static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3587{
3588}
3589
3590#endif /* CONFIG_PM */
3591
Arend van Spriel5b435de2011-10-05 13:19:03 +02003592static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3593{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003594 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3595 struct net_device *ndev = cfg_to_ndev(cfg);
3596 struct brcmf_if *ifp = netdev_priv(ndev);
3597
Arend van Sprield96b8012012-12-05 15:26:02 +01003598 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003599
Hante Meuleman3021ad92016-01-05 11:05:45 +01003600 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003601 brcmf_report_wowl_wakeind(wiphy, ifp);
3602 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3603 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003604 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3605 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003606 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003607 cfg->wowl.pre_pmmode);
3608 cfg->wowl.active = false;
3609 if (cfg->wowl.nd_enabled) {
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003610 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003611 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3612 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3613 brcmf_notify_sched_scan_results);
3614 cfg->wowl.nd_enabled = false;
3615 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003616 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003617 return 0;
3618}
3619
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003620static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3621 struct brcmf_if *ifp,
3622 struct cfg80211_wowlan *wowl)
3623{
3624 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003625 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003626 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003627
3628 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3629
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003630 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3631 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003632 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003633 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3634
3635 wowl_config = 0;
3636 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003637 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003638 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003639 wowl_config |= BRCMF_WOWL_MAGIC;
3640 if ((wowl->patterns) && (wowl->n_patterns)) {
3641 wowl_config |= BRCMF_WOWL_NET;
3642 for (i = 0; i < wowl->n_patterns; i++) {
3643 brcmf_config_wowl_pattern(ifp, "add",
3644 (u8 *)wowl->patterns[i].pattern,
3645 wowl->patterns[i].pattern_len,
3646 (u8 *)wowl->patterns[i].mask,
3647 wowl->patterns[i].pkt_offset);
3648 }
3649 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003650 if (wowl->nd_config) {
3651 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3652 wowl->nd_config);
3653 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3654
3655 cfg->wowl.nd_data_completed = false;
3656 cfg->wowl.nd_enabled = true;
3657 /* Now reroute the event for PFN to the wowl function. */
3658 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3659 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3660 brcmf_wowl_nd_results);
3661 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003662 if (wowl->gtk_rekey_failure)
3663 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003664 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3665 wowl_config |= BRCMF_WOWL_UNASSOC;
3666
Hante Meulemana7ed7822016-09-19 12:09:58 +01003667 memcpy(&wowl_wakeind, "clear", 6);
3668 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3669 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003670 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3671 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3672 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003673 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003674}
3675
Arend van Spriel5b435de2011-10-05 13:19:03 +02003676static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003677 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003678{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003679 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3680 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003681 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003682 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003683
Arend van Sprield96b8012012-12-05 15:26:02 +01003684 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003685
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003686 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003687 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003688 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003689 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003690 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003691
Hante Meuleman3021ad92016-01-05 11:05:45 +01003692 /* Stop scheduled scan */
3693 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
Arend Van Spriel3a3ecf12017-04-21 13:05:02 +01003694 brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003695
Arend van Spriel7d641072012-10-22 13:55:39 -07003696 /* end any scanning */
3697 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003698 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003699
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003700 if (wowl == NULL) {
3701 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3702 list_for_each_entry(vif, &cfg->vif_list, list) {
3703 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3704 continue;
3705 /* While going to suspend if associated with AP
3706 * disassociate from AP to save power while system is
3707 * in suspended state
3708 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003709 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003710 /* Make sure WPA_Supplicant receives all the event
3711 * generated due to DISASSOC call to the fw to keep
3712 * the state fw and WPA_Supplicant state consistent
3713 */
3714 brcmf_delay(500);
3715 }
3716 /* Configure MPC */
3717 brcmf_set_mpc(ifp, 1);
3718
3719 } else {
3720 /* Configure WOWL paramaters */
3721 brcmf_configure_wowl(cfg, ifp, wowl);
3722 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003723
Arend van Spriel7d641072012-10-22 13:55:39 -07003724exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003725 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003726 /* clear any scanning activity */
3727 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003728 return 0;
3729}
3730
3731static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003732brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003733{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003734 struct brcmf_pmk_list_le *pmk_list;
3735 int i;
3736 u32 npmk;
3737 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003738
Hante Meuleman6c404f32015-12-10 13:43:03 +01003739 pmk_list = &cfg->pmk_list;
3740 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003741
Hante Meuleman6c404f32015-12-10 13:43:03 +01003742 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3743 for (i = 0; i < npmk; i++)
3744 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003745
Hante Meuleman6c404f32015-12-10 13:43:03 +01003746 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3747 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003748
3749 return err;
3750}
3751
3752static s32
3753brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3754 struct cfg80211_pmksa *pmksa)
3755{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003756 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003757 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003758 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3759 s32 err;
3760 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003761
Arend van Sprield96b8012012-12-05 15:26:02 +01003762 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003763 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764 return -EIO;
3765
Hante Meuleman6c404f32015-12-10 13:43:03 +01003766 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3767 for (i = 0; i < npmk; i++)
3768 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003770 if (i < BRCMF_MAXPMKID) {
3771 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3772 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3773 if (i == npmk) {
3774 npmk++;
3775 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003776 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003777 } else {
3778 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3779 return -EINVAL;
3780 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003781
Hante Meuleman6c404f32015-12-10 13:43:03 +01003782 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3783 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3784 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3785 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3786 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003787
Hante Meuleman6c404f32015-12-10 13:43:03 +01003788 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003789
Arend van Sprield96b8012012-12-05 15:26:02 +01003790 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003791 return err;
3792}
3793
3794static s32
3795brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003796 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003797{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003798 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003799 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003800 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3801 s32 err;
3802 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003803
Arend van Sprield96b8012012-12-05 15:26:02 +01003804 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003805 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003806 return -EIO;
3807
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003808 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003809
Hante Meuleman6c404f32015-12-10 13:43:03 +01003810 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3811 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003812 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003813 break;
3814
Hante Meuleman6c404f32015-12-10 13:43:03 +01003815 if ((npmk > 0) && (i < npmk)) {
3816 for (; i < (npmk - 1); i++) {
3817 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3818 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003819 WLAN_PMKID_LEN);
3820 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003821 memset(&pmk[i], 0, sizeof(*pmk));
3822 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3823 } else {
3824 brcmf_err("Cache entry not found\n");
3825 return -EINVAL;
3826 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003827
Hante Meuleman6c404f32015-12-10 13:43:03 +01003828 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829
Arend van Sprield96b8012012-12-05 15:26:02 +01003830 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003831 return err;
3832
3833}
3834
3835static s32
3836brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3837{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003838 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003839 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003840 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003841
Arend van Sprield96b8012012-12-05 15:26:02 +01003842 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003843 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003844 return -EIO;
3845
Hante Meuleman6c404f32015-12-10 13:43:03 +01003846 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3847 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003848
Arend van Sprield96b8012012-12-05 15:26:02 +01003849 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003850 return err;
3851
3852}
3853
Hante Meuleman1f170112013-02-06 18:40:38 +01003854static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003855{
3856 s32 err;
3857
3858 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003859 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003860 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003861 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003862 return err;
3863 }
3864 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003865 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003866 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003867 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003868 return err;
3869 }
3870 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003871 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003872 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003873 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003874 return err;
3875 }
3876
3877 return 0;
3878}
3879
3880static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3881{
3882 if (is_rsn_ie)
3883 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3884
3885 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3886}
3887
3888static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003889brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003890 const struct brcmf_vs_tlv *wpa_ie,
3891 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003892{
3893 u32 auth = 0; /* d11 open authentication */
3894 u16 count;
3895 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003896 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003897 u32 i;
3898 u32 wsec;
3899 u32 pval = 0;
3900 u32 gval = 0;
3901 u32 wpa_auth = 0;
3902 u32 offset;
3903 u8 *data;
3904 u16 rsn_cap;
3905 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003906 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003907
Arend van Sprield96b8012012-12-05 15:26:02 +01003908 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003909 if (wpa_ie == NULL)
3910 goto exit;
3911
3912 len = wpa_ie->len + TLV_HDR_LEN;
3913 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003914 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003915 if (!is_rsn_ie)
3916 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003917 else
3918 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003919
3920 /* check for multicast cipher suite */
3921 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3922 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003923 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003924 goto exit;
3925 }
3926
3927 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3928 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003929 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003930 goto exit;
3931 }
3932 offset += TLV_OUI_LEN;
3933
3934 /* pick up multicast cipher */
3935 switch (data[offset]) {
3936 case WPA_CIPHER_NONE:
3937 gval = 0;
3938 break;
3939 case WPA_CIPHER_WEP_40:
3940 case WPA_CIPHER_WEP_104:
3941 gval = WEP_ENABLED;
3942 break;
3943 case WPA_CIPHER_TKIP:
3944 gval = TKIP_ENABLED;
3945 break;
3946 case WPA_CIPHER_AES_CCM:
3947 gval = AES_ENABLED;
3948 break;
3949 default:
3950 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003951 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003952 goto exit;
3953 }
3954
3955 offset++;
3956 /* walk thru unicast cipher list and pick up what we recognize */
3957 count = data[offset] + (data[offset + 1] << 8);
3958 offset += WPA_IE_SUITE_COUNT_LEN;
3959 /* Check for unicast suite(s) */
3960 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3961 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003962 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003963 goto exit;
3964 }
3965 for (i = 0; i < count; i++) {
3966 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3967 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003968 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003969 goto exit;
3970 }
3971 offset += TLV_OUI_LEN;
3972 switch (data[offset]) {
3973 case WPA_CIPHER_NONE:
3974 break;
3975 case WPA_CIPHER_WEP_40:
3976 case WPA_CIPHER_WEP_104:
3977 pval |= WEP_ENABLED;
3978 break;
3979 case WPA_CIPHER_TKIP:
3980 pval |= TKIP_ENABLED;
3981 break;
3982 case WPA_CIPHER_AES_CCM:
3983 pval |= AES_ENABLED;
3984 break;
3985 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00003986 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003987 }
3988 offset++;
3989 }
3990 /* walk thru auth management suite list and pick up what we recognize */
3991 count = data[offset] + (data[offset + 1] << 8);
3992 offset += WPA_IE_SUITE_COUNT_LEN;
3993 /* Check for auth key management suite(s) */
3994 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3995 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003996 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003997 goto exit;
3998 }
3999 for (i = 0; i < count; i++) {
4000 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4001 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004002 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004003 goto exit;
4004 }
4005 offset += TLV_OUI_LEN;
4006 switch (data[offset]) {
4007 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004008 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004009 wpa_auth |= WPA_AUTH_NONE;
4010 break;
4011 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004012 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004013 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4014 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4015 break;
4016 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004017 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004018 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4019 (wpa_auth |= WPA_AUTH_PSK);
4020 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004021 case RSN_AKM_SHA256_PSK:
4022 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4023 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4024 break;
4025 case RSN_AKM_SHA256_1X:
4026 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4027 wpa_auth |= WPA2_AUTH_1X_SHA256;
4028 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004029 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004030 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004031 }
4032 offset++;
4033 }
4034
Hante Meuleman240d61a2016-02-17 11:27:10 +01004035 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004036 if (is_rsn_ie) {
4037 wme_bss_disable = 1;
4038 if ((offset + RSN_CAP_LEN) <= len) {
4039 rsn_cap = data[offset] + (data[offset + 1] << 8);
4040 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4041 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004042 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4043 brcmf_dbg(TRACE, "MFP Required\n");
4044 mfp = BRCMF_MFP_REQUIRED;
4045 /* Firmware only supports mfp required in
4046 * combination with WPA2_AUTH_PSK_SHA256 or
4047 * WPA2_AUTH_1X_SHA256.
4048 */
4049 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4050 WPA2_AUTH_1X_SHA256))) {
4051 err = -EINVAL;
4052 goto exit;
4053 }
4054 /* Firmware has requirement that WPA2_AUTH_PSK/
4055 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4056 * is to be included in the rsn ie.
4057 */
4058 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4059 wpa_auth |= WPA2_AUTH_PSK;
4060 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4061 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4062 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4063 brcmf_dbg(TRACE, "MFP Capable\n");
4064 mfp = BRCMF_MFP_CAPABLE;
4065 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004066 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004067 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004068 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004069 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004070 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004071 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004072 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004073 goto exit;
4074 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004075
4076 /* Skip PMKID cnt as it is know to be 0 for AP. */
4077 offset += RSN_PMKID_COUNT_LEN;
4078
4079 /* See if there is BIP wpa suite left for MFP */
4080 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4081 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4082 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4083 &data[offset],
4084 WPA_IE_MIN_OUI_LEN);
4085 if (err < 0) {
4086 brcmf_err("bip error %d\n", err);
4087 goto exit;
4088 }
4089 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004090 }
4091 /* FOR WPS , set SES_OW_ENABLED */
4092 wsec = (pval | gval | SES_OW_ENABLED);
4093
4094 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004095 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004096 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004097 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004098 goto exit;
4099 }
4100 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004101 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004102 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004103 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004104 goto exit;
4105 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004106 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4107 * will overwrite the values set by MFP
4108 */
4109 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4110 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4111 if (err < 0) {
4112 brcmf_err("mfp error %d\n", err);
4113 goto exit;
4114 }
4115 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004116 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004117 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004118 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004119 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004120 goto exit;
4121 }
4122
4123exit:
4124 return err;
4125}
4126
4127static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004128brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004129 struct parsed_vndr_ies *vndr_ies)
4130{
Hante Meuleman1a873342012-09-27 14:17:54 +02004131 struct brcmf_vs_tlv *vndrie;
4132 struct brcmf_tlv *ie;
4133 struct parsed_vndr_ie_info *parsed_info;
4134 s32 remaining_len;
4135
4136 remaining_len = (s32)vndr_ie_len;
4137 memset(vndr_ies, 0, sizeof(*vndr_ies));
4138
4139 ie = (struct brcmf_tlv *)vndr_ie_buf;
4140 while (ie) {
4141 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4142 goto next;
4143 vndrie = (struct brcmf_vs_tlv *)ie;
4144 /* len should be bigger than OUI length + one */
4145 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004146 brcmf_err("invalid vndr ie. length is too small %d\n",
4147 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004148 goto next;
4149 }
4150 /* if wpa or wme ie, do not add ie */
4151 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4152 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4153 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004154 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004155 goto next;
4156 }
4157
4158 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4159
4160 /* save vndr ie information */
4161 parsed_info->ie_ptr = (char *)vndrie;
4162 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4163 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4164
4165 vndr_ies->count++;
4166
Arend van Sprield96b8012012-12-05 15:26:02 +01004167 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4168 parsed_info->vndrie.oui[0],
4169 parsed_info->vndrie.oui[1],
4170 parsed_info->vndrie.oui[2],
4171 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004172
Arend van Spriel9f440b72013-02-08 15:53:36 +01004173 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004174 break;
4175next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004176 remaining_len -= (ie->len + TLV_HDR_LEN);
4177 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004178 ie = NULL;
4179 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004180 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4181 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004182 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004183 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004184}
4185
4186static u32
4187brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4188{
4189
Hante Meuleman1a873342012-09-27 14:17:54 +02004190 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4191 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4192
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304193 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004194
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304195 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004196
4197 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4198
4199 return ie_len + VNDR_IE_HDR_SIZE;
4200}
4201
Arend van Spriel1332e262012-11-05 16:22:18 -08004202s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4203 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004204{
Arend van Spriel1332e262012-11-05 16:22:18 -08004205 struct brcmf_if *ifp;
4206 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004207 s32 err = 0;
4208 u8 *iovar_ie_buf;
4209 u8 *curr_ie_buf;
4210 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004211 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004212 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004213 u32 del_add_ie_buf_len = 0;
4214 u32 total_ie_buf_len = 0;
4215 u32 parsed_ie_buf_len = 0;
4216 struct parsed_vndr_ies old_vndr_ies;
4217 struct parsed_vndr_ies new_vndr_ies;
4218 struct parsed_vndr_ie_info *vndrie_info;
4219 s32 i;
4220 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004221 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004222
Arend van Spriel1332e262012-11-05 16:22:18 -08004223 if (!vif)
4224 return -ENODEV;
4225 ifp = vif->ifp;
4226 saved_ie = &vif->saved_ie;
4227
Hante Meuleman37a869e2015-10-29 20:33:17 +01004228 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4229 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004230 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4231 if (!iovar_ie_buf)
4232 return -ENOMEM;
4233 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004234 switch (pktflag) {
4235 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4236 mgmt_ie_buf = saved_ie->probe_req_ie;
4237 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4238 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4239 break;
4240 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4241 mgmt_ie_buf = saved_ie->probe_res_ie;
4242 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4243 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4244 break;
4245 case BRCMF_VNDR_IE_BEACON_FLAG:
4246 mgmt_ie_buf = saved_ie->beacon_ie;
4247 mgmt_ie_len = &saved_ie->beacon_ie_len;
4248 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4249 break;
4250 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4251 mgmt_ie_buf = saved_ie->assoc_req_ie;
4252 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4253 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4254 break;
4255 default:
4256 err = -EPERM;
4257 brcmf_err("not suitable type\n");
4258 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004259 }
4260
4261 if (vndr_ie_len > mgmt_ie_buf_len) {
4262 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004263 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004264 goto exit;
4265 }
4266
4267 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4268 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4269 ptr = curr_ie_buf;
4270 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4271 for (i = 0; i < new_vndr_ies.count; i++) {
4272 vndrie_info = &new_vndr_ies.ie_info[i];
4273 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4274 vndrie_info->ie_len);
4275 parsed_ie_buf_len += vndrie_info->ie_len;
4276 }
4277 }
4278
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004279 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004280 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4281 (memcmp(mgmt_ie_buf, curr_ie_buf,
4282 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004283 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004284 goto exit;
4285 }
4286
4287 /* parse old vndr_ie */
4288 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4289
4290 /* make a command to delete old ie */
4291 for (i = 0; i < old_vndr_ies.count; i++) {
4292 vndrie_info = &old_vndr_ies.ie_info[i];
4293
Arend van Sprield96b8012012-12-05 15:26:02 +01004294 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4295 vndrie_info->vndrie.id,
4296 vndrie_info->vndrie.len,
4297 vndrie_info->vndrie.oui[0],
4298 vndrie_info->vndrie.oui[1],
4299 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004300
4301 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4302 vndrie_info->ie_ptr,
4303 vndrie_info->ie_len,
4304 "del");
4305 curr_ie_buf += del_add_ie_buf_len;
4306 total_ie_buf_len += del_add_ie_buf_len;
4307 }
4308 }
4309
4310 *mgmt_ie_len = 0;
4311 /* Add if there is any extra IE */
4312 if (mgmt_ie_buf && parsed_ie_buf_len) {
4313 ptr = mgmt_ie_buf;
4314
4315 remained_buf_len = mgmt_ie_buf_len;
4316
4317 /* make a command to add new ie */
4318 for (i = 0; i < new_vndr_ies.count; i++) {
4319 vndrie_info = &new_vndr_ies.ie_info[i];
4320
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004321 /* verify remained buf size before copy data */
4322 if (remained_buf_len < (vndrie_info->vndrie.len +
4323 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004324 brcmf_err("no space in mgmt_ie_buf: len left %d",
4325 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004326 break;
4327 }
4328 remained_buf_len -= (vndrie_info->ie_len +
4329 VNDR_IE_VSIE_OFFSET);
4330
Arend van Sprield96b8012012-12-05 15:26:02 +01004331 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4332 vndrie_info->vndrie.id,
4333 vndrie_info->vndrie.len,
4334 vndrie_info->vndrie.oui[0],
4335 vndrie_info->vndrie.oui[1],
4336 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004337
4338 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4339 vndrie_info->ie_ptr,
4340 vndrie_info->ie_len,
4341 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004342
4343 /* save the parsed IE in wl struct */
4344 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4345 vndrie_info->ie_len);
4346 *mgmt_ie_len += vndrie_info->ie_len;
4347
4348 curr_ie_buf += del_add_ie_buf_len;
4349 total_ie_buf_len += del_add_ie_buf_len;
4350 }
4351 }
4352 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004353 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004354 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004355 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004356 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004357 }
4358
4359exit:
4360 kfree(iovar_ie_buf);
4361 return err;
4362}
4363
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004364s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4365{
4366 s32 pktflags[] = {
4367 BRCMF_VNDR_IE_PRBREQ_FLAG,
4368 BRCMF_VNDR_IE_PRBRSP_FLAG,
4369 BRCMF_VNDR_IE_BEACON_FLAG
4370 };
4371 int i;
4372
4373 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4374 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4375
4376 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4377 return 0;
4378}
4379
Hante Meuleman1a873342012-09-27 14:17:54 +02004380static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004381brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4382 struct cfg80211_beacon_data *beacon)
4383{
4384 s32 err;
4385
4386 /* Set Beacon IEs to FW */
4387 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4388 beacon->tail, beacon->tail_len);
4389 if (err) {
4390 brcmf_err("Set Beacon IE Failed\n");
4391 return err;
4392 }
4393 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4394
4395 /* Set Probe Response IEs to FW */
4396 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4397 beacon->proberesp_ies,
4398 beacon->proberesp_ies_len);
4399 if (err)
4400 brcmf_err("Set Probe Resp IE Failed\n");
4401 else
4402 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4403
4404 return err;
4405}
4406
4407static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004408brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4409 struct cfg80211_ap_settings *settings)
4410{
4411 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004412 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004413 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004414 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004415 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004416 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004417 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004418 const struct brcmf_tlv *rsn_ie;
4419 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004420 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004421 enum nl80211_iftype dev_role;
4422 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004423 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004424 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004425 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004426 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004427
Arend van Spriel06c01582014-05-12 10:47:37 +02004428 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4429 settings->chandef.chan->hw_value,
4430 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004431 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004432 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4433 settings->ssid, settings->ssid_len, settings->auth_type,
4434 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004435 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004436 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004437
Arend van Spriel98027762014-12-21 12:43:53 +01004438 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004439 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4440 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004441 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004442 } else {
4443 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4444 settings->beacon.tail_len,
4445 WLAN_EID_COUNTRY);
4446 is_11d = country_ie ? 1 : 0;
4447 supports_11d = true;
4448 }
Arend van Spriel98027762014-12-21 12:43:53 +01004449
Hante Meuleman1a873342012-09-27 14:17:54 +02004450 memset(&ssid_le, 0, sizeof(ssid_le));
4451 if (settings->ssid == NULL || settings->ssid_len == 0) {
4452 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4453 ssid_ie = brcmf_parse_tlvs(
4454 (u8 *)&settings->beacon.head[ie_offset],
4455 settings->beacon.head_len - ie_offset,
4456 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004457 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004458 return -EINVAL;
4459
4460 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4461 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004462 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004463 } else {
4464 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4465 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4466 }
4467
Hante Meulemana44aa402014-12-03 21:05:33 +01004468 if (!mbss) {
4469 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004470 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004471 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004472
4473 /* find the RSN_IE */
4474 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4475 settings->beacon.tail_len, WLAN_EID_RSN);
4476
4477 /* find the WPA_IE */
4478 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4479 settings->beacon.tail_len);
4480
Hante Meuleman1a873342012-09-27 14:17:54 +02004481 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004482 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004483 if (wpa_ie != NULL) {
4484 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004485 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004486 if (err < 0)
4487 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004488 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004489 struct brcmf_vs_tlv *tmp_ie;
4490
4491 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4492
Hante Meuleman1a873342012-09-27 14:17:54 +02004493 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004494 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004495 if (err < 0)
4496 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004497 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004498 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004499 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004500 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004501 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004502
Rafał Miłecki8707e082016-05-27 21:07:19 +02004503 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004504 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004505 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004506 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4507 is_11d);
4508 if (err < 0) {
4509 brcmf_err("Regulatory Set Error, %d\n", err);
4510 goto exit;
4511 }
4512 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004513 if (settings->beacon_interval) {
4514 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4515 settings->beacon_interval);
4516 if (err < 0) {
4517 brcmf_err("Beacon Interval Set Error, %d\n",
4518 err);
4519 goto exit;
4520 }
4521 }
4522 if (settings->dtim_period) {
4523 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4524 settings->dtim_period);
4525 if (err < 0) {
4526 brcmf_err("DTIM Interval Set Error, %d\n", err);
4527 goto exit;
4528 }
4529 }
4530
Hante Meuleman8abffd82015-10-29 20:33:16 +01004531 if ((dev_role == NL80211_IFTYPE_AP) &&
4532 ((ifp->ifidx == 0) ||
4533 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004534 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4535 if (err < 0) {
4536 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4537 goto exit;
4538 }
4539 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4540 }
4541
4542 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004543 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004544 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004545 goto exit;
4546 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004547 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004548 /* Multiple-BSS should use same 11d configuration */
4549 err = -EINVAL;
4550 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004551 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004552
4553 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004554 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004555 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4556 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4557
Hante Meulemana0f07952013-02-08 15:53:47 +01004558 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4559 if (err < 0) {
4560 brcmf_err("setting AP mode failed %d\n", err);
4561 goto exit;
4562 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004563 if (!mbss) {
4564 /* Firmware 10.x requires setting channel after enabling
4565 * AP and before bringing interface up.
4566 */
4567 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4568 if (err < 0) {
4569 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4570 chanspec, err);
4571 goto exit;
4572 }
4573 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004574 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4575 if (err < 0) {
4576 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4577 goto exit;
4578 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004579 /* On DOWN the firmware removes the WEP keys, reconfigure
4580 * them if they were set.
4581 */
4582 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004583
4584 memset(&join_params, 0, sizeof(join_params));
4585 /* join parameters starts with ssid */
4586 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4587 /* create softap */
4588 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4589 &join_params, sizeof(join_params));
4590 if (err < 0) {
4591 brcmf_err("SET SSID error (%d)\n", err);
4592 goto exit;
4593 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004594
4595 if (settings->hidden_ssid) {
4596 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4597 if (err) {
4598 brcmf_err("closednet error (%d)\n", err);
4599 goto exit;
4600 }
4601 }
4602
Hante Meulemana0f07952013-02-08 15:53:47 +01004603 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004604 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4605 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4606 if (err < 0) {
4607 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4608 chanspec, err);
4609 goto exit;
4610 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004611 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4612 sizeof(ssid_le));
4613 if (err < 0) {
4614 brcmf_err("setting ssid failed %d\n", err);
4615 goto exit;
4616 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004617 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004618 bss_enable.enable = cpu_to_le32(1);
4619 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4620 sizeof(bss_enable));
4621 if (err < 0) {
4622 brcmf_err("bss_enable config failed %d\n", err);
4623 goto exit;
4624 }
4625
4626 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004627 } else {
4628 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004629 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004630
Wright Fengf25ba692016-11-18 09:59:52 +08004631 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004632 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004633 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004634
4635exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004636 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004637 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004638 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004639 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004640 return err;
4641}
4642
4643static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4644{
Arend van Sprielc1179032012-10-22 13:55:33 -07004645 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004646 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004647 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004648 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004649
Arend van Sprield96b8012012-12-05 15:26:02 +01004650 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004651
Hante Meuleman426d0a52013-02-08 15:53:53 +01004652 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004653 /* Due to most likely deauths outstanding we sleep */
4654 /* first to make sure they get processed by fw. */
4655 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004656
Hante Meulemana44aa402014-12-03 21:05:33 +01004657 if (ifp->vif->mbss) {
4658 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4659 return err;
4660 }
4661
Rafał Miłeckic940de12016-07-06 12:22:54 +02004662 /* First BSS doesn't get a full reset */
4663 if (ifp->bsscfgidx == 0)
4664 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4665
Hante Meuleman5c33a942013-04-02 21:06:18 +02004666 memset(&join_params, 0, sizeof(join_params));
4667 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4668 &join_params, sizeof(join_params));
4669 if (err < 0)
4670 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004671 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004672 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004673 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004674 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4675 if (err < 0)
4676 brcmf_err("setting AP mode failed %d\n", err);
4677 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4678 if (err < 0)
4679 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004680 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4681 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004682 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4683 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004684 /* Bring device back up so it can be used again */
4685 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4686 if (err < 0)
4687 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004688
4689 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004690 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004691 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004692 bss_enable.enable = cpu_to_le32(0);
4693 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4694 sizeof(bss_enable));
4695 if (err < 0)
4696 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004697 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004698 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004699 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004700 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004701 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004702
Hante Meuleman1a873342012-09-27 14:17:54 +02004703 return err;
4704}
4705
Hante Meulemana0f07952013-02-08 15:53:47 +01004706static s32
4707brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4708 struct cfg80211_beacon_data *info)
4709{
Hante Meulemana0f07952013-02-08 15:53:47 +01004710 struct brcmf_if *ifp = netdev_priv(ndev);
4711 s32 err;
4712
4713 brcmf_dbg(TRACE, "Enter\n");
4714
Hante Meulemana0f07952013-02-08 15:53:47 +01004715 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4716
4717 return err;
4718}
4719
Hante Meuleman1a873342012-09-27 14:17:54 +02004720static int
4721brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004722 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004723{
Hante Meulemana0f07952013-02-08 15:53:47 +01004724 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004725 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004726 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004727 s32 err;
4728
Jouni Malinen89c771e2014-10-10 20:52:40 +03004729 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004730 return -EFAULT;
4731
Jouni Malinen89c771e2014-10-10 20:52:40 +03004732 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004733
Hante Meulemana0f07952013-02-08 15:53:47 +01004734 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4735 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004736 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004737 return -EIO;
4738
Jouni Malinen89c771e2014-10-10 20:52:40 +03004739 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004740 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004741 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004742 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004743 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004744 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004745
Arend van Sprield96b8012012-12-05 15:26:02 +01004746 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004747 return err;
4748}
4749
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004750static int
4751brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4752 const u8 *mac, struct station_parameters *params)
4753{
4754 struct brcmf_if *ifp = netdev_priv(ndev);
4755 s32 err;
4756
4757 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4758 params->sta_flags_mask, params->sta_flags_set);
4759
4760 /* Ignore all 00 MAC */
4761 if (is_zero_ether_addr(mac))
4762 return 0;
4763
4764 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4765 return 0;
4766
4767 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4768 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4769 (void *)mac, ETH_ALEN);
4770 else
4771 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4772 (void *)mac, ETH_ALEN);
4773 if (err < 0)
4774 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4775
4776 return err;
4777}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004778
4779static void
4780brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4781 struct wireless_dev *wdev,
4782 u16 frame_type, bool reg)
4783{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004784 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004785 u16 mgmt_type;
4786
4787 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4788
4789 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004790 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004791 if (reg)
4792 vif->mgmt_rx_reg |= BIT(mgmt_type);
4793 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004794 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004795}
4796
4797
4798static int
4799brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004800 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004801{
4802 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004803 struct ieee80211_channel *chan = params->chan;
4804 const u8 *buf = params->buf;
4805 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004806 const struct ieee80211_mgmt *mgmt;
4807 struct brcmf_cfg80211_vif *vif;
4808 s32 err = 0;
4809 s32 ie_offset;
4810 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004811 struct brcmf_fil_action_frame_le *action_frame;
4812 struct brcmf_fil_af_params_le *af_params;
4813 bool ack;
4814 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004815 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004816
4817 brcmf_dbg(TRACE, "Enter\n");
4818
4819 *cookie = 0;
4820
4821 mgmt = (const struct ieee80211_mgmt *)buf;
4822
Hante Meulemana0f07952013-02-08 15:53:47 +01004823 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4824 brcmf_err("Driver only allows MGMT packet type\n");
4825 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004826 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004827
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004828 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4829
Hante Meulemana0f07952013-02-08 15:53:47 +01004830 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4831 /* Right now the only reason to get a probe response */
4832 /* is for p2p listen response or for p2p GO from */
4833 /* wpa_supplicant. Unfortunately the probe is send */
4834 /* on primary ndev, while dongle wants it on the p2p */
4835 /* vif. Since this is only reason for a probe */
4836 /* response to be sent, the vif is taken from cfg. */
4837 /* If ever desired to send proberesp for non p2p */
4838 /* response then data should be checked for */
4839 /* "DIRECT-". Note in future supplicant will take */
4840 /* dedicated p2p wdev to do this and then this 'hack'*/
4841 /* is not needed anymore. */
4842 ie_offset = DOT11_MGMT_HDR_LEN +
4843 DOT11_BCN_PRB_FIXED_LEN;
4844 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004845 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4846 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4847 err = brcmf_vif_set_mgmt_ie(vif,
4848 BRCMF_VNDR_IE_PRBRSP_FLAG,
4849 &buf[ie_offset],
4850 ie_len);
4851 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4852 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004853 } else if (ieee80211_is_action(mgmt->frame_control)) {
4854 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4855 if (af_params == NULL) {
4856 brcmf_err("unable to allocate frame\n");
4857 err = -ENOMEM;
4858 goto exit;
4859 }
4860 action_frame = &af_params->action_frame;
4861 /* Add the packet Id */
4862 action_frame->packet_id = cpu_to_le32(*cookie);
4863 /* Add BSSID */
4864 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4865 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4866 /* Add the length exepted for 802.11 header */
4867 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004868 /* Add the channel. Use the one specified as parameter if any or
4869 * the current one (got from the firmware) otherwise
4870 */
4871 if (chan)
4872 freq = chan->center_freq;
4873 else
4874 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4875 &freq);
4876 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004877 af_params->channel = cpu_to_le32(chan_nr);
4878
4879 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4880 le16_to_cpu(action_frame->len));
4881
4882 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004883 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004884
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004885 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004886 af_params);
4887
4888 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4889 GFP_KERNEL);
4890 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004891 } else {
4892 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004893 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004894 }
4895
Hante Meuleman18e2f612013-02-08 15:53:49 +01004896exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004897 return err;
4898}
4899
4900
4901static int
4902brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4903 struct wireless_dev *wdev,
4904 u64 cookie)
4905{
4906 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4907 struct brcmf_cfg80211_vif *vif;
4908 int err = 0;
4909
4910 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4911
4912 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4913 if (vif == NULL) {
4914 brcmf_err("No p2p device available for probe response\n");
4915 err = -ENODEV;
4916 goto exit;
4917 }
4918 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4919exit:
4920 return err;
4921}
4922
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004923static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4924 struct wireless_dev *wdev,
4925 struct cfg80211_chan_def *chandef)
4926{
4927 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4928 struct net_device *ndev = wdev->netdev;
4929 struct brcmf_if *ifp;
4930 struct brcmu_chan ch;
4931 enum nl80211_band band = 0;
4932 enum nl80211_chan_width width = 0;
4933 u32 chanspec;
4934 int freq, err;
4935
4936 if (!ndev)
4937 return -ENODEV;
4938 ifp = netdev_priv(ndev);
4939
4940 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4941 if (err) {
4942 brcmf_err("chanspec failed (%d)\n", err);
4943 return err;
4944 }
4945
4946 ch.chspec = chanspec;
4947 cfg->d11inf.decchspec(&ch);
4948
4949 switch (ch.band) {
4950 case BRCMU_CHAN_BAND_2G:
4951 band = NL80211_BAND_2GHZ;
4952 break;
4953 case BRCMU_CHAN_BAND_5G:
4954 band = NL80211_BAND_5GHZ;
4955 break;
4956 }
4957
4958 switch (ch.bw) {
4959 case BRCMU_CHAN_BW_80:
4960 width = NL80211_CHAN_WIDTH_80;
4961 break;
4962 case BRCMU_CHAN_BW_40:
4963 width = NL80211_CHAN_WIDTH_40;
4964 break;
4965 case BRCMU_CHAN_BW_20:
4966 width = NL80211_CHAN_WIDTH_20;
4967 break;
4968 case BRCMU_CHAN_BW_80P80:
4969 width = NL80211_CHAN_WIDTH_80P80;
4970 break;
4971 case BRCMU_CHAN_BW_160:
4972 width = NL80211_CHAN_WIDTH_160;
4973 break;
4974 }
4975
4976 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
4977 chandef->chan = ieee80211_get_channel(wiphy, freq);
4978 chandef->width = width;
4979 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
4980 chandef->center_freq2 = 0;
4981
4982 return 0;
4983}
4984
Piotr Haber61730d42013-04-23 12:53:12 +02004985static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4986 struct wireless_dev *wdev,
4987 enum nl80211_crit_proto_id proto,
4988 u16 duration)
4989{
4990 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4991 struct brcmf_cfg80211_vif *vif;
4992
4993 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4994
4995 /* only DHCP support for now */
4996 if (proto != NL80211_CRIT_PROTO_DHCP)
4997 return -EINVAL;
4998
4999 /* suppress and abort scanning */
5000 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5001 brcmf_abort_scanning(cfg);
5002
5003 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5004}
5005
5006static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5007 struct wireless_dev *wdev)
5008{
5009 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5010 struct brcmf_cfg80211_vif *vif;
5011
5012 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5013
5014 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5015 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5016}
5017
Hante Meuleman70b7d942014-07-30 13:20:07 +02005018static s32
5019brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5020 const struct brcmf_event_msg *e, void *data)
5021{
5022 switch (e->reason) {
5023 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5024 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5025 break;
5026 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5027 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5028 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5029 break;
5030 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5031 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5032 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5033 break;
5034 }
5035
5036 return 0;
5037}
5038
Arend van Spriel89c2f382013-08-10 12:27:25 +02005039static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5040{
5041 int ret;
5042
5043 switch (oper) {
5044 case NL80211_TDLS_DISCOVERY_REQ:
5045 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5046 break;
5047 case NL80211_TDLS_SETUP:
5048 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5049 break;
5050 case NL80211_TDLS_TEARDOWN:
5051 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5052 break;
5053 default:
5054 brcmf_err("unsupported operation: %d\n", oper);
5055 ret = -EOPNOTSUPP;
5056 }
5057 return ret;
5058}
5059
5060static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005061 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005062 enum nl80211_tdls_operation oper)
5063{
5064 struct brcmf_if *ifp;
5065 struct brcmf_tdls_iovar_le info;
5066 int ret = 0;
5067
5068 ret = brcmf_convert_nl80211_tdls_oper(oper);
5069 if (ret < 0)
5070 return ret;
5071
5072 ifp = netdev_priv(ndev);
5073 memset(&info, 0, sizeof(info));
5074 info.mode = (u8)ret;
5075 if (peer)
5076 memcpy(info.ea, peer, ETH_ALEN);
5077
5078 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5079 &info, sizeof(info));
5080 if (ret < 0)
5081 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5082
5083 return ret;
5084}
5085
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005086static int
5087brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5088 struct net_device *ndev,
5089 struct cfg80211_connect_params *sme,
5090 u32 changed)
5091{
5092 struct brcmf_if *ifp;
5093 int err;
5094
5095 if (!(changed & UPDATE_ASSOC_IES))
5096 return 0;
5097
5098 ifp = netdev_priv(ndev);
5099 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5100 sme->ie, sme->ie_len);
5101 if (err)
5102 brcmf_err("Set Assoc REQ IE Failed\n");
5103 else
5104 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5105
5106 return err;
5107}
5108
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005109#ifdef CONFIG_PM
5110static int
5111brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5112 struct cfg80211_gtk_rekey_data *gtk)
5113{
5114 struct brcmf_if *ifp = netdev_priv(ndev);
5115 struct brcmf_gtk_keyinfo_le gtk_le;
5116 int ret;
5117
5118 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5119
5120 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5121 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5122 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5123 sizeof(gtk_le.replay_counter));
5124
5125 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5126 sizeof(gtk_le));
5127 if (ret < 0)
5128 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5129
5130 return ret;
5131}
5132#endif
5133
5134static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005135 .add_virtual_intf = brcmf_cfg80211_add_iface,
5136 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005137 .change_virtual_intf = brcmf_cfg80211_change_iface,
5138 .scan = brcmf_cfg80211_scan,
5139 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5140 .join_ibss = brcmf_cfg80211_join_ibss,
5141 .leave_ibss = brcmf_cfg80211_leave_ibss,
5142 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005143 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005144 .set_tx_power = brcmf_cfg80211_set_tx_power,
5145 .get_tx_power = brcmf_cfg80211_get_tx_power,
5146 .add_key = brcmf_cfg80211_add_key,
5147 .del_key = brcmf_cfg80211_del_key,
5148 .get_key = brcmf_cfg80211_get_key,
5149 .set_default_key = brcmf_cfg80211_config_default_key,
5150 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5151 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005152 .connect = brcmf_cfg80211_connect,
5153 .disconnect = brcmf_cfg80211_disconnect,
5154 .suspend = brcmf_cfg80211_suspend,
5155 .resume = brcmf_cfg80211_resume,
5156 .set_pmksa = brcmf_cfg80211_set_pmksa,
5157 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005158 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005159 .start_ap = brcmf_cfg80211_start_ap,
5160 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005161 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005162 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005163 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005164 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5165 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005166 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5167 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5168 .remain_on_channel = brcmf_p2p_remain_on_channel,
5169 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005170 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005171 .start_p2p_device = brcmf_p2p_start_device,
5172 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005173 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5174 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005175 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005176 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005177};
5178
Arend van Spriel3eacf862012-10-22 13:55:30 -07005179struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005180 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005181{
Hante Meulemana44aa402014-12-03 21:05:33 +01005182 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005183 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005184 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005185
Arend van Spriel33a6b152013-02-08 15:53:39 +01005186 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005187 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005188 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5189 if (!vif)
5190 return ERR_PTR(-ENOMEM);
5191
5192 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005193 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005194
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005195 brcmf_init_prof(&vif->profile);
5196
Hante Meulemana44aa402014-12-03 21:05:33 +01005197 if (type == NL80211_IFTYPE_AP) {
5198 mbss = false;
5199 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5200 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5201 mbss = true;
5202 break;
5203 }
5204 }
5205 vif->mbss = mbss;
5206 }
5207
Arend van Spriel3eacf862012-10-22 13:55:30 -07005208 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005209 return vif;
5210}
5211
Arend van Spriel427dec52014-01-06 12:40:47 +01005212void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005213{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005214 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005215 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005216}
5217
Arend van Spriel9df4d542014-01-06 12:40:49 +01005218void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5219{
5220 struct brcmf_cfg80211_vif *vif;
5221 struct brcmf_if *ifp;
5222
5223 ifp = netdev_priv(ndev);
5224 vif = ifp->vif;
5225
Arend van Spriel95ef1232015-08-26 22:15:04 +02005226 if (vif)
5227 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005228 free_netdev(ndev);
5229}
5230
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005231static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005232{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005233 u32 event = e->event_code;
5234 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005235
5236 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005237 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005238 return true;
5239 }
5240
5241 return false;
5242}
5243
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005244static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005245{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005246 u32 event = e->event_code;
5247 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005248
Hante Meuleman68ca3952014-02-25 20:30:26 +01005249 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5250 (event == BRCMF_E_DISASSOC_IND) ||
5251 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005252 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005253 return true;
5254 }
5255 return false;
5256}
5257
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005258static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005259 const struct brcmf_event_msg *e)
5260{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005261 u32 event = e->event_code;
5262 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263
5264 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005265 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5266 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005267 return true;
5268 }
5269
5270 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005271 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005272 return true;
5273 }
5274
5275 return false;
5276}
5277
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005278static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005279{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005280 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005281
5282 kfree(conn_info->req_ie);
5283 conn_info->req_ie = NULL;
5284 conn_info->req_ie_len = 0;
5285 kfree(conn_info->resp_ie);
5286 conn_info->resp_ie = NULL;
5287 conn_info->resp_ie_len = 0;
5288}
5289
Hante Meuleman89286dc2013-02-08 15:53:46 +01005290static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5291 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005292{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005293 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005294 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005295 u32 req_len;
5296 u32 resp_len;
5297 s32 err = 0;
5298
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005299 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005300
Arend van Sprielac24be62012-10-22 10:36:23 -07005301 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5302 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005303 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005304 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005305 return err;
5306 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005307 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005308 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005309 req_len = le32_to_cpu(assoc_info->req_len);
5310 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005311 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005312 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005313 cfg->extra_buf,
5314 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005315 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005316 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005317 return err;
5318 }
5319 conn_info->req_ie_len = req_len;
5320 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005321 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005322 GFP_KERNEL);
5323 } else {
5324 conn_info->req_ie_len = 0;
5325 conn_info->req_ie = NULL;
5326 }
5327 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005328 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005329 cfg->extra_buf,
5330 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005331 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005332 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005333 return err;
5334 }
5335 conn_info->resp_ie_len = resp_len;
5336 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005337 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005338 GFP_KERNEL);
5339 } else {
5340 conn_info->resp_ie_len = 0;
5341 conn_info->resp_ie = NULL;
5342 }
Arend van Spriel16886732012-12-05 15:26:04 +01005343 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5344 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005345
5346 return err;
5347}
5348
5349static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005350brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005351 struct net_device *ndev,
5352 const struct brcmf_event_msg *e)
5353{
Arend van Sprielc1179032012-10-22 13:55:33 -07005354 struct brcmf_if *ifp = netdev_priv(ndev);
5355 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005356 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5357 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005358 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005359 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005360 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005361 struct brcmu_chan ch;
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005362 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 u32 freq;
5364 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005365 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005366
Arend van Sprield96b8012012-12-05 15:26:02 +01005367 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368
Hante Meuleman89286dc2013-02-08 15:53:46 +01005369 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005370 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005371 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005372
Franky Lina180b832012-10-10 11:13:09 -07005373 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5374 if (buf == NULL) {
5375 err = -ENOMEM;
5376 goto done;
5377 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378
Franky Lina180b832012-10-10 11:13:09 -07005379 /* data sent to dongle has to be little endian */
5380 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005381 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005382 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005383
5384 if (err)
5385 goto done;
5386
5387 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005388 ch.chspec = le16_to_cpu(bi->chanspec);
5389 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390
Franky Lin83cf17a2013-04-11 13:28:50 +02005391 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005392 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005393 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005394 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005395
Rafał Miłecki4712d882016-05-20 13:38:57 +02005396 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005397 notify_channel = ieee80211_get_channel(wiphy, freq);
5398
Franky Lina180b832012-10-10 11:13:09 -07005399done:
5400 kfree(buf);
Avraham Stern29ce6ec2017-04-26 10:58:49 +03005401
5402 roam_info.channel = notify_channel;
5403 roam_info.bssid = profile->bssid;
5404 roam_info.req_ie = conn_info->req_ie;
5405 roam_info.req_ie_len = conn_info->req_ie_len;
5406 roam_info.resp_ie = conn_info->resp_ie;
5407 roam_info.resp_ie_len = conn_info->resp_ie_len;
5408
5409 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005410 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005411
Arend van Sprielc1179032012-10-22 13:55:33 -07005412 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005413 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005414 return err;
5415}
5416
5417static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005418brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419 struct net_device *ndev, const struct brcmf_event_msg *e,
5420 bool completed)
5421{
Arend van Sprielc1179032012-10-22 13:55:33 -07005422 struct brcmf_if *ifp = netdev_priv(ndev);
5423 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005424 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005425
Arend van Sprield96b8012012-12-05 15:26:02 +01005426 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005427
Arend van Sprielc1179032012-10-22 13:55:33 -07005428 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5429 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005430 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005431 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005432 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005433 brcmf_update_bss_info(cfg, ifp);
5434 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5435 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005436 }
5437 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005438 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 conn_info->req_ie,
5440 conn_info->req_ie_len,
5441 conn_info->resp_ie,
5442 conn_info->resp_ie_len,
5443 completed ? WLAN_STATUS_SUCCESS :
5444 WLAN_STATUS_AUTH_TIMEOUT,
5445 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005446 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5447 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005448 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005449 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005450 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451}
5452
5453static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005454brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005455 struct net_device *ndev,
5456 const struct brcmf_event_msg *e, void *data)
5457{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005458 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005459 u32 event = e->event_code;
5460 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005461 struct station_info sinfo;
5462
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005463 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5464 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005465 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5466 ndev != cfg_to_ndev(cfg)) {
5467 brcmf_dbg(CONN, "AP mode link down\n");
5468 complete(&cfg->vif_disabled);
5469 return 0;
5470 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005471
Hante Meuleman1a873342012-09-27 14:17:54 +02005472 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005473 (reason == BRCMF_E_STATUS_SUCCESS)) {
5474 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005475 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005476 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005477 return -EINVAL;
5478 }
5479 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005480 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005481 generation++;
5482 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005483 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005484 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5485 (event == BRCMF_E_DEAUTH_IND) ||
5486 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005487 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005488 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005489 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005490}
5491
5492static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005493brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005494 const struct brcmf_event_msg *e, void *data)
5495{
Arend van Spriel19937322012-11-05 16:22:32 -08005496 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5497 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005498 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005499 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005500 s32 err = 0;
5501
Hante Meuleman8851cce2014-07-30 13:20:02 +02005502 if ((e->event_code == BRCMF_E_DEAUTH) ||
5503 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5504 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5505 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5506 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5507 }
5508
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005509 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005510 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005511 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005512 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005513 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005514 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005515 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005516 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005517 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005518 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5519 &ifp->vif->sme_state);
5520 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5521 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005522 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005523 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005524 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005525 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005526 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005527 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005528 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005529 brcmf_link_down(ifp->vif,
5530 brcmf_map_fw_linkdown_reason(e));
5531 brcmf_init_prof(ndev_to_prof(ndev));
5532 if (ndev != cfg_to_ndev(cfg))
5533 complete(&cfg->vif_disabled);
5534 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005535 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005536 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005537 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005538 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5539 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005540 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005541 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005542 }
5543
5544 return err;
5545}
5546
5547static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005548brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005549 const struct brcmf_event_msg *e, void *data)
5550{
Arend van Spriel19937322012-11-05 16:22:32 -08005551 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005552 u32 event = e->event_code;
5553 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005554
5555 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005556 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005557 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005558 else
Arend van Spriel19937322012-11-05 16:22:32 -08005559 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005560 }
5561
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005562 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005563}
5564
5565static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005566brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005567 const struct brcmf_event_msg *e, void *data)
5568{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005569 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005570 enum nl80211_key_type key_type;
5571
5572 if (flags & BRCMF_EVENT_MSG_GROUP)
5573 key_type = NL80211_KEYTYPE_GROUP;
5574 else
5575 key_type = NL80211_KEYTYPE_PAIRWISE;
5576
Arend van Spriel19937322012-11-05 16:22:32 -08005577 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005578 NULL, GFP_KERNEL);
5579
5580 return 0;
5581}
5582
Arend van Sprield3c0b632013-02-08 15:53:37 +01005583static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5584 const struct brcmf_event_msg *e, void *data)
5585{
5586 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5587 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5588 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5589 struct brcmf_cfg80211_vif *vif;
5590
Hante Meuleman37a869e2015-10-29 20:33:17 +01005591 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005592 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005593 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005594
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005595 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005596 event->action = ifevent->action;
5597 vif = event->vif;
5598
5599 switch (ifevent->action) {
5600 case BRCMF_E_IF_ADD:
5601 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005602 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005603 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005604 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005605 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005606
5607 ifp->vif = vif;
5608 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005609 if (ifp->ndev) {
5610 vif->wdev.netdev = ifp->ndev;
5611 ifp->ndev->ieee80211_ptr = &vif->wdev;
5612 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5613 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005614 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005615 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005616 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005617
5618 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005619 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005620 /* event may not be upon user request */
5621 if (brcmf_cfg80211_vif_event_armed(cfg))
5622 wake_up(&event->vif_wq);
5623 return 0;
5624
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005625 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005626 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005627 wake_up(&event->vif_wq);
5628 return 0;
5629
Arend van Sprield3c0b632013-02-08 15:53:37 +01005630 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005631 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005632 break;
5633 }
5634 return -EINVAL;
5635}
5636
Arend van Spriel5b435de2011-10-05 13:19:03 +02005637static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5638{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005639 conf->frag_threshold = (u32)-1;
5640 conf->rts_threshold = (u32)-1;
5641 conf->retry_short = (u32)-1;
5642 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005643}
5644
Arend van Spriel5c36b992012-11-14 18:46:05 -08005645static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005646{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005647 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5648 brcmf_notify_connect_status);
5649 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5650 brcmf_notify_connect_status);
5651 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5652 brcmf_notify_connect_status);
5653 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5654 brcmf_notify_connect_status);
5655 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5656 brcmf_notify_connect_status);
5657 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5658 brcmf_notify_connect_status);
5659 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5660 brcmf_notify_roaming_status);
5661 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5662 brcmf_notify_mic_status);
5663 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5664 brcmf_notify_connect_status);
5665 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5666 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005667 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5668 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005669 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005670 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005671 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5672 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005673 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5674 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005675 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5676 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005677 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5678 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005679}
5680
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005681static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005682{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005683 kfree(cfg->conf);
5684 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005685 kfree(cfg->extra_buf);
5686 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005687 kfree(cfg->wowl.nd);
5688 cfg->wowl.nd = NULL;
5689 kfree(cfg->wowl.nd_info);
5690 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005691 kfree(cfg->escan_info.escan_buf);
5692 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005693}
5694
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005695static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005696{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005697 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5698 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005699 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005700 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5701 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005702 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005703 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5704 if (!cfg->wowl.nd)
5705 goto init_priv_mem_out;
5706 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5707 sizeof(struct cfg80211_wowlan_nd_match *),
5708 GFP_KERNEL);
5709 if (!cfg->wowl.nd_info)
5710 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005711 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5712 if (!cfg->escan_info.escan_buf)
5713 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005714
5715 return 0;
5716
5717init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005718 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005719
5720 return -ENOMEM;
5721}
5722
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005723static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005724{
5725 s32 err = 0;
5726
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005727 cfg->scan_request = NULL;
5728 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005729 cfg->active_scan = true; /* we do active scan per default */
5730 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005731 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005732 if (err)
5733 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005734 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005735 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005736 brcmf_init_escan(cfg);
5737 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005738 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005739 return err;
5740}
5741
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005742static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005743{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005744 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005745 brcmf_abort_scanning(cfg);
5746 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005747}
5748
Arend van Sprield3c0b632013-02-08 15:53:37 +01005749static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5750{
5751 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005752 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005753}
5754
Hante Meuleman1119e232015-11-25 11:32:42 +01005755static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005756{
Hante Meuleman1119e232015-11-25 11:32:42 +01005757 s32 err;
5758 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005759 __le32 roamtrigger[2];
5760 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005761
Hante Meuleman1119e232015-11-25 11:32:42 +01005762 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005763 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005764 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5765 else
5766 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5767 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5768 if (err) {
5769 brcmf_err("bcn_timeout error (%d)\n", err);
5770 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005771 }
5772
Hante Meuleman1119e232015-11-25 11:32:42 +01005773 /* Enable/Disable built-in roaming to allow supplicant to take care of
5774 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005775 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005776 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005777 ifp->drvr->settings->roamoff ? "Off" : "On");
5778 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5779 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005780 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005781 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005782 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005783 }
5784
Arend van Sprielf588bc02011-10-12 20:51:22 +02005785 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5786 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005787 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005788 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005789 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005790 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005791 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005792 }
5793
Arend van Sprielf588bc02011-10-12 20:51:22 +02005794 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5795 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005796 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005797 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005798 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005799 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005800 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005801 }
5802
Hante Meuleman1119e232015-11-25 11:32:42 +01005803roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005804 return err;
5805}
5806
5807static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005808brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005809{
5810 s32 err = 0;
5811
Arend van Sprielac24be62012-10-22 10:36:23 -07005812 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005813 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005814 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005815 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005816 goto dongle_scantime_out;
5817 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005818 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005819 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005820 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005821 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005822 goto dongle_scantime_out;
5823 }
5824
Arend van Sprielac24be62012-10-22 10:36:23 -07005825 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005826 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005827 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005828 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005829 goto dongle_scantime_out;
5830 }
5831
5832dongle_scantime_out:
5833 return err;
5834}
5835
Arend van Sprielb48d8912014-07-12 08:49:41 +02005836static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5837 struct brcmu_chan *ch)
5838{
5839 u32 ht40_flag;
5840
5841 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5842 if (ch->sb == BRCMU_CHAN_SB_U) {
5843 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5844 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5845 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5846 } else {
5847 /* It should be one of
5848 * IEEE80211_CHAN_NO_HT40 or
5849 * IEEE80211_CHAN_NO_HT40PLUS
5850 */
5851 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5852 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5853 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5854 }
5855}
5856
5857static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5858 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005859{
5860 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005861 struct ieee80211_supported_band *band;
5862 struct ieee80211_channel *channel;
5863 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005864 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005865 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005866 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005867 u8 *pbuf;
5868 u32 i, j;
5869 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005870 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005871
5872 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5873
5874 if (pbuf == NULL)
5875 return -ENOMEM;
5876
5877 list = (struct brcmf_chanspec_list *)pbuf;
5878
5879 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5880 BRCMF_DCMD_MEDLEN);
5881 if (err) {
5882 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005883 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005884 }
5885
Arend van Sprielb48d8912014-07-12 08:49:41 +02005886 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005887 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005888 if (band)
5889 for (i = 0; i < band->n_channels; i++)
5890 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005891 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005892 if (band)
5893 for (i = 0; i < band->n_channels; i++)
5894 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005895
5896 total = le32_to_cpu(list->count);
5897 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005898 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5899 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005900
Franky Lin83cf17a2013-04-11 13:28:50 +02005901 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005902 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005903 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005904 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005905 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005906 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005907 continue;
5908 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005909 if (!band)
5910 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005911 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005912 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005913 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005914 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005915 ch.bw == BRCMU_CHAN_BW_80)
5916 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005917
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005918 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005919 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005920 if (band->channels[j].hw_value == ch.control_ch_num) {
5921 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02005922 break;
5923 }
5924 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005925 if (!channel) {
5926 /* It seems firmware supports some channel we never
5927 * considered. Something new in IEEE standard?
5928 */
5929 brcmf_err("Ignoring unexpected firmware channel %d\n",
5930 ch.control_ch_num);
5931 continue;
5932 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005933
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01005934 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
5935 continue;
5936
Arend van Sprielb48d8912014-07-12 08:49:41 +02005937 /* assuming the chanspecs order is HT20,
5938 * HT40 upper, HT40 lower, and VHT80.
5939 */
5940 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005941 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005942 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005943 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005944 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005945 /* enable the channel and disable other bandwidths
5946 * for now as mentioned order assure they are enabled
5947 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005948 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005949 channel->flags = IEEE80211_CHAN_NO_HT40 |
5950 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005951 ch.bw = BRCMU_CHAN_BW_20;
5952 cfg->d11inf.encchspec(&ch);
5953 chaninfo = ch.chspec;
5954 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5955 &chaninfo);
5956 if (!err) {
5957 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005958 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02005959 (IEEE80211_CHAN_RADAR |
5960 IEEE80211_CHAN_NO_IR);
5961 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005962 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02005963 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005964 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005965 }
5966 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005967
Arend van Sprielb48d8912014-07-12 08:49:41 +02005968fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005969 kfree(pbuf);
5970 return err;
5971}
5972
Arend van Sprielb48d8912014-07-12 08:49:41 +02005973static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005974{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005975 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5976 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005977 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005978 struct brcmf_chanspec_list *list;
5979 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005980 u32 val;
5981 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005982 struct brcmu_chan ch;
5983 u32 num_chan;
5984 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005985
5986 /* verify support for bw_cap command */
5987 val = WLC_BAND_5G;
5988 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5989
5990 if (!err) {
5991 /* only set 2G bandwidth using bw_cap command */
5992 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5993 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5994 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5995 sizeof(band_bwcap));
5996 } else {
5997 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5998 val = WLC_N_BW_40ALL;
5999 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6000 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006001
6002 if (!err) {
6003 /* update channel info in 2G band */
6004 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6005
6006 if (pbuf == NULL)
6007 return -ENOMEM;
6008
6009 ch.band = BRCMU_CHAN_BAND_2G;
6010 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006011 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006012 ch.chnum = 0;
6013 cfg->d11inf.encchspec(&ch);
6014
6015 /* pass encoded chanspec in query */
6016 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6017
6018 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6019 BRCMF_DCMD_MEDLEN);
6020 if (err) {
6021 brcmf_err("get chanspecs error (%d)\n", err);
6022 kfree(pbuf);
6023 return err;
6024 }
6025
Johannes Berg57fbcce2016-04-12 15:56:15 +02006026 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006027 list = (struct brcmf_chanspec_list *)pbuf;
6028 num_chan = le32_to_cpu(list->count);
6029 for (i = 0; i < num_chan; i++) {
6030 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6031 cfg->d11inf.decchspec(&ch);
6032 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6033 continue;
6034 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6035 continue;
6036 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006037 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006038 break;
6039 }
6040 if (WARN_ON(j == band->n_channels))
6041 continue;
6042
6043 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6044 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006045 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006046 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006047 return err;
6048}
6049
Arend van Spriel2375d972014-01-06 12:40:41 +01006050static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6051{
6052 u32 band, mimo_bwcap;
6053 int err;
6054
6055 band = WLC_BAND_2G;
6056 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6057 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006058 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006059 band = WLC_BAND_5G;
6060 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6061 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006062 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006063 return;
6064 }
6065 WARN_ON(1);
6066 return;
6067 }
6068 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6069 mimo_bwcap = 0;
6070 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6071 if (err)
6072 /* assume 20MHz if firmware does not give a clue */
6073 mimo_bwcap = WLC_N_BW_20ALL;
6074
6075 switch (mimo_bwcap) {
6076 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006077 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006078 /* fall-thru */
6079 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006080 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006081 /* fall-thru */
6082 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006083 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6084 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006085 break;
6086 default:
6087 brcmf_err("invalid mimo_bw_cap value\n");
6088 }
6089}
Hante Meulemand48200b2013-04-03 12:40:29 +02006090
Arend van Spriel18d6c532014-05-12 10:47:35 +02006091static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6092 u32 bw_cap[2], u32 nchain)
6093{
6094 band->ht_cap.ht_supported = true;
6095 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6096 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6097 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6098 }
6099 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6100 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6101 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6102 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6103 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6104 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6105}
6106
6107static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6108{
6109 u16 mcs_map;
6110 int i;
6111
6112 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6113 mcs_map = (mcs_map << 2) | supp;
6114
6115 return cpu_to_le16(mcs_map);
6116}
6117
6118static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006119 u32 bw_cap[2], u32 nchain, u32 txstreams,
6120 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006121{
6122 __le16 mcs_map;
6123
6124 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006125 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006126 return;
6127
6128 band->vht_cap.vht_supported = true;
6129 /* 80MHz is mandatory */
6130 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6131 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6132 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6133 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6134 }
6135 /* all support 256-QAM */
6136 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6137 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6138 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006139
6140 /* Beamforming support information */
6141 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6142 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6143 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6144 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6145 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6146 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6147 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6148 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6149
6150 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6151 band->vht_cap.cap |=
6152 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6153 band->vht_cap.cap |= ((txstreams - 1) <<
6154 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6155 band->vht_cap.cap |=
6156 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6157 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006158}
6159
Arend van Sprielb48d8912014-07-12 08:49:41 +02006160static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006161{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006162 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006163 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006164 u32 nmode = 0;
6165 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006166 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006167 u32 rxchain;
6168 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006169 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006170 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006171 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006172 u32 txstreams = 0;
6173 u32 txbf_bfe_cap = 0;
6174 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006175
Arend van Spriel18d6c532014-05-12 10:47:35 +02006176 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006177 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6178 if (err) {
6179 brcmf_err("nmode error (%d)\n", err);
6180 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006181 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006182 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006183 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006184 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6185 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006186
Daniel Kim4aca7a12014-02-25 20:30:36 +01006187 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6188 if (err) {
6189 brcmf_err("rxchain error (%d)\n", err);
6190 nchain = 1;
6191 } else {
6192 for (nchain = 0; rxchain; nchain++)
6193 rxchain = rxchain & (rxchain - 1);
6194 }
6195 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6196
Arend van Sprielb48d8912014-07-12 08:49:41 +02006197 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006198 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006199 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006200 return err;
6201 }
6202
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006203 if (vhtmode) {
6204 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6205 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6206 &txbf_bfe_cap);
6207 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6208 &txbf_bfr_cap);
6209 }
6210
Arend van Sprielb48d8912014-07-12 08:49:41 +02006211 wiphy = cfg_to_wiphy(cfg);
6212 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6213 band = wiphy->bands[i];
6214 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006215 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006216
Arend van Spriel18d6c532014-05-12 10:47:35 +02006217 if (nmode)
6218 brcmf_update_ht_cap(band, bw_cap, nchain);
6219 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006220 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6221 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006222 }
6223
Arend van Sprielb48d8912014-07-12 08:49:41 +02006224 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006225}
6226
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006227static const struct ieee80211_txrx_stypes
6228brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6229 [NL80211_IFTYPE_STATION] = {
6230 .tx = 0xffff,
6231 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6232 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6233 },
6234 [NL80211_IFTYPE_P2P_CLIENT] = {
6235 .tx = 0xffff,
6236 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6237 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6238 },
6239 [NL80211_IFTYPE_P2P_GO] = {
6240 .tx = 0xffff,
6241 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6242 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6243 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6244 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6245 BIT(IEEE80211_STYPE_AUTH >> 4) |
6246 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6247 BIT(IEEE80211_STYPE_ACTION >> 4)
6248 },
6249 [NL80211_IFTYPE_P2P_DEVICE] = {
6250 .tx = 0xffff,
6251 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6252 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6253 }
6254};
6255
Arend van Spriel0882dda2015-08-20 22:06:03 +02006256/**
6257 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6258 *
6259 * @wiphy: wiphy object.
6260 * @ifp: interface object needed for feat module api.
6261 *
6262 * The interface modes and combinations are determined dynamically here
6263 * based on firmware functionality.
6264 *
6265 * no p2p and no mbss:
6266 *
6267 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6268 *
6269 * no p2p and mbss:
6270 *
6271 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6272 * #AP <= 4, matching BI, channels = 1, 4 total
6273 *
6274 * p2p, no mchan, and mbss:
6275 *
6276 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6277 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6278 * #AP <= 4, matching BI, channels = 1, 4 total
6279 *
6280 * p2p, mchan, and mbss:
6281 *
6282 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6283 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6284 * #AP <= 4, matching BI, channels = 1, 4 total
6285 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006286static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6287{
6288 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006289 struct ieee80211_iface_limit *c0_limits = NULL;
6290 struct ieee80211_iface_limit *p2p_limits = NULL;
6291 struct ieee80211_iface_limit *mbss_limits = NULL;
6292 bool mbss, p2p;
6293 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006294
Arend van Spriel0882dda2015-08-20 22:06:03 +02006295 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6296 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6297
6298 n_combos = 1 + !!p2p + !!mbss;
6299 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006300 if (!combo)
6301 goto err;
6302
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006303 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6304 BIT(NL80211_IFTYPE_ADHOC) |
6305 BIT(NL80211_IFTYPE_AP);
6306
Arend van Spriel0882dda2015-08-20 22:06:03 +02006307 c = 0;
6308 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006309 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6310 if (!c0_limits)
6311 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006312 c0_limits[i].max = 1;
6313 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6314 if (p2p) {
6315 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6316 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006317 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6318 BIT(NL80211_IFTYPE_P2P_GO) |
6319 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006320 c0_limits[i].max = 1;
6321 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6322 c0_limits[i].max = 1;
6323 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6324 BIT(NL80211_IFTYPE_P2P_GO);
6325 } else {
6326 c0_limits[i].max = 1;
6327 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006328 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006329 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006330 combo[c].max_interfaces = i;
6331 combo[c].n_limits = i;
6332 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006333
Arend van Spriel0882dda2015-08-20 22:06:03 +02006334 if (p2p) {
6335 c++;
6336 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006337 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6338 if (!p2p_limits)
6339 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006340 p2p_limits[i].max = 1;
6341 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6342 p2p_limits[i].max = 1;
6343 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6344 p2p_limits[i].max = 1;
6345 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6346 p2p_limits[i].max = 1;
6347 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006348 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006349 combo[c].max_interfaces = i;
6350 combo[c].n_limits = i;
6351 combo[c].limits = p2p_limits;
6352 }
6353
6354 if (mbss) {
6355 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006356 i = 0;
6357 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6358 if (!mbss_limits)
6359 goto err;
6360 mbss_limits[i].max = 4;
6361 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006362 combo[c].beacon_int_infra_match = true;
6363 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006364 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006365 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006366 combo[c].limits = mbss_limits;
6367 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006368
Arend van Spriel0882dda2015-08-20 22:06:03 +02006369 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006370 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006371 return 0;
6372
6373err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006374 kfree(c0_limits);
6375 kfree(p2p_limits);
6376 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006377 kfree(combo);
6378 return -ENOMEM;
6379}
6380
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006381static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6382{
6383 /* scheduled scan settings */
Arend Van Sprielca986ad2017-04-21 13:05:00 +01006384 wiphy->max_sched_scan_reqs = 1;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006385 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6386 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6387 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend Van Sprielc6989fd2016-11-23 10:25:30 +00006388 wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006389}
6390
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006391#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006392static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006393 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006394 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6395 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6396 .pattern_min_len = 1,
6397 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006398};
6399#endif
6400
Hante Meuleman3021ad92016-01-05 11:05:45 +01006401static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006402{
6403#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006404 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006405 struct wiphy_wowlan_support *wowl;
6406
6407 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6408 GFP_KERNEL);
6409 if (!wowl) {
6410 brcmf_err("only support basic wowlan features\n");
6411 wiphy->wowlan = &brcmf_wowlan_support;
6412 return;
6413 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006414
6415 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006416 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006417 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6418 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006419 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006420 }
6421 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006422 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006423 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6424 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006425 }
6426
Arend Van Spriel0b570102017-01-27 12:27:47 +00006427 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006428#endif
6429}
6430
Arend van Sprielb48d8912014-07-12 08:49:41 +02006431static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006432{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006433 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006434 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006435 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006436 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006437 __le32 bandlist[3];
6438 u32 n_bands;
6439 int err, i;
6440
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006441 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6442 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006443 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006444
6445 err = brcmf_setup_ifmodes(wiphy, ifp);
6446 if (err)
6447 return err;
6448
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006449 for (i = 0, combo = wiphy->iface_combinations;
6450 i < wiphy->n_iface_combinations; i++, combo++) {
6451 max_interfaces = max(max_interfaces, combo->max_interfaces);
6452 }
6453
6454 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6455 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006456 u8 *addr = drvr->addresses[i].addr;
6457
6458 memcpy(addr, drvr->mac, ETH_ALEN);
6459 if (i) {
6460 addr[0] |= BIT(1);
6461 addr[ETH_ALEN - 1] ^= i;
6462 }
6463 }
6464 wiphy->addresses = drvr->addresses;
6465 wiphy->n_addresses = i;
6466
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006467 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006468 wiphy->cipher_suites = brcmf_cipher_suites;
6469 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6470 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6471 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006472 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6473 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6474 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6475
Arend Van Spriel0cc02362017-03-28 11:43:26 +01006476 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
6477 WIPHY_FLAG_PS_ON_BY_DEFAULT |
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006478 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006479 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6480 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6481 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006482 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006483 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6484 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6485 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006486 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6487 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006488
6489 /* vendor commands/events support */
6490 wiphy->vendor_commands = brcmf_vendor_cmds;
6491 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6492
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006493 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006494 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006495 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6496 sizeof(bandlist));
6497 if (err) {
6498 brcmf_err("could not obtain band info: err=%d\n", err);
6499 return err;
6500 }
6501 /* first entry in bandlist is number of bands */
6502 n_bands = le32_to_cpu(bandlist[0]);
6503 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6504 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6505 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6506 GFP_KERNEL);
6507 if (!band)
6508 return -ENOMEM;
6509
6510 band->channels = kmemdup(&__wl_2ghz_channels,
6511 sizeof(__wl_2ghz_channels),
6512 GFP_KERNEL);
6513 if (!band->channels) {
6514 kfree(band);
6515 return -ENOMEM;
6516 }
6517
6518 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006519 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006520 }
6521 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6522 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6523 GFP_KERNEL);
6524 if (!band)
6525 return -ENOMEM;
6526
6527 band->channels = kmemdup(&__wl_5ghz_channels,
6528 sizeof(__wl_5ghz_channels),
6529 GFP_KERNEL);
6530 if (!band->channels) {
6531 kfree(band);
6532 return -ENOMEM;
6533 }
6534
6535 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006536 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006537 }
6538 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006539
6540 wiphy_read_of_freq_limits(wiphy);
6541
Rafał Miłeckiab990632017-01-07 21:36:05 +01006542 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006543}
6544
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006545static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006546{
6547 struct net_device *ndev;
6548 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006549 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006550 s32 power_mode;
6551 s32 err = 0;
6552
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006553 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006554 return err;
6555
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006556 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006557 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006558 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006559
Hante Meuleman40a23292013-01-02 15:22:51 +01006560 /* make sure RF is ready for work */
6561 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6562
Hante Meuleman1678ba82015-12-10 13:43:00 +01006563 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006564
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006565 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006566 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006567 if (err)
6568 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006569 brcmf_dbg(INFO, "power save set to %s\n",
6570 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006571
Hante Meuleman1119e232015-11-25 11:32:42 +01006572 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006573 if (err)
6574 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006575 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006576 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006577 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006578 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006579
Franky Lin52f22fb2016-02-17 11:26:55 +01006580 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006581
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006582 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006583default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006584
6585 return err;
6586
6587}
6588
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006589static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006590{
Arend van Sprielc1179032012-10-22 13:55:33 -07006591 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006592
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006593 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006594}
6595
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006596static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006597{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006598 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006599
Arend van Spriel5b435de2011-10-05 13:19:03 +02006600 /*
6601 * While going down, if associated with AP disassociate
6602 * from AP to save power
6603 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006604 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006605 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006606
6607 /* Make sure WPA_Supplicant receives all the event
6608 generated due to DISASSOC call to the fw to keep
6609 the state fw and WPA_Supplicant state consistent
6610 */
6611 brcmf_delay(500);
6612 }
6613
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006614 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006615 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006616
Arend van Spriel5b435de2011-10-05 13:19:03 +02006617 return 0;
6618}
6619
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006620s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006621{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006622 struct brcmf_if *ifp = netdev_priv(ndev);
6623 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006624 s32 err = 0;
6625
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006626 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006627 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006628 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006629
6630 return err;
6631}
6632
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006633s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006634{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006635 struct brcmf_if *ifp = netdev_priv(ndev);
6636 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006637 s32 err = 0;
6638
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006639 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006640 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006641 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006642
6643 return err;
6644}
6645
Arend van Spriela7965fb2013-04-11 17:08:37 +02006646enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6647{
6648 struct wireless_dev *wdev = &ifp->vif->wdev;
6649
6650 return wdev->iftype;
6651}
6652
Hante Meulemanbfe81972014-10-28 14:56:16 +01006653bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6654 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006655{
6656 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006657
6658 list_for_each_entry(vif, &cfg->vif_list, list) {
6659 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006660 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006661 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006662 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006663}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006664
6665static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6666 u8 action)
6667{
6668 u8 evt_action;
6669
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006670 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006671 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006672 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006673 return evt_action == action;
6674}
6675
6676void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6677 struct brcmf_cfg80211_vif *vif)
6678{
6679 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6680
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006681 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006682 event->vif = vif;
6683 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006684 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006685}
6686
6687bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6688{
6689 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6690 bool armed;
6691
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006692 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006693 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006694 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006695
6696 return armed;
6697}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006698
6699int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6700 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006701{
6702 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6703
6704 return wait_event_timeout(event->vif_wq,
6705 vif_event_equals(event, action), timeout);
6706}
6707
Hante Meuleman73345fd2016-02-17 11:26:53 +01006708static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6709 struct brcmf_fil_country_le *ccreq)
6710{
Hante Meuleman4d792892016-02-17 11:27:07 +01006711 struct brcmfmac_pd_cc *country_codes;
6712 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006713 s32 found_index;
6714 int i;
6715
6716 country_codes = drvr->settings->country_codes;
6717 if (!country_codes) {
6718 brcmf_dbg(TRACE, "No country codes configured for device\n");
6719 return -EINVAL;
6720 }
6721
6722 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6723 (alpha2[1] == ccreq->country_abbrev[1])) {
6724 brcmf_dbg(TRACE, "Country code already set\n");
6725 return -EAGAIN;
6726 }
6727
6728 found_index = -1;
6729 for (i = 0; i < country_codes->table_size; i++) {
6730 cc = &country_codes->table[i];
6731 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6732 found_index = i;
6733 if ((cc->iso3166[0] == alpha2[0]) &&
6734 (cc->iso3166[1] == alpha2[1])) {
6735 found_index = i;
6736 break;
6737 }
6738 }
6739 if (found_index == -1) {
6740 brcmf_dbg(TRACE, "No country code match found\n");
6741 return -EINVAL;
6742 }
6743 memset(ccreq, 0, sizeof(*ccreq));
6744 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6745 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6746 BRCMF_COUNTRY_BUF_SZ);
6747 ccreq->country_abbrev[0] = alpha2[0];
6748 ccreq->country_abbrev[1] = alpha2[1];
6749 ccreq->country_abbrev[2] = 0;
6750
6751 return 0;
6752}
6753
Arend van Spriel63db1a42014-12-21 12:43:51 +01006754static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6755 struct regulatory_request *req)
6756{
6757 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6758 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6759 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006760 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006761 int i;
6762
Hans de Goede26e537882017-03-08 14:50:16 +01006763 /* The country code gets set to "00" by default at boot, ignore */
6764 if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
6765 return;
6766
Arend van Spriel63db1a42014-12-21 12:43:51 +01006767 /* ignore non-ISO3166 country codes */
6768 for (i = 0; i < sizeof(req->alpha2); i++)
6769 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006770 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6771 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006772 return;
6773 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006774
6775 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6776 req->alpha2[0], req->alpha2[1]);
6777
6778 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6779 if (err) {
6780 brcmf_err("Country code iovar returned err = %d\n", err);
6781 return;
6782 }
6783
6784 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6785 if (err)
6786 return;
6787
6788 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6789 if (err) {
6790 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006791 return;
6792 }
6793 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006794}
6795
Arend van Sprielb48d8912014-07-12 08:49:41 +02006796static void brcmf_free_wiphy(struct wiphy *wiphy)
6797{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006798 int i;
6799
Arend van Spriel58de92d2015-04-14 20:10:24 +02006800 if (!wiphy)
6801 return;
6802
Arend van Spriel0882dda2015-08-20 22:06:03 +02006803 if (wiphy->iface_combinations) {
6804 for (i = 0; i < wiphy->n_iface_combinations; i++)
6805 kfree(wiphy->iface_combinations[i].limits);
6806 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006807 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006808 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6809 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6810 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006811 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006812 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6813 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6814 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006815 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006816#if IS_ENABLED(CONFIG_PM)
6817 if (wiphy->wowlan != &brcmf_wowlan_support)
6818 kfree(wiphy->wowlan);
6819#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006820 wiphy_free(wiphy);
6821}
6822
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006823struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006824 struct device *busdev,
6825 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006826{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006827 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006828 struct brcmf_cfg80211_info *cfg;
6829 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006830 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006831 struct brcmf_cfg80211_vif *vif;
6832 struct brcmf_if *ifp;
6833 s32 err = 0;
6834 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006835 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006836
6837 if (!ndev) {
6838 brcmf_err("ndev is invalid\n");
6839 return NULL;
6840 }
6841
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306842 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006843 if (!ops)
6844 return NULL;
6845
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006846 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006847#ifdef CONFIG_PM
6848 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6849 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6850#endif
6851 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006852 if (!wiphy) {
6853 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006854 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006855 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006856 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006857 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006858
6859 cfg = wiphy_priv(wiphy);
6860 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006861 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006862 cfg->pub = drvr;
6863 init_vif_event(&cfg->vif_event);
6864 INIT_LIST_HEAD(&cfg->vif_list);
6865
Rafał Miłecki26072332016-06-06 23:03:55 +02006866 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006867 if (IS_ERR(vif))
6868 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006869
6870 vif->ifp = ifp;
6871 vif->wdev.netdev = ndev;
6872 ndev->ieee80211_ptr = &vif->wdev;
6873 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6874
6875 err = wl_init_priv(cfg);
6876 if (err) {
6877 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006878 brcmf_free_vif(vif);
6879 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006880 }
6881 ifp->vif = vif;
6882
Arend van Sprielb48d8912014-07-12 08:49:41 +02006883 /* determine d11 io type before wiphy setup */
6884 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006885 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006886 brcmf_err("Failed to get D11 version (%d)\n", err);
6887 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006888 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006889 cfg->d11inf.io_type = (u8)io_type;
6890 brcmu_d11_attach(&cfg->d11inf);
6891
6892 err = brcmf_setup_wiphy(wiphy, ifp);
6893 if (err < 0)
6894 goto priv_out;
6895
6896 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006897 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006898 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6899 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6900
6901 /* firmware defaults to 40MHz disabled in 2G band. We signal
6902 * cfg80211 here that we do and have it decide we can enable
6903 * it. But first check if device does support 2G operation.
6904 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006905 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6906 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006907 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6908 }
6909 err = wiphy_register(wiphy);
6910 if (err < 0) {
6911 brcmf_err("Could not register wiphy device (%d)\n", err);
6912 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006913 }
6914
Rafał Miłeckiab990632017-01-07 21:36:05 +01006915 err = brcmf_setup_wiphybands(wiphy);
6916 if (err) {
6917 brcmf_err("Setting wiphy bands failed (%d)\n", err);
6918 goto wiphy_unreg_out;
6919 }
6920
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006921 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6922 * setup 40MHz in 2GHz band and enable OBSS scanning.
6923 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006924 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6925 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006926 if (!err)
6927 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6928 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006929 else
6930 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006931 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006932 /* p2p might require that "if-events" get processed by fweh. So
6933 * activate the already registered event handlers now and activate
6934 * the rest when initialization has completed. drvr->config needs to
6935 * be assigned before activating events.
6936 */
6937 drvr->config = cfg;
6938 err = brcmf_fweh_activate_events(ifp);
6939 if (err) {
6940 brcmf_err("FWEH activation failed (%d)\n", err);
6941 goto wiphy_unreg_out;
6942 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006943
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006944 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006945 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006946 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006947 goto wiphy_unreg_out;
6948 }
6949 err = brcmf_btcoex_attach(cfg);
6950 if (err) {
6951 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6952 brcmf_p2p_detach(&cfg->p2p);
6953 goto wiphy_unreg_out;
6954 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006955
Hante Meulemana7b82d42015-12-10 13:43:04 +01006956 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6957 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6958 if (err) {
6959 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6960 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6961 } else {
6962 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6963 brcmf_notify_tdls_peer_event);
6964 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006965 }
6966
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006967 /* (re-) activate FWEH event handling */
6968 err = brcmf_fweh_activate_events(ifp);
6969 if (err) {
6970 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006971 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006972 }
6973
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006974 /* Fill in some of the advertised nl80211 supported features */
6975 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6976 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6977#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006978 if (wiphy->wowlan &&
6979 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006980 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6981#endif
6982 }
6983
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006984 return cfg;
6985
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006986detach:
6987 brcmf_btcoex_detach(cfg);
6988 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006989wiphy_unreg_out:
6990 wiphy_unregister(cfg->wiphy);
6991priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006992 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006993 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006994 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006995wiphy_out:
6996 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006997 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006998 return NULL;
6999}
7000
7001void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7002{
7003 if (!cfg)
7004 return;
7005
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007006 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007007 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007008 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007009 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007010 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007011}