blob: 83524657a34931a0946c685c8067d53ab1dcc191 [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"
Hante Meulemanbfe81972014-10-28 14:56:16 +010035#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020036#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070037#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020038#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020039#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010040#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010041#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
Arend van Spriele5806072012-09-19 22:21:08 +020043#define BRCMF_SCAN_IE_LEN_MAX 2048
44#define BRCMF_PNO_VERSION 2
45#define BRCMF_PNO_TIME 30
46#define BRCMF_PNO_REPEAT 4
47#define BRCMF_PNO_FREQ_EXPO_MAX 3
48#define BRCMF_PNO_MAX_PFN_COUNT 16
49#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
50#define BRCMF_PNO_HIDDEN_BIT 2
51#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
52#define BRCMF_PNO_SCAN_COMPLETE 1
53#define BRCMF_PNO_SCAN_INCOMPLETE 0
54
Hante Meuleman1a873342012-09-27 14:17:54 +020055#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
56#define WPA_OUI_TYPE 1
57#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
58#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010059#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020060
61#define VS_IE_FIXED_HDR_LEN 6
62#define WPA_IE_VERSION_LEN 2
63#define WPA_IE_MIN_OUI_LEN 4
64#define WPA_IE_SUITE_COUNT_LEN 2
65
66#define WPA_CIPHER_NONE 0 /* None */
67#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
68#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
69#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
70#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
71
72#define RSN_AKM_NONE 0 /* None (IBSS) */
73#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
74#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010075#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
76#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020077#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010078#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
79#define RSN_CAP_MFPR_MASK BIT(6)
80#define RSN_CAP_MFPC_MASK BIT(7)
81#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define VNDR_IE_CMD_LEN 4 /* length of the set command
84 * string :"add", "del" (+ NUL)
85 */
86#define VNDR_IE_COUNT_OFFSET 4
87#define VNDR_IE_PKTFLAG_OFFSET 8
88#define VNDR_IE_VSIE_OFFSET 12
89#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010090#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020091
92#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
93#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020094
Hante Meuleman89286dc2013-02-08 15:53:46 +010095#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
96#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
97#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
98
Hante Meuleman1678ba82015-12-10 13:43:00 +010099#define BRCMF_SCAN_CHANNEL_TIME 40
100#define BRCMF_SCAN_UNASSOC_TIME 40
101#define BRCMF_SCAN_PASSIVE_TIME 120
102
Hante Meuleman3021ad92016-01-05 11:05:45 +0100103#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
104
Arend van Spriel5b435de2011-10-05 13:19:03 +0200105#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
106 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
107
Arend van Sprielce81e312012-10-22 13:55:37 -0700108static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109{
Arend van Sprielc1179032012-10-22 13:55:33 -0700110 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100111 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
112 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200113 return false;
114 }
115 return true;
116}
117
Arend van Spriel5b435de2011-10-05 13:19:03 +0200118#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
119#define RATETAB_ENT(_rateid, _flags) \
120 { \
121 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
122 .hw_value = (_rateid), \
123 .flags = (_flags), \
124 }
125
126static struct ieee80211_rate __wl_rates[] = {
127 RATETAB_ENT(BRCM_RATE_1M, 0),
128 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
129 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
130 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_6M, 0),
132 RATETAB_ENT(BRCM_RATE_9M, 0),
133 RATETAB_ENT(BRCM_RATE_12M, 0),
134 RATETAB_ENT(BRCM_RATE_18M, 0),
135 RATETAB_ENT(BRCM_RATE_24M, 0),
136 RATETAB_ENT(BRCM_RATE_36M, 0),
137 RATETAB_ENT(BRCM_RATE_48M, 0),
138 RATETAB_ENT(BRCM_RATE_54M, 0),
139};
140
Arend van Spriel5b435de2011-10-05 13:19:03 +0200141#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200142#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
143#define wl_a_rates (__wl_rates + 4)
144#define wl_a_rates_size (wl_g_rates_size - 4)
145
146#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200147 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200148 .center_freq = (_freq), \
149 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200150 .max_antenna_gain = 0, \
151 .max_power = 30, \
152}
153
154#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200155 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200156 .center_freq = 5000 + (5 * (_channel)), \
157 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200158 .max_antenna_gain = 0, \
159 .max_power = 30, \
160}
161
162static struct ieee80211_channel __wl_2ghz_channels[] = {
163 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
164 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
165 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
166 CHAN2G(13, 2472), CHAN2G(14, 2484)
167};
168
169static struct ieee80211_channel __wl_5ghz_channels[] = {
170 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
171 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
172 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
173 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
174 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
175 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
176};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200177
Arend van Sprielb48d8912014-07-12 08:49:41 +0200178/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200179 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200180 */
181static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200182 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200183 .bitrates = wl_g_rates,
184 .n_bitrates = wl_g_rates_size,
185};
186
Arend van Spriel58de92d2015-04-14 20:10:24 +0200187static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200188 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200189 .bitrates = wl_a_rates,
190 .n_bitrates = wl_a_rates_size,
191};
192
Hante Meulemand48200b2013-04-03 12:40:29 +0200193/* This is to override regulatory domains defined in cfg80211 module (reg.c)
194 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200195 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
196 * With respect to these flags, wpa_supplicant doesn't * start p2p
197 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200198 * domain are to be done here.
199 */
200static const struct ieee80211_regdomain brcmf_regdom = {
201 .n_reg_rules = 4,
202 .alpha2 = "99",
203 .reg_rules = {
204 /* IEEE 802.11b/g, channels 1..11 */
205 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
206 /* If any */
207 /* IEEE 802.11 channel 14 - Only JP enables
208 * this and for 802.11b only
209 */
210 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
211 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200212 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200213 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200214 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200215};
216
Hante Meuleman240d61a2016-02-17 11:27:10 +0100217/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
218 * are supported. A pointer to this array and the number of entries is passed
219 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
220 * So the cipher suite AES_CMAC has to be the last one in the array, and when
221 * device does not support MFP then the number of suites will be decreased by 1
222 */
223static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200224 WLAN_CIPHER_SUITE_WEP40,
225 WLAN_CIPHER_SUITE_WEP104,
226 WLAN_CIPHER_SUITE_TKIP,
227 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100228 /* Keep as last entry: */
229 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200230};
231
Hante Meuleman1a873342012-09-27 14:17:54 +0200232/* Vendor specific ie. id = 221, oui and type defines exact ie */
233struct brcmf_vs_tlv {
234 u8 id;
235 u8 len;
236 u8 oui[3];
237 u8 oui_type;
238};
239
240struct parsed_vndr_ie_info {
241 u8 *ie_ptr;
242 u32 ie_len; /* total length including id & length field */
243 struct brcmf_vs_tlv vndrie;
244};
245
246struct parsed_vndr_ies {
247 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100248 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200249};
250
Arend van Spriel7705ba62016-04-17 16:44:58 +0200251static u8 nl80211_band_to_fwil(enum nl80211_band band)
252{
253 switch (band) {
254 case NL80211_BAND_2GHZ:
255 return WLC_BAND_2G;
256 case NL80211_BAND_5GHZ:
257 return WLC_BAND_5G;
258 default:
259 WARN_ON(1);
260 break;
261 }
262 return 0;
263}
264
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200265static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
266 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200267{
268 struct brcmu_chan ch_inf;
269 s32 primary_offset;
270
271 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
272 ch->chan->center_freq, ch->center_freq1, ch->width);
273 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100274 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200275 switch (ch->width) {
276 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100277 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200278 ch_inf.bw = BRCMU_CHAN_BW_20;
279 WARN_ON(primary_offset != 0);
280 break;
281 case NL80211_CHAN_WIDTH_40:
282 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100283 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200284 ch_inf.sb = BRCMU_CHAN_SB_U;
285 else
286 ch_inf.sb = BRCMU_CHAN_SB_L;
287 break;
288 case NL80211_CHAN_WIDTH_80:
289 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100290 if (primary_offset == -30)
291 ch_inf.sb = BRCMU_CHAN_SB_LL;
292 else if (primary_offset == -10)
293 ch_inf.sb = BRCMU_CHAN_SB_LU;
294 else if (primary_offset == 10)
295 ch_inf.sb = BRCMU_CHAN_SB_UL;
296 else
297 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200298 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100299 case NL80211_CHAN_WIDTH_80P80:
300 case NL80211_CHAN_WIDTH_160:
301 case NL80211_CHAN_WIDTH_5:
302 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200303 default:
304 WARN_ON_ONCE(1);
305 }
306 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200307 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200308 ch_inf.band = BRCMU_CHAN_BAND_2G;
309 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200310 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200311 ch_inf.band = BRCMU_CHAN_BAND_5G;
312 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200313 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200314 default:
315 WARN_ON_ONCE(1);
316 }
317 d11inf->encchspec(&ch_inf);
318
319 return ch_inf.chspec;
320}
321
Franky Lin83cf17a2013-04-11 13:28:50 +0200322u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
323 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700324{
Franky Lin83cf17a2013-04-11 13:28:50 +0200325 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700326
Franky Lin83cf17a2013-04-11 13:28:50 +0200327 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
328 ch_inf.bw = BRCMU_CHAN_BW_20;
329 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700330
Franky Lin83cf17a2013-04-11 13:28:50 +0200331 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700332}
333
Hante Meuleman89286dc2013-02-08 15:53:46 +0100334/* Traverse a string of 1-byte tag/1-byte length/variable-length value
335 * triples, returning a pointer to the substring whose first element
336 * matches tag
337 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100338const struct brcmf_tlv *
339brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100340{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100341 const struct brcmf_tlv *elt = buf;
342 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100343
344 /* find tagged parameter */
345 while (totlen >= TLV_HDR_LEN) {
346 int len = elt->len;
347
348 /* validate remaining totlen */
349 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
350 return elt;
351
352 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
353 totlen -= (len + TLV_HDR_LEN);
354 }
355
356 return NULL;
357}
358
359/* Is any of the tlvs the expected entry? If
360 * not update the tlvs buffer pointer/length.
361 */
362static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100363brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
364 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100365{
366 /* If the contents match the OUI and the type */
367 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
368 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
369 type == ie[TLV_BODY_OFF + oui_len]) {
370 return true;
371 }
372
373 if (tlvs == NULL)
374 return false;
375 /* point to the next ie */
376 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
377 /* calculate the length of the rest of the buffer */
378 *tlvs_len -= (int)(ie - *tlvs);
379 /* update the pointer to the start of the buffer */
380 *tlvs = ie;
381
382 return false;
383}
384
385static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100386brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100387{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100388 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100389
390 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100391 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100392 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
393 return (struct brcmf_vs_tlv *)ie;
394 }
395 return NULL;
396}
397
398static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100399brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100400{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100401 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100402
403 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
404 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
405 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
406 return (struct brcmf_vs_tlv *)ie;
407 }
408 return NULL;
409}
410
Arend van Spriel39504a22015-08-20 22:06:05 +0200411static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
412 struct brcmf_cfg80211_vif *vif,
413 enum nl80211_iftype new_type)
414{
Arend van Spriel39504a22015-08-20 22:06:05 +0200415 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100416 bool check_combos = false;
417 int ret = 0;
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530418 struct iface_combination_params params = {
419 .num_different_channels = 1,
420 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
Arend van Spriel39504a22015-08-20 22:06:05 +0200422 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100423 if (pos == vif) {
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530424 params.iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100425 } else {
426 /* concurrent interfaces so need check combinations */
427 check_combos = true;
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530428 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100429 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200430
Arend van Spriel353c46a2015-12-10 13:43:06 +0100431 if (check_combos)
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530432 ret = cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel353c46a2015-12-10 13:43:06 +0100433
434 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200435}
436
437static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
438 enum nl80211_iftype new_type)
439{
Arend van Spriel39504a22015-08-20 22:06:05 +0200440 struct brcmf_cfg80211_vif *pos;
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530441 struct iface_combination_params params = {
442 .num_different_channels = 1,
443 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200444
Arend van Spriel39504a22015-08-20 22:06:05 +0200445 list_for_each_entry(pos, &cfg->vif_list, list)
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530446 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel39504a22015-08-20 22:06:05 +0200447
Purushottam Kushwaha11716392016-10-12 18:25:35 +0530448 params.iftype_num[new_type]++;
449 return cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel39504a22015-08-20 22:06:05 +0200450}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100451
Arend van Spriel5b435de2011-10-05 13:19:03 +0200452static void convert_key_from_CPU(struct brcmf_wsec_key *key,
453 struct brcmf_wsec_key_le *key_le)
454{
455 key_le->index = cpu_to_le32(key->index);
456 key_le->len = cpu_to_le32(key->len);
457 key_le->algo = cpu_to_le32(key->algo);
458 key_le->flags = cpu_to_le32(key->flags);
459 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
460 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
461 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
462 memcpy(key_le->data, key->data, sizeof(key->data));
463 memcpy(key_le->ea, key->ea, sizeof(key->ea));
464}
465
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200466static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100467send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200468{
469 int err;
470 struct brcmf_wsec_key_le key_le;
471
472 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200473
Hante Meuleman118eb302014-12-21 12:43:49 +0100474 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700475
Hante Meuleman118eb302014-12-21 12:43:49 +0100476 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700477 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200478
Arend van Spriel5b435de2011-10-05 13:19:03 +0200479 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100480 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200481 return err;
482}
483
Hante Meulemanb3657452013-05-27 21:09:53 +0200484static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100485brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200486{
487 s32 err;
488 u32 mode;
489
490 if (enable)
491 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
492 else
493 mode = 0;
494
495 /* Try to set and enable ARP offload feature, this may fail, then it */
496 /* is simply not supported and err 0 will be returned */
497 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
498 if (err) {
499 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
500 mode, err);
501 err = 0;
502 } else {
503 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
504 if (err) {
505 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
506 enable, err);
507 err = 0;
508 } else
509 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
510 enable, mode);
511 }
512
Franky Lin52f22fb2016-02-17 11:26:55 +0100513 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
514 if (err) {
515 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
516 enable, err);
517 err = 0;
518 } else
519 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
520 enable, mode);
521
Hante Meulemanb3657452013-05-27 21:09:53 +0200522 return err;
523}
524
Hante Meuleman8851cce2014-07-30 13:20:02 +0200525static void
526brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
527{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200528 struct brcmf_cfg80211_vif *vif;
529 struct brcmf_if *ifp;
530
531 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
532 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200533
534 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
535 (wdev->iftype == NL80211_IFTYPE_AP) ||
536 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
537 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
538 ADDR_DIRECT);
539 else
540 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
541 ADDR_INDIRECT);
542}
543
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200544static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
545{
546 int bsscfgidx;
547
548 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
549 /* bsscfgidx 1 is reserved for legacy P2P */
550 if (bsscfgidx == 1)
551 continue;
552 if (!drvr->iflist[bsscfgidx])
553 return bsscfgidx;
554 }
555
556 return -ENOMEM;
557}
558
Hante Meulemana44aa402014-12-03 21:05:33 +0100559static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
560{
561 struct brcmf_mbss_ssid_le mbss_ssid_le;
562 int bsscfgidx;
563 int err;
564
565 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200566 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100567 if (bsscfgidx < 0)
568 return bsscfgidx;
569
570 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
571 mbss_ssid_le.SSID_len = cpu_to_le32(5);
572 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
573
574 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
575 sizeof(mbss_ssid_le));
576 if (err < 0)
577 brcmf_err("setting ssid failed %d\n", err);
578
579 return err;
580}
581
582/**
583 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
584 *
585 * @wiphy: wiphy device of new interface.
586 * @name: name of the new interface.
587 * @flags: not used.
588 * @params: contains mac address for AP device.
589 */
590static
591struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
592 u32 *flags, struct vif_params *params)
593{
594 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
595 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
596 struct brcmf_cfg80211_vif *vif;
597 int err;
598
599 if (brcmf_cfg80211_vif_event_armed(cfg))
600 return ERR_PTR(-EBUSY);
601
602 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
603
Rafał Miłecki26072332016-06-06 23:03:55 +0200604 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100605 if (IS_ERR(vif))
606 return (struct wireless_dev *)vif;
607
608 brcmf_cfg80211_arm_vif_event(cfg, vif);
609
610 err = brcmf_cfg80211_request_ap_if(ifp);
611 if (err) {
612 brcmf_cfg80211_arm_vif_event(cfg, NULL);
613 goto fail;
614 }
615
616 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100617 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
618 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100619 brcmf_cfg80211_arm_vif_event(cfg, NULL);
620 if (!err) {
621 brcmf_err("timeout occurred\n");
622 err = -EIO;
623 goto fail;
624 }
625
626 /* interface created in firmware */
627 ifp = vif->ifp;
628 if (!ifp) {
629 brcmf_err("no if pointer provided\n");
630 err = -ENOENT;
631 goto fail;
632 }
633
634 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
635 err = brcmf_net_attach(ifp, true);
636 if (err) {
637 brcmf_err("Registering netdevice failed\n");
638 goto fail;
639 }
640
641 return &ifp->vif->wdev;
642
643fail:
644 brcmf_free_vif(vif);
645 return ERR_PTR(err);
646}
647
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100648static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
649{
650 enum nl80211_iftype iftype;
651
652 iftype = vif->wdev.iftype;
653 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
654}
655
656static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
657{
658 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
659}
660
Arend van Spriel9f440b72013-02-08 15:53:36 +0100661static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
662 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100663 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100664 enum nl80211_iftype type,
665 u32 *flags,
666 struct vif_params *params)
667{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200668 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200669 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200670
Arend van Spriel9f440b72013-02-08 15:53:36 +0100671 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200672 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
673 if (err) {
674 brcmf_err("iface validation failed: err=%d\n", err);
675 return ERR_PTR(err);
676 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100677 switch (type) {
678 case NL80211_IFTYPE_ADHOC:
679 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100680 case NL80211_IFTYPE_AP_VLAN:
681 case NL80211_IFTYPE_WDS:
682 case NL80211_IFTYPE_MONITOR:
683 case NL80211_IFTYPE_MESH_POINT:
684 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100685 case NL80211_IFTYPE_AP:
686 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200687 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100688 case NL80211_IFTYPE_P2P_CLIENT:
689 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200690 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100691 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200692 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100693 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100694 default:
695 return ERR_PTR(-EINVAL);
696 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200697
698 if (IS_ERR(wdev))
699 brcmf_err("add iface %s type %d failed: err=%d\n",
700 name, type, (int)PTR_ERR(wdev));
701 else
702 brcmf_cfg80211_update_proto_addr_mode(wdev);
703
704 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100705}
706
Daniel Kim5e787f72014-06-21 12:11:18 +0200707static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
708{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200709 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200710 brcmf_set_mpc(ifp, mpc);
711}
712
Arend van Sprielf96aa072013-04-05 10:57:48 +0200713void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100714{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100715 s32 err = 0;
716
717 if (check_vif_up(ifp->vif)) {
718 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
719 if (err) {
720 brcmf_err("fail to set mpc\n");
721 return;
722 }
723 brcmf_dbg(INFO, "MPC : %d\n", mpc);
724 }
725}
726
Arend van Spriela0f472a2013-04-05 10:57:49 +0200727s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
728 struct brcmf_if *ifp, bool aborted,
729 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100730{
731 struct brcmf_scan_params_le params_le;
732 struct cfg80211_scan_request *scan_request;
733 s32 err = 0;
734
735 brcmf_dbg(SCAN, "Enter\n");
736
737 /* clear scan request, because the FW abort can cause a second call */
738 /* to this functon and might cause a double cfg80211_scan_done */
739 scan_request = cfg->scan_request;
740 cfg->scan_request = NULL;
741
742 if (timer_pending(&cfg->escan_timeout))
743 del_timer_sync(&cfg->escan_timeout);
744
745 if (fw_abort) {
746 /* Do a scan abort to stop the driver's scan engine */
747 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
748 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800749 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100750 params_le.bss_type = DOT11_BSSTYPE_ANY;
751 params_le.scan_type = 0;
752 params_le.channel_num = cpu_to_le32(1);
753 params_le.nprobes = cpu_to_le32(1);
754 params_le.active_time = cpu_to_le32(-1);
755 params_le.passive_time = cpu_to_le32(-1);
756 params_le.home_time = cpu_to_le32(-1);
757 /* Scan is aborted by setting channel_list[0] to -1 */
758 params_le.channel_list[0] = cpu_to_le16(-1);
759 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200760 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100761 &params_le, sizeof(params_le));
762 if (err)
763 brcmf_err("Scan abort failed\n");
764 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200765
Daniel Kim5e787f72014-06-21 12:11:18 +0200766 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200767
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100768 /*
769 * e-scan can be initiated by scheduled scan
770 * which takes precedence.
771 */
772 if (cfg->sched_escan) {
773 brcmf_dbg(SCAN, "scheduled scan completed\n");
774 cfg->sched_escan = false;
775 if (!aborted)
776 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100777 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300778 struct cfg80211_scan_info info = {
779 .aborted = aborted,
780 };
781
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100782 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
783 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300784 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100785 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100786 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
787 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100788
789 return err;
790}
791
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200792static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
793 struct wireless_dev *wdev)
794{
795 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
796 struct net_device *ndev = wdev->netdev;
797 struct brcmf_if *ifp = netdev_priv(ndev);
798 int ret;
799 int err;
800
801 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
802
803 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
804 if (err) {
805 brcmf_err("interface_remove failed %d\n", err);
806 goto err_unarm;
807 }
808
809 /* wait for firmware event */
810 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
811 BRCMF_VIF_EVENT_TIMEOUT);
812 if (!ret) {
813 brcmf_err("timeout occurred\n");
814 err = -EIO;
815 goto err_unarm;
816 }
817
818 brcmf_remove_interface(ifp, true);
819
820err_unarm:
821 brcmf_cfg80211_arm_vif_event(cfg, NULL);
822 return err;
823}
824
Arend van Spriel9f440b72013-02-08 15:53:36 +0100825static
826int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
827{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100828 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
829 struct net_device *ndev = wdev->netdev;
830
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200831 if (ndev && ndev == cfg_to_ndev(cfg))
832 return -ENOTSUPP;
833
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100834 /* vif event pending in firmware */
835 if (brcmf_cfg80211_vif_event_armed(cfg))
836 return -EBUSY;
837
838 if (ndev) {
839 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200840 cfg->escan_info.ifp == netdev_priv(ndev))
841 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
842 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100843
844 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
845 }
846
Arend van Spriel9f440b72013-02-08 15:53:36 +0100847 switch (wdev->iftype) {
848 case NL80211_IFTYPE_ADHOC:
849 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100850 case NL80211_IFTYPE_AP_VLAN:
851 case NL80211_IFTYPE_WDS:
852 case NL80211_IFTYPE_MONITOR:
853 case NL80211_IFTYPE_MESH_POINT:
854 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200855 case NL80211_IFTYPE_AP:
856 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100857 case NL80211_IFTYPE_P2P_CLIENT:
858 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200859 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100860 return brcmf_p2p_del_vif(wiphy, wdev);
861 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100862 default:
863 return -EINVAL;
864 }
865 return -EOPNOTSUPP;
866}
867
Arend van Spriel5b435de2011-10-05 13:19:03 +0200868static s32
869brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
870 enum nl80211_iftype type, u32 *flags,
871 struct vif_params *params)
872{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100873 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700874 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100875 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200876 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200877 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200878 s32 err = 0;
879
Hante Meuleman37a869e2015-10-29 20:33:17 +0100880 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
881 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200882
883 /* WAR: There are a number of p2p interface related problems which
884 * need to be handled initially (before doing the validate).
885 * wpa_supplicant tends to do iface changes on p2p device/client/go
886 * which are not always possible/allowed. However we need to return
887 * OK otherwise the wpa_supplicant wont start. The situation differs
888 * on configuration and setup (p2pon=1 module param). The first check
889 * is to see if the request is a change to station for p2p iface.
890 */
891 if ((type == NL80211_IFTYPE_STATION) &&
892 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
893 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
894 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
895 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
896 /* Now depending on whether module param p2pon=1 was used the
897 * response needs to be either 0 or EOPNOTSUPP. The reason is
898 * that if p2pon=1 is used, but a newer supplicant is used then
899 * we should return an error, as this combination wont work.
900 * In other situations 0 is returned and supplicant will start
901 * normally. It will give a trace in cfg80211, but it is the
902 * only way to get it working. Unfortunately this will result
903 * in situation where we wont support new supplicant in
904 * combination with module param p2pon=1, but that is the way
905 * it is. If the user tries this then unloading of driver might
906 * fail/lock.
907 */
908 if (cfg->p2p.p2pdev_dynamically)
909 return -EOPNOTSUPP;
910 else
911 return 0;
912 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200913 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
914 if (err) {
915 brcmf_err("iface validation failed: err=%d\n", err);
916 return err;
917 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200918 switch (type) {
919 case NL80211_IFTYPE_MONITOR:
920 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100921 brcmf_err("type (%d) : currently we do not support this type\n",
922 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200923 return -EOPNOTSUPP;
924 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200925 infra = 0;
926 break;
927 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200928 infra = 1;
929 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200930 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100931 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200932 ap = 1;
933 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200934 default:
935 err = -EINVAL;
936 goto done;
937 }
938
Hante Meuleman1a873342012-09-27 14:17:54 +0200939 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100940 if (type == NL80211_IFTYPE_P2P_GO) {
941 brcmf_dbg(INFO, "IF Type = P2P GO\n");
942 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
943 }
944 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100945 brcmf_dbg(INFO, "IF Type = AP\n");
946 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200947 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100948 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200949 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100950 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200951 err = -EAGAIN;
952 goto done;
953 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100954 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100955 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200956 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200957 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200958
Hante Meuleman8851cce2014-07-30 13:20:02 +0200959 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
960
Arend van Spriel5b435de2011-10-05 13:19:03 +0200961done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100962 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200963
964 return err;
965}
966
Franky Lin83cf17a2013-04-11 13:28:50 +0200967static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
968 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200969 struct cfg80211_scan_request *request)
970{
971 u32 n_ssids;
972 u32 n_channels;
973 s32 i;
974 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200975 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200976 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200977 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200978
Joe Perches93803b32015-03-02 19:54:49 -0800979 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200980 params_le->bss_type = DOT11_BSSTYPE_ANY;
Arend Van Spriel54aa8322017-09-12 10:47:54 +0200981 params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
Hante Meulemane756af52012-09-11 21:18:52 +0200982 params_le->channel_num = 0;
983 params_le->nprobes = cpu_to_le32(-1);
984 params_le->active_time = cpu_to_le32(-1);
985 params_le->passive_time = cpu_to_le32(-1);
986 params_le->home_time = cpu_to_le32(-1);
987 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
988
Hante Meulemane756af52012-09-11 21:18:52 +0200989 n_ssids = request->n_ssids;
990 n_channels = request->n_channels;
Arend Van Spriel54aa8322017-09-12 10:47:54 +0200991
Hante Meulemane756af52012-09-11 21:18:52 +0200992 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100993 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
994 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200995 if (n_channels > 0) {
996 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200997 chanspec = channel_to_chanspec(&cfg->d11inf,
998 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100999 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
1000 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +02001001 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +02001002 }
1003 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001004 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001005 }
1006 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001007 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001008 if (n_ssids > 0) {
1009 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1010 n_channels * sizeof(u16);
1011 offset = roundup(offset, sizeof(u32));
1012 ptr = (char *)params_le + offset;
1013 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001014 memset(&ssid_le, 0, sizeof(ssid_le));
1015 ssid_le.SSID_len =
1016 cpu_to_le32(request->ssids[i].ssid_len);
1017 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1018 request->ssids[i].ssid_len);
1019 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001020 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001021 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001022 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
1023 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001024 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1025 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001026 }
1027 } else {
Arend Van Spriel54aa8322017-09-12 10:47:54 +02001028 brcmf_dbg(SCAN, "Performing passive scan\n");
1029 params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
Hante Meulemane756af52012-09-11 21:18:52 +02001030 }
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 Spriel27a68fe2012-09-27 14:17:55 +02001081brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001082 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001083{
1084 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 Spriel9f440b72013-02-08 15:53:36 +01001091 escan->wiphy = wiphy;
1092 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 Spriela0f472a2013-04-05 10:57:49 +02001171 err = brcmf_do_escan(cfg, wiphy, 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 cfg80211_bss *bss;
2780 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002781 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002782 u16 channel;
2783 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002784 u16 notify_capability;
2785 u16 notify_interval;
2786 u8 *notify_ie;
2787 size_t notify_ielen;
Franky Lin73fdfa32018-05-15 11:14:44 +02002788 struct cfg80211_inform_bss bss_data = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02002789
2790 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002791 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792 return 0;
2793 }
2794
Franky Lin83cf17a2013-04-11 13:28:50 +02002795 if (!bi->ctl_ch) {
2796 ch.chspec = le16_to_cpu(bi->chanspec);
2797 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002798 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002799 }
2800 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801
2802 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002803 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002804 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002805 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806
2807 freq = ieee80211_channel_to_frequency(channel, band->band);
Franky Lin039656e2018-04-26 12:18:35 +02002808 bss_data.chan = ieee80211_get_channel(wiphy, freq);
2809 bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
2810 bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811
Arend van Spriel5b435de2011-10-05 13:19:03 +02002812 notify_capability = le16_to_cpu(bi->capability);
2813 notify_interval = le16_to_cpu(bi->beacon_period);
2814 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2815 notify_ielen = le32_to_cpu(bi->ie_length);
Franky Lin039656e2018-04-26 12:18:35 +02002816 bss_data.signal = (s16)le16_to_cpu(bi->RSSI) * 100;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002817
Arend van Spriel16886732012-12-05 15:26:04 +01002818 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2819 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2820 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2821 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
Franky Lin039656e2018-04-26 12:18:35 +02002822 brcmf_dbg(CONN, "Signal: %d\n", bss_data.signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002823
Franky Lin039656e2018-04-26 12:18:35 +02002824 bss = cfg80211_inform_bss_data(wiphy, &bss_data,
2825 CFG80211_BSS_FTYPE_UNKNOWN,
2826 (const u8 *)bi->BSSID,
2827 0, notify_capability,
2828 notify_interval, notify_ie,
2829 notify_ielen, 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);
Hante Meulemanf07998952012-11-05 16:22:13 -08003014 if (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 Spriel27a68fe2012-09-27 14:17:55 +02003037 if (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;
Arend Van Spriel4d3132d2017-09-12 10:47:53 +02003089 u32 escan_buflen;
Hante Meulemane756af52012-09-11 21:18:52 +02003090 struct brcmf_bss_info_le *bss_info_le;
3091 struct brcmf_bss_info_le *bss = NULL;
3092 u32 bi_length;
3093 struct brcmf_scan_results *list;
3094 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003095 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003096
Arend van Spriel5c36b992012-11-14 18:46:05 -08003097 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003098
Arend van Spriela0f472a2013-04-05 10:57:49 +02003099 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003100 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003101 return -EPERM;
3102 }
3103
3104 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003105 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Arend Van Spriel4d3132d2017-09-12 10:47:53 +02003106 if (e->datalen < sizeof(*escan_result_le)) {
3107 brcmf_err("invalid event data length\n");
3108 goto exit;
3109 }
Hante Meulemane756af52012-09-11 21:18:52 +02003110 escan_result_le = (struct brcmf_escan_result_le *) data;
3111 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003112 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003113 goto exit;
3114 }
Arend Van Spriel4d3132d2017-09-12 10:47:53 +02003115 escan_buflen = le32_to_cpu(escan_result_le->buflen);
3116 if (escan_buflen > BRCMF_ESCAN_BUF_SIZE ||
3117 escan_buflen > e->datalen ||
3118 escan_buflen < sizeof(*escan_result_le)) {
3119 brcmf_err("Invalid escan buffer length: %d\n",
3120 escan_buflen);
3121 goto exit;
3122 }
Hante Meulemane756af52012-09-11 21:18:52 +02003123 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003124 brcmf_err("Invalid bss_count %d: ignoring\n",
3125 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003126 goto exit;
3127 }
3128 bss_info_le = &escan_result_le->bss_info_le;
3129
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003130 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3131 goto exit;
3132
3133 if (!cfg->scan_request) {
3134 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3135 goto exit;
3136 }
3137
Hante Meulemane756af52012-09-11 21:18:52 +02003138 bi_length = le32_to_cpu(bss_info_le->length);
Arend Van Spriel4d3132d2017-09-12 10:47:53 +02003139 if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
3140 brcmf_err("Ignoring invalid bss_info length: %d\n",
Arend van Spriel57d6e912012-12-05 15:26:00 +01003141 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003142 goto exit;
3143 }
3144
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003145 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003146 BIT(NL80211_IFTYPE_ADHOC))) {
3147 if (le16_to_cpu(bss_info_le->capability) &
3148 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003149 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003150 goto exit;
3151 }
3152 }
3153
3154 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003155 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003156 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003157 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003158 goto exit;
3159 }
3160
3161 for (i = 0; i < list->count; i++) {
3162 bss = bss ? (struct brcmf_bss_info_le *)
3163 ((unsigned char *)bss +
3164 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003165 if (brcmf_compare_update_same_bss(cfg, bss,
3166 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003167 goto exit;
3168 }
Hante Meulemand5367332016-02-17 11:26:51 +01003169 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3170 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003171 list->version = le32_to_cpu(bss_info_le->version);
3172 list->buflen += bi_length;
3173 list->count++;
3174 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003175 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003176 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3177 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003178 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003179 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003180 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003181 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003182 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003183 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3184 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003185 }
3186exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003187 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003188}
3189
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003190static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003191{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003192 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3193 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003194 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3195 /* Init scan_timeout timer */
3196 init_timer(&cfg->escan_timeout);
3197 cfg->escan_timeout.data = (unsigned long) cfg;
3198 cfg->escan_timeout.function = brcmf_escan_timeout;
3199 INIT_WORK(&cfg->escan_timeout_work,
3200 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003201}
3202
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003203/* PFN result doesn't have all the info which are required by the supplicant
3204 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3205 * via wl_inform_single_bss in the required format. Escan does require the
3206 * scan request in the form of cfg80211_scan_request. For timebeing, create
3207 * cfg80211_scan_request one out of the received PNO event.
3208 */
3209static s32
3210brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3211 const struct brcmf_event_msg *e, void *data)
3212{
3213 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3214 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3215 struct cfg80211_scan_request *request = NULL;
3216 struct cfg80211_ssid *ssid = NULL;
3217 struct ieee80211_channel *channel = NULL;
3218 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3219 int err = 0;
3220 int channel_req = 0;
3221 int band = 0;
3222 struct brcmf_pno_scanresults_le *pfn_result;
3223 u32 result_count;
3224 u32 status;
3225
3226 brcmf_dbg(SCAN, "Enter\n");
3227
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003228 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3229 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3230 return 0;
3231 }
3232
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003233 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3234 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3235 return 0;
3236 }
3237
3238 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3239 result_count = le32_to_cpu(pfn_result->count);
3240 status = le32_to_cpu(pfn_result->status);
3241
3242 /* PFN event is limited to fit 512 bytes so we may get
3243 * multiple NET_FOUND events. For now place a warning here.
3244 */
3245 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3246 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3247 if (result_count > 0) {
3248 int i;
3249
3250 request = kzalloc(sizeof(*request), GFP_KERNEL);
3251 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3252 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3253 if (!request || !ssid || !channel) {
3254 err = -ENOMEM;
3255 goto out_err;
3256 }
3257
3258 request->wiphy = wiphy;
3259 data += sizeof(struct brcmf_pno_scanresults_le);
3260 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3261
3262 for (i = 0; i < result_count; i++) {
3263 netinfo = &netinfo_start[i];
3264 if (!netinfo) {
3265 brcmf_err("Invalid netinfo ptr. index: %d\n",
3266 i);
3267 err = -EINVAL;
3268 goto out_err;
3269 }
3270
3271 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3272 netinfo->SSID, netinfo->channel);
3273 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3274 ssid[i].ssid_len = netinfo->SSID_len;
3275 request->n_ssids++;
3276
3277 channel_req = netinfo->channel;
3278 if (channel_req <= CH_MAX_2G_CHANNEL)
3279 band = NL80211_BAND_2GHZ;
3280 else
3281 band = NL80211_BAND_5GHZ;
3282 channel[i].center_freq =
3283 ieee80211_channel_to_frequency(channel_req,
3284 band);
3285 channel[i].band = band;
3286 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3287 request->channels[i] = &channel[i];
3288 request->n_channels++;
3289 }
3290
3291 /* assign parsed ssid array */
3292 if (request->n_ssids)
3293 request->ssids = &ssid[0];
3294
3295 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3296 /* Abort any on-going scan */
3297 brcmf_abort_scanning(cfg);
3298 }
3299
3300 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3301 cfg->escan_info.run = brcmf_run_escan;
3302 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3303 if (err) {
3304 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3305 goto out_err;
3306 }
3307 cfg->sched_escan = true;
3308 cfg->scan_request = request;
3309 } else {
3310 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3311 goto out_err;
3312 }
3313
3314 kfree(ssid);
3315 kfree(channel);
3316 kfree(request);
3317 return 0;
3318
3319out_err:
3320 kfree(ssid);
3321 kfree(channel);
3322 kfree(request);
3323 cfg80211_sched_scan_stopped(wiphy);
3324 return err;
3325}
3326
3327static int brcmf_dev_pno_clean(struct net_device *ndev)
3328{
3329 int ret;
3330
3331 /* Disable pfn */
3332 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3333 if (ret == 0) {
3334 /* clear pfn */
3335 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3336 NULL, 0);
3337 }
3338 if (ret < 0)
3339 brcmf_err("failed code %d\n", ret);
3340
3341 return ret;
3342}
3343
3344static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3345 struct cfg80211_sched_scan_request *request)
3346{
3347 struct brcmf_pno_param_le pfn_param;
3348 struct brcmf_pno_macaddr_le pfn_mac;
3349 s32 err;
3350 u8 *mac_mask;
3351 int i;
3352
3353 memset(&pfn_param, 0, sizeof(pfn_param));
3354 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3355
3356 /* set extra pno params */
3357 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3358 pfn_param.repeat = BRCMF_PNO_REPEAT;
3359 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3360
3361 /* set up pno scan fr */
3362 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3363
3364 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3365 sizeof(pfn_param));
3366 if (err) {
3367 brcmf_err("pfn_set failed, err=%d\n", err);
3368 return err;
3369 }
3370
3371 /* Find out if mac randomization should be turned on */
3372 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3373 return 0;
3374
3375 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3376 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3377
3378 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3379 mac_mask = request->mac_addr_mask;
3380 for (i = 0; i < ETH_ALEN; i++) {
3381 pfn_mac.mac[i] &= mac_mask[i];
3382 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3383 }
3384 /* Clear multi bit */
3385 pfn_mac.mac[0] &= 0xFE;
3386 /* Set locally administered */
3387 pfn_mac.mac[0] |= 0x02;
3388
3389 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3390 sizeof(pfn_mac));
3391 if (err)
3392 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3393
3394 return err;
3395}
3396
3397static int
3398brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3399 struct net_device *ndev,
3400 struct cfg80211_sched_scan_request *request)
3401{
3402 struct brcmf_if *ifp = netdev_priv(ndev);
3403 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3404 struct brcmf_pno_net_param_le pfn;
3405 int i;
3406 int ret = 0;
3407
3408 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3409 request->n_match_sets, request->n_ssids);
3410 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3411 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3412 return -EAGAIN;
3413 }
3414 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3415 brcmf_err("Scanning suppressed: status (%lu)\n",
3416 cfg->scan_status);
3417 return -EAGAIN;
3418 }
3419
3420 if (!request->n_ssids || !request->n_match_sets) {
3421 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3422 request->n_ssids);
3423 return -EINVAL;
3424 }
3425
3426 if (request->n_ssids > 0) {
3427 for (i = 0; i < request->n_ssids; i++) {
3428 /* Active scan req for ssids */
3429 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3430 request->ssids[i].ssid);
3431
3432 /* match_set ssids is a supert set of n_ssid list,
3433 * so we need not add these set separately.
3434 */
3435 }
3436 }
3437
3438 if (request->n_match_sets > 0) {
3439 /* clean up everything */
3440 ret = brcmf_dev_pno_clean(ndev);
3441 if (ret < 0) {
3442 brcmf_err("failed error=%d\n", ret);
3443 return ret;
3444 }
3445
3446 /* configure pno */
3447 if (brcmf_dev_pno_config(ifp, request))
3448 return -EINVAL;
3449
3450 /* configure each match set */
3451 for (i = 0; i < request->n_match_sets; i++) {
3452 struct cfg80211_ssid *ssid;
3453 u32 ssid_len;
3454
3455 ssid = &request->match_sets[i].ssid;
3456 ssid_len = ssid->ssid_len;
3457
3458 if (!ssid_len) {
3459 brcmf_err("skip broadcast ssid\n");
3460 continue;
3461 }
3462 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3463 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3464 pfn.wsec = cpu_to_le32(0);
3465 pfn.infra = cpu_to_le32(1);
3466 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3467 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3468 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3469 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3470 sizeof(pfn));
3471 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3472 ret == 0 ? "set" : "failed", ssid->ssid);
3473 }
3474 /* Enable the PNO */
3475 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3476 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3477 return -EINVAL;
3478 }
3479 } else {
3480 return -EINVAL;
3481 }
3482
3483 return 0;
3484}
3485
3486static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3487 struct net_device *ndev)
3488{
3489 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3490
3491 brcmf_dbg(SCAN, "enter\n");
3492 brcmf_dev_pno_clean(ndev);
3493 if (cfg->sched_escan)
3494 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3495 return 0;
3496}
3497
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003498static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003499{
3500 if (ms < 1000 / HZ) {
3501 cond_resched();
3502 mdelay(ms);
3503 } else {
3504 msleep(ms);
3505 }
3506}
3507
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003508static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3509 u8 *pattern, u32 patternsize, u8 *mask,
3510 u32 packet_offset)
3511{
3512 struct brcmf_fil_wowl_pattern_le *filter;
3513 u32 masksize;
3514 u32 patternoffset;
3515 u8 *buf;
3516 u32 bufsize;
3517 s32 ret;
3518
3519 masksize = (patternsize + 7) / 8;
3520 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3521
3522 bufsize = sizeof(*filter) + patternsize + masksize;
3523 buf = kzalloc(bufsize, GFP_KERNEL);
3524 if (!buf)
3525 return -ENOMEM;
3526 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3527
3528 memcpy(filter->cmd, cmd, 4);
3529 filter->masksize = cpu_to_le32(masksize);
3530 filter->offset = cpu_to_le32(packet_offset);
3531 filter->patternoffset = cpu_to_le32(patternoffset);
3532 filter->patternsize = cpu_to_le32(patternsize);
3533 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3534
3535 if ((mask) && (masksize))
3536 memcpy(buf + sizeof(*filter), mask, masksize);
3537 if ((pattern) && (patternsize))
3538 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3539
3540 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3541
3542 kfree(buf);
3543 return ret;
3544}
3545
Hante Meuleman3021ad92016-01-05 11:05:45 +01003546static s32
3547brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3548 void *data)
3549{
3550 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3551 struct brcmf_pno_scanresults_le *pfn_result;
3552 struct brcmf_pno_net_info_le *netinfo;
3553
3554 brcmf_dbg(SCAN, "Enter\n");
3555
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003556 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3557 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3558 return 0;
3559 }
3560
Hante Meuleman3021ad92016-01-05 11:05:45 +01003561 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3562
3563 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3564 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3565 return 0;
3566 }
3567
3568 if (le32_to_cpu(pfn_result->count) < 1) {
3569 brcmf_err("Invalid result count, expected 1 (%d)\n",
3570 le32_to_cpu(pfn_result->count));
3571 return -EINVAL;
3572 }
3573
3574 data += sizeof(struct brcmf_pno_scanresults_le);
3575 netinfo = (struct brcmf_pno_net_info_le *)data;
3576 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3577 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3578 cfg->wowl.nd->n_channels = 1;
3579 cfg->wowl.nd->channels[0] =
3580 ieee80211_channel_to_frequency(netinfo->channel,
3581 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3582 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3583 cfg->wowl.nd_info->n_matches = 1;
3584 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3585
3586 /* Inform (the resume task) that the net detect information was recvd */
3587 cfg->wowl.nd_data_completed = true;
3588 wake_up(&cfg->wowl.nd_data_wait);
3589
3590 return 0;
3591}
3592
Hante Meulemanaeb64222015-10-29 20:33:19 +01003593#ifdef CONFIG_PM
3594
3595static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3596{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003597 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003598 struct brcmf_wowl_wakeind_le wake_ind_le;
3599 struct cfg80211_wowlan_wakeup wakeup_data;
3600 struct cfg80211_wowlan_wakeup *wakeup;
3601 u32 wakeind;
3602 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003603 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003604
3605 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3606 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003607 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003608 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3609 return;
3610 }
3611
3612 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3613 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003614 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3615 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003616 wakeup = &wakeup_data;
3617 memset(&wakeup_data, 0, sizeof(wakeup_data));
3618 wakeup_data.pattern_idx = -1;
3619
3620 if (wakeind & BRCMF_WOWL_MAGIC) {
3621 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3622 wakeup_data.magic_pkt = true;
3623 }
3624 if (wakeind & BRCMF_WOWL_DIS) {
3625 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3626 wakeup_data.disconnect = true;
3627 }
3628 if (wakeind & BRCMF_WOWL_BCN) {
3629 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3630 wakeup_data.disconnect = true;
3631 }
3632 if (wakeind & BRCMF_WOWL_RETR) {
3633 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3634 wakeup_data.disconnect = true;
3635 }
3636 if (wakeind & BRCMF_WOWL_NET) {
3637 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3638 /* For now always map to pattern 0, no API to get
3639 * correct information available at the moment.
3640 */
3641 wakeup_data.pattern_idx = 0;
3642 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003643 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3644 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3645 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3646 cfg->wowl.nd_data_completed,
3647 BRCMF_ND_INFO_TIMEOUT);
3648 if (!timeout)
3649 brcmf_err("No result for wowl net detect\n");
3650 else
3651 wakeup_data.net_detect = cfg->wowl.nd_info;
3652 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003653 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3654 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3655 wakeup_data.gtk_rekey_failure = true;
3656 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003657 } else {
3658 wakeup = NULL;
3659 }
3660 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3661}
3662
3663#else
3664
3665static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3666{
3667}
3668
3669#endif /* CONFIG_PM */
3670
Arend van Spriel5b435de2011-10-05 13:19:03 +02003671static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3672{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003673 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3674 struct net_device *ndev = cfg_to_ndev(cfg);
3675 struct brcmf_if *ifp = netdev_priv(ndev);
3676
Arend van Sprield96b8012012-12-05 15:26:02 +01003677 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003678
Hante Meuleman3021ad92016-01-05 11:05:45 +01003679 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003680 brcmf_report_wowl_wakeind(wiphy, ifp);
3681 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3682 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003683 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3684 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003685 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003686 cfg->wowl.pre_pmmode);
3687 cfg->wowl.active = false;
3688 if (cfg->wowl.nd_enabled) {
3689 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3690 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3691 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3692 brcmf_notify_sched_scan_results);
3693 cfg->wowl.nd_enabled = false;
3694 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003695 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003696 return 0;
3697}
3698
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003699static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3700 struct brcmf_if *ifp,
3701 struct cfg80211_wowlan *wowl)
3702{
3703 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003704 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003705 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003706
3707 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3708
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003709 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3710 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003711 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003712 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3713
3714 wowl_config = 0;
3715 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003716 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003717 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003718 wowl_config |= BRCMF_WOWL_MAGIC;
3719 if ((wowl->patterns) && (wowl->n_patterns)) {
3720 wowl_config |= BRCMF_WOWL_NET;
3721 for (i = 0; i < wowl->n_patterns; i++) {
3722 brcmf_config_wowl_pattern(ifp, "add",
3723 (u8 *)wowl->patterns[i].pattern,
3724 wowl->patterns[i].pattern_len,
3725 (u8 *)wowl->patterns[i].mask,
3726 wowl->patterns[i].pkt_offset);
3727 }
3728 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003729 if (wowl->nd_config) {
3730 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3731 wowl->nd_config);
3732 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3733
3734 cfg->wowl.nd_data_completed = false;
3735 cfg->wowl.nd_enabled = true;
3736 /* Now reroute the event for PFN to the wowl function. */
3737 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3738 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3739 brcmf_wowl_nd_results);
3740 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003741 if (wowl->gtk_rekey_failure)
3742 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003743 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3744 wowl_config |= BRCMF_WOWL_UNASSOC;
3745
Hante Meulemana7ed7822016-09-19 12:09:58 +01003746 memcpy(&wowl_wakeind, "clear", 6);
3747 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3748 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003749 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3750 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3751 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003752 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003753}
3754
Arend van Spriel5b435de2011-10-05 13:19:03 +02003755static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003756 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003757{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003758 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3759 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003760 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003761 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003762
Arend van Sprield96b8012012-12-05 15:26:02 +01003763 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003765 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003766 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003767 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003768 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003769 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003770
Hante Meuleman3021ad92016-01-05 11:05:45 +01003771 /* Stop scheduled scan */
3772 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3773 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3774
Arend van Spriel7d641072012-10-22 13:55:39 -07003775 /* end any scanning */
3776 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003777 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003778
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003779 if (wowl == NULL) {
3780 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3781 list_for_each_entry(vif, &cfg->vif_list, list) {
3782 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3783 continue;
3784 /* While going to suspend if associated with AP
3785 * disassociate from AP to save power while system is
3786 * in suspended state
3787 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003788 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003789 /* Make sure WPA_Supplicant receives all the event
3790 * generated due to DISASSOC call to the fw to keep
3791 * the state fw and WPA_Supplicant state consistent
3792 */
3793 brcmf_delay(500);
3794 }
3795 /* Configure MPC */
3796 brcmf_set_mpc(ifp, 1);
3797
3798 } else {
3799 /* Configure WOWL paramaters */
3800 brcmf_configure_wowl(cfg, ifp, wowl);
3801 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003802
Arend van Spriel7d641072012-10-22 13:55:39 -07003803exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003804 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003805 /* clear any scanning activity */
3806 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003807 return 0;
3808}
3809
3810static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003811brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003812{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003813 struct brcmf_pmk_list_le *pmk_list;
3814 int i;
3815 u32 npmk;
3816 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003817
Hante Meuleman6c404f32015-12-10 13:43:03 +01003818 pmk_list = &cfg->pmk_list;
3819 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003820
Hante Meuleman6c404f32015-12-10 13:43:03 +01003821 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3822 for (i = 0; i < npmk; i++)
3823 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003824
Hante Meuleman6c404f32015-12-10 13:43:03 +01003825 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3826 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003827
3828 return err;
3829}
3830
3831static s32
3832brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3833 struct cfg80211_pmksa *pmksa)
3834{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003835 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003836 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003837 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3838 s32 err;
3839 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003840
Arend van Sprield96b8012012-12-05 15:26:02 +01003841 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003842 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003843 return -EIO;
3844
Hante Meuleman6c404f32015-12-10 13:43:03 +01003845 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3846 for (i = 0; i < npmk; i++)
3847 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003848 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003849 if (i < BRCMF_MAXPMKID) {
3850 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3851 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3852 if (i == npmk) {
3853 npmk++;
3854 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003855 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003856 } else {
3857 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3858 return -EINVAL;
3859 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003860
Hante Meuleman6c404f32015-12-10 13:43:03 +01003861 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3862 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3863 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3864 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3865 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003866
Hante Meuleman6c404f32015-12-10 13:43:03 +01003867 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003868
Arend van Sprield96b8012012-12-05 15:26:02 +01003869 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003870 return err;
3871}
3872
3873static s32
3874brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003875 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003876{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003877 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003878 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003879 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3880 s32 err;
3881 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003882
Arend van Sprield96b8012012-12-05 15:26:02 +01003883 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003884 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003885 return -EIO;
3886
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003887 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003888
Hante Meuleman6c404f32015-12-10 13:43:03 +01003889 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3890 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003891 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003892 break;
3893
Hante Meuleman6c404f32015-12-10 13:43:03 +01003894 if ((npmk > 0) && (i < npmk)) {
3895 for (; i < (npmk - 1); i++) {
3896 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3897 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003898 WLAN_PMKID_LEN);
3899 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003900 memset(&pmk[i], 0, sizeof(*pmk));
3901 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3902 } else {
3903 brcmf_err("Cache entry not found\n");
3904 return -EINVAL;
3905 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003906
Hante Meuleman6c404f32015-12-10 13:43:03 +01003907 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003908
Arend van Sprield96b8012012-12-05 15:26:02 +01003909 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003910 return err;
3911
3912}
3913
3914static s32
3915brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3916{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003917 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003918 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003919 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003920
Arend van Sprield96b8012012-12-05 15:26:02 +01003921 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003922 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003923 return -EIO;
3924
Hante Meuleman6c404f32015-12-10 13:43:03 +01003925 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3926 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003927
Arend van Sprield96b8012012-12-05 15:26:02 +01003928 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003929 return err;
3930
3931}
3932
Hante Meuleman1f170112013-02-06 18:40:38 +01003933static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003934{
3935 s32 err;
3936
3937 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003938 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003939 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003940 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003941 return err;
3942 }
3943 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003944 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003945 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003946 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003947 return err;
3948 }
3949 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003950 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003951 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003952 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003953 return err;
3954 }
3955
3956 return 0;
3957}
3958
3959static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3960{
3961 if (is_rsn_ie)
3962 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3963
3964 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3965}
3966
3967static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003968brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003969 const struct brcmf_vs_tlv *wpa_ie,
3970 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003971{
3972 u32 auth = 0; /* d11 open authentication */
3973 u16 count;
3974 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003975 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003976 u32 i;
3977 u32 wsec;
3978 u32 pval = 0;
3979 u32 gval = 0;
3980 u32 wpa_auth = 0;
3981 u32 offset;
3982 u8 *data;
3983 u16 rsn_cap;
3984 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003985 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003986
Arend van Sprield96b8012012-12-05 15:26:02 +01003987 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 if (wpa_ie == NULL)
3989 goto exit;
3990
3991 len = wpa_ie->len + TLV_HDR_LEN;
3992 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003993 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003994 if (!is_rsn_ie)
3995 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003996 else
3997 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003998
3999 /* check for multicast cipher suite */
4000 if (offset + WPA_IE_MIN_OUI_LEN > len) {
4001 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004002 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004003 goto exit;
4004 }
4005
4006 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4007 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004008 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004009 goto exit;
4010 }
4011 offset += TLV_OUI_LEN;
4012
4013 /* pick up multicast cipher */
4014 switch (data[offset]) {
4015 case WPA_CIPHER_NONE:
4016 gval = 0;
4017 break;
4018 case WPA_CIPHER_WEP_40:
4019 case WPA_CIPHER_WEP_104:
4020 gval = WEP_ENABLED;
4021 break;
4022 case WPA_CIPHER_TKIP:
4023 gval = TKIP_ENABLED;
4024 break;
4025 case WPA_CIPHER_AES_CCM:
4026 gval = AES_ENABLED;
4027 break;
4028 default:
4029 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004030 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004031 goto exit;
4032 }
4033
4034 offset++;
4035 /* walk thru unicast cipher list and pick up what we recognize */
4036 count = data[offset] + (data[offset + 1] << 8);
4037 offset += WPA_IE_SUITE_COUNT_LEN;
4038 /* Check for unicast suite(s) */
4039 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4040 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004041 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004042 goto exit;
4043 }
4044 for (i = 0; i < count; i++) {
4045 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4046 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004047 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004048 goto exit;
4049 }
4050 offset += TLV_OUI_LEN;
4051 switch (data[offset]) {
4052 case WPA_CIPHER_NONE:
4053 break;
4054 case WPA_CIPHER_WEP_40:
4055 case WPA_CIPHER_WEP_104:
4056 pval |= WEP_ENABLED;
4057 break;
4058 case WPA_CIPHER_TKIP:
4059 pval |= TKIP_ENABLED;
4060 break;
4061 case WPA_CIPHER_AES_CCM:
4062 pval |= AES_ENABLED;
4063 break;
4064 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004065 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004066 }
4067 offset++;
4068 }
4069 /* walk thru auth management suite list and pick up what we recognize */
4070 count = data[offset] + (data[offset + 1] << 8);
4071 offset += WPA_IE_SUITE_COUNT_LEN;
4072 /* Check for auth key management suite(s) */
4073 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4074 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004075 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004076 goto exit;
4077 }
4078 for (i = 0; i < count; i++) {
4079 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4080 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004081 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004082 goto exit;
4083 }
4084 offset += TLV_OUI_LEN;
4085 switch (data[offset]) {
4086 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004087 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004088 wpa_auth |= WPA_AUTH_NONE;
4089 break;
4090 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004091 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004092 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4093 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4094 break;
4095 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004096 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004097 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4098 (wpa_auth |= WPA_AUTH_PSK);
4099 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004100 case RSN_AKM_SHA256_PSK:
4101 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4102 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4103 break;
4104 case RSN_AKM_SHA256_1X:
4105 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4106 wpa_auth |= WPA2_AUTH_1X_SHA256;
4107 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004108 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004109 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004110 }
4111 offset++;
4112 }
4113
Hante Meuleman240d61a2016-02-17 11:27:10 +01004114 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004115 if (is_rsn_ie) {
4116 wme_bss_disable = 1;
4117 if ((offset + RSN_CAP_LEN) <= len) {
4118 rsn_cap = data[offset] + (data[offset + 1] << 8);
4119 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4120 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004121 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4122 brcmf_dbg(TRACE, "MFP Required\n");
4123 mfp = BRCMF_MFP_REQUIRED;
4124 /* Firmware only supports mfp required in
4125 * combination with WPA2_AUTH_PSK_SHA256 or
4126 * WPA2_AUTH_1X_SHA256.
4127 */
4128 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4129 WPA2_AUTH_1X_SHA256))) {
4130 err = -EINVAL;
4131 goto exit;
4132 }
4133 /* Firmware has requirement that WPA2_AUTH_PSK/
4134 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4135 * is to be included in the rsn ie.
4136 */
4137 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4138 wpa_auth |= WPA2_AUTH_PSK;
4139 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4140 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4141 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4142 brcmf_dbg(TRACE, "MFP Capable\n");
4143 mfp = BRCMF_MFP_CAPABLE;
4144 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004145 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004146 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004147 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004148 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004149 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004150 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004151 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004152 goto exit;
4153 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004154
4155 /* Skip PMKID cnt as it is know to be 0 for AP. */
4156 offset += RSN_PMKID_COUNT_LEN;
4157
4158 /* See if there is BIP wpa suite left for MFP */
4159 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4160 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4161 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4162 &data[offset],
4163 WPA_IE_MIN_OUI_LEN);
4164 if (err < 0) {
4165 brcmf_err("bip error %d\n", err);
4166 goto exit;
4167 }
4168 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004169 }
4170 /* FOR WPS , set SES_OW_ENABLED */
4171 wsec = (pval | gval | SES_OW_ENABLED);
4172
4173 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004174 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004175 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004176 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004177 goto exit;
4178 }
4179 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004180 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004181 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004182 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004183 goto exit;
4184 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004185 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4186 * will overwrite the values set by MFP
4187 */
4188 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4189 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4190 if (err < 0) {
4191 brcmf_err("mfp error %d\n", err);
4192 goto exit;
4193 }
4194 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004195 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004196 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004197 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004198 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004199 goto exit;
4200 }
4201
4202exit:
4203 return err;
4204}
4205
4206static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004207brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004208 struct parsed_vndr_ies *vndr_ies)
4209{
Hante Meuleman1a873342012-09-27 14:17:54 +02004210 struct brcmf_vs_tlv *vndrie;
4211 struct brcmf_tlv *ie;
4212 struct parsed_vndr_ie_info *parsed_info;
4213 s32 remaining_len;
4214
4215 remaining_len = (s32)vndr_ie_len;
4216 memset(vndr_ies, 0, sizeof(*vndr_ies));
4217
4218 ie = (struct brcmf_tlv *)vndr_ie_buf;
4219 while (ie) {
4220 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4221 goto next;
4222 vndrie = (struct brcmf_vs_tlv *)ie;
4223 /* len should be bigger than OUI length + one */
4224 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004225 brcmf_err("invalid vndr ie. length is too small %d\n",
4226 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004227 goto next;
4228 }
4229 /* if wpa or wme ie, do not add ie */
4230 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4231 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4232 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004233 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004234 goto next;
4235 }
4236
4237 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4238
4239 /* save vndr ie information */
4240 parsed_info->ie_ptr = (char *)vndrie;
4241 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4242 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4243
4244 vndr_ies->count++;
4245
Arend van Sprield96b8012012-12-05 15:26:02 +01004246 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4247 parsed_info->vndrie.oui[0],
4248 parsed_info->vndrie.oui[1],
4249 parsed_info->vndrie.oui[2],
4250 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004251
Arend van Spriel9f440b72013-02-08 15:53:36 +01004252 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004253 break;
4254next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004255 remaining_len -= (ie->len + TLV_HDR_LEN);
4256 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004257 ie = NULL;
4258 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004259 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4260 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004261 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004262 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004263}
4264
4265static u32
4266brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4267{
4268
Hante Meuleman1a873342012-09-27 14:17:54 +02004269 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4270 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4271
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304272 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004273
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304274 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004275
4276 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4277
4278 return ie_len + VNDR_IE_HDR_SIZE;
4279}
4280
Arend van Spriel1332e262012-11-05 16:22:18 -08004281s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4282 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004283{
Arend van Spriel1332e262012-11-05 16:22:18 -08004284 struct brcmf_if *ifp;
4285 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004286 s32 err = 0;
4287 u8 *iovar_ie_buf;
4288 u8 *curr_ie_buf;
4289 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004290 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004291 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004292 u32 del_add_ie_buf_len = 0;
4293 u32 total_ie_buf_len = 0;
4294 u32 parsed_ie_buf_len = 0;
4295 struct parsed_vndr_ies old_vndr_ies;
4296 struct parsed_vndr_ies new_vndr_ies;
4297 struct parsed_vndr_ie_info *vndrie_info;
4298 s32 i;
4299 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004300 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004301
Arend van Spriel1332e262012-11-05 16:22:18 -08004302 if (!vif)
4303 return -ENODEV;
4304 ifp = vif->ifp;
4305 saved_ie = &vif->saved_ie;
4306
Hante Meuleman37a869e2015-10-29 20:33:17 +01004307 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4308 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004309 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4310 if (!iovar_ie_buf)
4311 return -ENOMEM;
4312 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004313 switch (pktflag) {
4314 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4315 mgmt_ie_buf = saved_ie->probe_req_ie;
4316 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4317 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4318 break;
4319 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4320 mgmt_ie_buf = saved_ie->probe_res_ie;
4321 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4322 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4323 break;
4324 case BRCMF_VNDR_IE_BEACON_FLAG:
4325 mgmt_ie_buf = saved_ie->beacon_ie;
4326 mgmt_ie_len = &saved_ie->beacon_ie_len;
4327 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4328 break;
4329 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4330 mgmt_ie_buf = saved_ie->assoc_req_ie;
4331 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4332 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4333 break;
4334 default:
4335 err = -EPERM;
4336 brcmf_err("not suitable type\n");
4337 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004338 }
4339
4340 if (vndr_ie_len > mgmt_ie_buf_len) {
4341 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004342 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004343 goto exit;
4344 }
4345
4346 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4347 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4348 ptr = curr_ie_buf;
4349 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4350 for (i = 0; i < new_vndr_ies.count; i++) {
4351 vndrie_info = &new_vndr_ies.ie_info[i];
4352 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4353 vndrie_info->ie_len);
4354 parsed_ie_buf_len += vndrie_info->ie_len;
4355 }
4356 }
4357
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004358 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004359 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4360 (memcmp(mgmt_ie_buf, curr_ie_buf,
4361 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004362 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004363 goto exit;
4364 }
4365
4366 /* parse old vndr_ie */
4367 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4368
4369 /* make a command to delete old ie */
4370 for (i = 0; i < old_vndr_ies.count; i++) {
4371 vndrie_info = &old_vndr_ies.ie_info[i];
4372
Arend van Sprield96b8012012-12-05 15:26:02 +01004373 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4374 vndrie_info->vndrie.id,
4375 vndrie_info->vndrie.len,
4376 vndrie_info->vndrie.oui[0],
4377 vndrie_info->vndrie.oui[1],
4378 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004379
4380 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4381 vndrie_info->ie_ptr,
4382 vndrie_info->ie_len,
4383 "del");
4384 curr_ie_buf += del_add_ie_buf_len;
4385 total_ie_buf_len += del_add_ie_buf_len;
4386 }
4387 }
4388
4389 *mgmt_ie_len = 0;
4390 /* Add if there is any extra IE */
4391 if (mgmt_ie_buf && parsed_ie_buf_len) {
4392 ptr = mgmt_ie_buf;
4393
4394 remained_buf_len = mgmt_ie_buf_len;
4395
4396 /* make a command to add new ie */
4397 for (i = 0; i < new_vndr_ies.count; i++) {
4398 vndrie_info = &new_vndr_ies.ie_info[i];
4399
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004400 /* verify remained buf size before copy data */
4401 if (remained_buf_len < (vndrie_info->vndrie.len +
4402 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004403 brcmf_err("no space in mgmt_ie_buf: len left %d",
4404 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004405 break;
4406 }
4407 remained_buf_len -= (vndrie_info->ie_len +
4408 VNDR_IE_VSIE_OFFSET);
4409
Arend van Sprield96b8012012-12-05 15:26:02 +01004410 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4411 vndrie_info->vndrie.id,
4412 vndrie_info->vndrie.len,
4413 vndrie_info->vndrie.oui[0],
4414 vndrie_info->vndrie.oui[1],
4415 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004416
4417 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4418 vndrie_info->ie_ptr,
4419 vndrie_info->ie_len,
4420 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004421
4422 /* save the parsed IE in wl struct */
4423 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4424 vndrie_info->ie_len);
4425 *mgmt_ie_len += vndrie_info->ie_len;
4426
4427 curr_ie_buf += del_add_ie_buf_len;
4428 total_ie_buf_len += del_add_ie_buf_len;
4429 }
4430 }
4431 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004432 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004433 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004434 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004435 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004436 }
4437
4438exit:
4439 kfree(iovar_ie_buf);
4440 return err;
4441}
4442
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004443s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4444{
4445 s32 pktflags[] = {
4446 BRCMF_VNDR_IE_PRBREQ_FLAG,
4447 BRCMF_VNDR_IE_PRBRSP_FLAG,
4448 BRCMF_VNDR_IE_BEACON_FLAG
4449 };
4450 int i;
4451
4452 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4453 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4454
4455 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4456 return 0;
4457}
4458
Hante Meuleman1a873342012-09-27 14:17:54 +02004459static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004460brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4461 struct cfg80211_beacon_data *beacon)
4462{
4463 s32 err;
4464
4465 /* Set Beacon IEs to FW */
4466 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4467 beacon->tail, beacon->tail_len);
4468 if (err) {
4469 brcmf_err("Set Beacon IE Failed\n");
4470 return err;
4471 }
4472 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4473
4474 /* Set Probe Response IEs to FW */
4475 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4476 beacon->proberesp_ies,
4477 beacon->proberesp_ies_len);
4478 if (err)
4479 brcmf_err("Set Probe Resp IE Failed\n");
4480 else
4481 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4482
4483 return err;
4484}
4485
4486static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004487brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4488 struct cfg80211_ap_settings *settings)
4489{
4490 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004491 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004492 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004493 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004494 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004495 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004496 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004497 const struct brcmf_tlv *rsn_ie;
4498 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004499 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004500 enum nl80211_iftype dev_role;
4501 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004502 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004503 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004504 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004505 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004506
Arend van Spriel06c01582014-05-12 10:47:37 +02004507 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4508 settings->chandef.chan->hw_value,
4509 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004510 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004511 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4512 settings->ssid, settings->ssid_len, settings->auth_type,
4513 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004514 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004515 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004516
Arend van Spriel98027762014-12-21 12:43:53 +01004517 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004518 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4519 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004520 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004521 } else {
4522 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4523 settings->beacon.tail_len,
4524 WLAN_EID_COUNTRY);
4525 is_11d = country_ie ? 1 : 0;
4526 supports_11d = true;
4527 }
Arend van Spriel98027762014-12-21 12:43:53 +01004528
Hante Meuleman1a873342012-09-27 14:17:54 +02004529 memset(&ssid_le, 0, sizeof(ssid_le));
4530 if (settings->ssid == NULL || settings->ssid_len == 0) {
4531 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4532 ssid_ie = brcmf_parse_tlvs(
4533 (u8 *)&settings->beacon.head[ie_offset],
4534 settings->beacon.head_len - ie_offset,
4535 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004536 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004537 return -EINVAL;
4538
4539 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4540 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004541 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004542 } else {
4543 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4544 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4545 }
4546
Hante Meulemana44aa402014-12-03 21:05:33 +01004547 if (!mbss) {
4548 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004549 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004550 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004551
4552 /* find the RSN_IE */
4553 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4554 settings->beacon.tail_len, WLAN_EID_RSN);
4555
4556 /* find the WPA_IE */
4557 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4558 settings->beacon.tail_len);
4559
Hante Meuleman1a873342012-09-27 14:17:54 +02004560 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004561 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004562 if (wpa_ie != NULL) {
4563 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004564 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004565 if (err < 0)
4566 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004567 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004568 struct brcmf_vs_tlv *tmp_ie;
4569
4570 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4571
Hante Meuleman1a873342012-09-27 14:17:54 +02004572 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004573 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 if (err < 0)
4575 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004576 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004577 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004578 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004579 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004580 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004581
Hante Meulemana0f07952013-02-08 15:53:47 +01004582 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004583
Rafał Miłecki8707e082016-05-27 21:07:19 +02004584 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004585 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004586 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004587 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4588 is_11d);
4589 if (err < 0) {
4590 brcmf_err("Regulatory Set Error, %d\n", err);
4591 goto exit;
4592 }
4593 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004594 if (settings->beacon_interval) {
4595 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4596 settings->beacon_interval);
4597 if (err < 0) {
4598 brcmf_err("Beacon Interval Set Error, %d\n",
4599 err);
4600 goto exit;
4601 }
4602 }
4603 if (settings->dtim_period) {
4604 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4605 settings->dtim_period);
4606 if (err < 0) {
4607 brcmf_err("DTIM Interval Set Error, %d\n", err);
4608 goto exit;
4609 }
4610 }
4611
Hante Meuleman8abffd82015-10-29 20:33:16 +01004612 if ((dev_role == NL80211_IFTYPE_AP) &&
4613 ((ifp->ifidx == 0) ||
4614 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004615 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4616 if (err < 0) {
4617 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4618 goto exit;
4619 }
4620 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4621 }
4622
4623 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004624 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004625 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004626 goto exit;
4627 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004628 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004629 /* Multiple-BSS should use same 11d configuration */
4630 err = -EINVAL;
4631 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004632 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004633
4634 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004635 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004636 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4637 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4638
Hante Meulemana0f07952013-02-08 15:53:47 +01004639 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4640 if (err < 0) {
4641 brcmf_err("setting AP mode failed %d\n", err);
4642 goto exit;
4643 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004644 if (!mbss) {
4645 /* Firmware 10.x requires setting channel after enabling
4646 * AP and before bringing interface up.
4647 */
4648 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4649 if (err < 0) {
4650 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4651 chanspec, err);
4652 goto exit;
4653 }
4654 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004655 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4656 if (err < 0) {
4657 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4658 goto exit;
4659 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004660 /* On DOWN the firmware removes the WEP keys, reconfigure
4661 * them if they were set.
4662 */
4663 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004664
4665 memset(&join_params, 0, sizeof(join_params));
4666 /* join parameters starts with ssid */
4667 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4668 /* create softap */
4669 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4670 &join_params, sizeof(join_params));
4671 if (err < 0) {
4672 brcmf_err("SET SSID error (%d)\n", err);
4673 goto exit;
4674 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004675
4676 if (settings->hidden_ssid) {
4677 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4678 if (err) {
4679 brcmf_err("closednet error (%d)\n", err);
4680 goto exit;
4681 }
4682 }
4683
Hante Meulemana0f07952013-02-08 15:53:47 +01004684 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004685 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4686 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4687 if (err < 0) {
4688 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4689 chanspec, err);
4690 goto exit;
4691 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004692 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4693 sizeof(ssid_le));
4694 if (err < 0) {
4695 brcmf_err("setting ssid failed %d\n", err);
4696 goto exit;
4697 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004698 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004699 bss_enable.enable = cpu_to_le32(1);
4700 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4701 sizeof(bss_enable));
4702 if (err < 0) {
4703 brcmf_err("bss_enable config failed %d\n", err);
4704 goto exit;
4705 }
4706
4707 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004708 } else {
4709 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004710 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004711
Arend van Sprielc1179032012-10-22 13:55:33 -07004712 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004713 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004714
4715exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004716 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004717 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004718 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004719 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004720 return err;
4721}
4722
4723static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4724{
Arend van Sprielc1179032012-10-22 13:55:33 -07004725 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004726 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004727 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004728 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004729
Arend van Sprield96b8012012-12-05 15:26:02 +01004730 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004731
Hante Meuleman426d0a52013-02-08 15:53:53 +01004732 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004733 /* Due to most likely deauths outstanding we sleep */
4734 /* first to make sure they get processed by fw. */
4735 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004736
Hante Meulemana44aa402014-12-03 21:05:33 +01004737 if (ifp->vif->mbss) {
4738 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4739 return err;
4740 }
4741
Rafał Miłeckic940de12016-07-06 12:22:54 +02004742 /* First BSS doesn't get a full reset */
4743 if (ifp->bsscfgidx == 0)
4744 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4745
Hante Meuleman5c33a942013-04-02 21:06:18 +02004746 memset(&join_params, 0, sizeof(join_params));
4747 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4748 &join_params, sizeof(join_params));
4749 if (err < 0)
4750 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004751 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004752 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004753 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004754 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4755 if (err < 0)
4756 brcmf_err("setting AP mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004757 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4758 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004759 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4760 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004761 /* Bring device back up so it can be used again */
4762 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4763 if (err < 0)
4764 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004765 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004766 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004767 bss_enable.enable = cpu_to_le32(0);
4768 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4769 sizeof(bss_enable));
4770 if (err < 0)
4771 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004772 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004773 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004774 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004775 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004776 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004777
Hante Meuleman1a873342012-09-27 14:17:54 +02004778 return err;
4779}
4780
Hante Meulemana0f07952013-02-08 15:53:47 +01004781static s32
4782brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4783 struct cfg80211_beacon_data *info)
4784{
Hante Meulemana0f07952013-02-08 15:53:47 +01004785 struct brcmf_if *ifp = netdev_priv(ndev);
4786 s32 err;
4787
4788 brcmf_dbg(TRACE, "Enter\n");
4789
Hante Meulemana0f07952013-02-08 15:53:47 +01004790 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4791
4792 return err;
4793}
4794
Hante Meuleman1a873342012-09-27 14:17:54 +02004795static int
4796brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004797 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004798{
Hante Meulemana0f07952013-02-08 15:53:47 +01004799 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004800 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004801 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004802 s32 err;
4803
Jouni Malinen89c771e2014-10-10 20:52:40 +03004804 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004805 return -EFAULT;
4806
Jouni Malinen89c771e2014-10-10 20:52:40 +03004807 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004808
Hante Meulemana0f07952013-02-08 15:53:47 +01004809 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4810 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004811 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004812 return -EIO;
4813
Jouni Malinen89c771e2014-10-10 20:52:40 +03004814 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004815 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004816 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004817 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004818 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004819 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004820
Arend van Sprield96b8012012-12-05 15:26:02 +01004821 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004822 return err;
4823}
4824
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004825static int
4826brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4827 const u8 *mac, struct station_parameters *params)
4828{
4829 struct brcmf_if *ifp = netdev_priv(ndev);
4830 s32 err;
4831
4832 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4833 params->sta_flags_mask, params->sta_flags_set);
4834
4835 /* Ignore all 00 MAC */
4836 if (is_zero_ether_addr(mac))
4837 return 0;
4838
4839 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4840 return 0;
4841
4842 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4843 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4844 (void *)mac, ETH_ALEN);
4845 else
4846 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4847 (void *)mac, ETH_ALEN);
4848 if (err < 0)
4849 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4850
4851 return err;
4852}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004853
4854static void
4855brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4856 struct wireless_dev *wdev,
4857 u16 frame_type, bool reg)
4858{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004859 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004860 u16 mgmt_type;
4861
4862 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4863
4864 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004865 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004866 if (reg)
4867 vif->mgmt_rx_reg |= BIT(mgmt_type);
4868 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004869 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004870}
4871
4872
4873static int
4874brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004875 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004876{
4877 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004878 struct ieee80211_channel *chan = params->chan;
4879 const u8 *buf = params->buf;
4880 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004881 const struct ieee80211_mgmt *mgmt;
4882 struct brcmf_cfg80211_vif *vif;
4883 s32 err = 0;
4884 s32 ie_offset;
4885 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004886 struct brcmf_fil_action_frame_le *action_frame;
4887 struct brcmf_fil_af_params_le *af_params;
4888 bool ack;
4889 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004890 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004891
4892 brcmf_dbg(TRACE, "Enter\n");
4893
4894 *cookie = 0;
4895
4896 mgmt = (const struct ieee80211_mgmt *)buf;
4897
Hante Meulemana0f07952013-02-08 15:53:47 +01004898 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4899 brcmf_err("Driver only allows MGMT packet type\n");
4900 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004901 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004902
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004903 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4904
Hante Meulemana0f07952013-02-08 15:53:47 +01004905 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4906 /* Right now the only reason to get a probe response */
4907 /* is for p2p listen response or for p2p GO from */
4908 /* wpa_supplicant. Unfortunately the probe is send */
4909 /* on primary ndev, while dongle wants it on the p2p */
4910 /* vif. Since this is only reason for a probe */
4911 /* response to be sent, the vif is taken from cfg. */
4912 /* If ever desired to send proberesp for non p2p */
4913 /* response then data should be checked for */
4914 /* "DIRECT-". Note in future supplicant will take */
4915 /* dedicated p2p wdev to do this and then this 'hack'*/
4916 /* is not needed anymore. */
4917 ie_offset = DOT11_MGMT_HDR_LEN +
4918 DOT11_BCN_PRB_FIXED_LEN;
4919 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004920 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4921 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4922 err = brcmf_vif_set_mgmt_ie(vif,
4923 BRCMF_VNDR_IE_PRBRSP_FLAG,
4924 &buf[ie_offset],
4925 ie_len);
4926 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4927 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004928 } else if (ieee80211_is_action(mgmt->frame_control)) {
Arend van Spriel414848b2017-07-07 21:09:06 +01004929 if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
4930 brcmf_err("invalid action frame length\n");
4931 err = -EINVAL;
4932 goto exit;
4933 }
Hante Meuleman18e2f612013-02-08 15:53:49 +01004934 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4935 if (af_params == NULL) {
4936 brcmf_err("unable to allocate frame\n");
4937 err = -ENOMEM;
4938 goto exit;
4939 }
4940 action_frame = &af_params->action_frame;
4941 /* Add the packet Id */
4942 action_frame->packet_id = cpu_to_le32(*cookie);
4943 /* Add BSSID */
4944 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4945 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4946 /* Add the length exepted for 802.11 header */
4947 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004948 /* Add the channel. Use the one specified as parameter if any or
4949 * the current one (got from the firmware) otherwise
4950 */
4951 if (chan)
4952 freq = chan->center_freq;
4953 else
4954 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4955 &freq);
4956 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004957 af_params->channel = cpu_to_le32(chan_nr);
4958
4959 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4960 le16_to_cpu(action_frame->len));
4961
4962 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004963 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004964
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004965 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004966 af_params);
4967
4968 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4969 GFP_KERNEL);
4970 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004971 } else {
4972 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4973 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4974 }
4975
Hante Meuleman18e2f612013-02-08 15:53:49 +01004976exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004977 return err;
4978}
4979
4980
4981static int
4982brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4983 struct wireless_dev *wdev,
4984 u64 cookie)
4985{
4986 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4987 struct brcmf_cfg80211_vif *vif;
4988 int err = 0;
4989
4990 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4991
4992 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4993 if (vif == NULL) {
4994 brcmf_err("No p2p device available for probe response\n");
4995 err = -ENODEV;
4996 goto exit;
4997 }
4998 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4999exit:
5000 return err;
5001}
5002
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005003static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
5004 struct wireless_dev *wdev,
5005 struct cfg80211_chan_def *chandef)
5006{
5007 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5008 struct net_device *ndev = wdev->netdev;
5009 struct brcmf_if *ifp;
5010 struct brcmu_chan ch;
5011 enum nl80211_band band = 0;
5012 enum nl80211_chan_width width = 0;
5013 u32 chanspec;
5014 int freq, err;
5015
5016 if (!ndev)
5017 return -ENODEV;
5018 ifp = netdev_priv(ndev);
5019
5020 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
5021 if (err) {
5022 brcmf_err("chanspec failed (%d)\n", err);
5023 return err;
5024 }
5025
5026 ch.chspec = chanspec;
5027 cfg->d11inf.decchspec(&ch);
5028
5029 switch (ch.band) {
5030 case BRCMU_CHAN_BAND_2G:
5031 band = NL80211_BAND_2GHZ;
5032 break;
5033 case BRCMU_CHAN_BAND_5G:
5034 band = NL80211_BAND_5GHZ;
5035 break;
5036 }
5037
5038 switch (ch.bw) {
5039 case BRCMU_CHAN_BW_80:
5040 width = NL80211_CHAN_WIDTH_80;
5041 break;
5042 case BRCMU_CHAN_BW_40:
5043 width = NL80211_CHAN_WIDTH_40;
5044 break;
5045 case BRCMU_CHAN_BW_20:
5046 width = NL80211_CHAN_WIDTH_20;
5047 break;
5048 case BRCMU_CHAN_BW_80P80:
5049 width = NL80211_CHAN_WIDTH_80P80;
5050 break;
5051 case BRCMU_CHAN_BW_160:
5052 width = NL80211_CHAN_WIDTH_160;
5053 break;
5054 }
5055
5056 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
5057 chandef->chan = ieee80211_get_channel(wiphy, freq);
5058 chandef->width = width;
5059 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
5060 chandef->center_freq2 = 0;
5061
5062 return 0;
5063}
5064
Piotr Haber61730d42013-04-23 12:53:12 +02005065static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
5066 struct wireless_dev *wdev,
5067 enum nl80211_crit_proto_id proto,
5068 u16 duration)
5069{
5070 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5071 struct brcmf_cfg80211_vif *vif;
5072
5073 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5074
5075 /* only DHCP support for now */
5076 if (proto != NL80211_CRIT_PROTO_DHCP)
5077 return -EINVAL;
5078
5079 /* suppress and abort scanning */
5080 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5081 brcmf_abort_scanning(cfg);
5082
5083 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5084}
5085
5086static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5087 struct wireless_dev *wdev)
5088{
5089 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5090 struct brcmf_cfg80211_vif *vif;
5091
5092 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5093
5094 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5095 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5096}
5097
Hante Meuleman70b7d942014-07-30 13:20:07 +02005098static s32
5099brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5100 const struct brcmf_event_msg *e, void *data)
5101{
5102 switch (e->reason) {
5103 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5104 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5105 break;
5106 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5107 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5108 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5109 break;
5110 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5111 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5112 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5113 break;
5114 }
5115
5116 return 0;
5117}
5118
Arend van Spriel89c2f382013-08-10 12:27:25 +02005119static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5120{
5121 int ret;
5122
5123 switch (oper) {
5124 case NL80211_TDLS_DISCOVERY_REQ:
5125 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5126 break;
5127 case NL80211_TDLS_SETUP:
5128 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5129 break;
5130 case NL80211_TDLS_TEARDOWN:
5131 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5132 break;
5133 default:
5134 brcmf_err("unsupported operation: %d\n", oper);
5135 ret = -EOPNOTSUPP;
5136 }
5137 return ret;
5138}
5139
5140static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005141 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005142 enum nl80211_tdls_operation oper)
5143{
5144 struct brcmf_if *ifp;
5145 struct brcmf_tdls_iovar_le info;
5146 int ret = 0;
5147
5148 ret = brcmf_convert_nl80211_tdls_oper(oper);
5149 if (ret < 0)
5150 return ret;
5151
5152 ifp = netdev_priv(ndev);
5153 memset(&info, 0, sizeof(info));
5154 info.mode = (u8)ret;
5155 if (peer)
5156 memcpy(info.ea, peer, ETH_ALEN);
5157
5158 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5159 &info, sizeof(info));
5160 if (ret < 0)
5161 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5162
5163 return ret;
5164}
5165
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005166#ifdef CONFIG_PM
5167static int
5168brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5169 struct cfg80211_gtk_rekey_data *gtk)
5170{
5171 struct brcmf_if *ifp = netdev_priv(ndev);
5172 struct brcmf_gtk_keyinfo_le gtk_le;
5173 int ret;
5174
5175 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5176
5177 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5178 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5179 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5180 sizeof(gtk_le.replay_counter));
5181
5182 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5183 sizeof(gtk_le));
5184 if (ret < 0)
5185 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5186
5187 return ret;
5188}
5189#endif
5190
5191static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005192 .add_virtual_intf = brcmf_cfg80211_add_iface,
5193 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005194 .change_virtual_intf = brcmf_cfg80211_change_iface,
5195 .scan = brcmf_cfg80211_scan,
5196 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5197 .join_ibss = brcmf_cfg80211_join_ibss,
5198 .leave_ibss = brcmf_cfg80211_leave_ibss,
5199 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005200 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005201 .set_tx_power = brcmf_cfg80211_set_tx_power,
5202 .get_tx_power = brcmf_cfg80211_get_tx_power,
5203 .add_key = brcmf_cfg80211_add_key,
5204 .del_key = brcmf_cfg80211_del_key,
5205 .get_key = brcmf_cfg80211_get_key,
5206 .set_default_key = brcmf_cfg80211_config_default_key,
5207 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5208 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005209 .connect = brcmf_cfg80211_connect,
5210 .disconnect = brcmf_cfg80211_disconnect,
5211 .suspend = brcmf_cfg80211_suspend,
5212 .resume = brcmf_cfg80211_resume,
5213 .set_pmksa = brcmf_cfg80211_set_pmksa,
5214 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005215 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005216 .start_ap = brcmf_cfg80211_start_ap,
5217 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005218 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005219 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005220 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005221 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5222 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005223 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5224 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5225 .remain_on_channel = brcmf_p2p_remain_on_channel,
5226 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005227 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005228 .start_p2p_device = brcmf_p2p_start_device,
5229 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005230 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5231 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005232 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005233};
5234
Arend van Spriel3eacf862012-10-22 13:55:30 -07005235struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005236 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005237{
Hante Meulemana44aa402014-12-03 21:05:33 +01005238 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005239 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005240 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005241
Arend van Spriel33a6b152013-02-08 15:53:39 +01005242 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005243 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005244 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5245 if (!vif)
5246 return ERR_PTR(-ENOMEM);
5247
5248 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005249 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005250
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005251 brcmf_init_prof(&vif->profile);
5252
Hante Meulemana44aa402014-12-03 21:05:33 +01005253 if (type == NL80211_IFTYPE_AP) {
5254 mbss = false;
5255 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5256 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5257 mbss = true;
5258 break;
5259 }
5260 }
5261 vif->mbss = mbss;
5262 }
5263
Arend van Spriel3eacf862012-10-22 13:55:30 -07005264 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005265 return vif;
5266}
5267
Arend van Spriel427dec52014-01-06 12:40:47 +01005268void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005269{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005270 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005271 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005272}
5273
Arend van Spriel9df4d542014-01-06 12:40:49 +01005274void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5275{
5276 struct brcmf_cfg80211_vif *vif;
5277 struct brcmf_if *ifp;
5278
5279 ifp = netdev_priv(ndev);
5280 vif = ifp->vif;
5281
Arend van Spriel95ef1232015-08-26 22:15:04 +02005282 if (vif)
5283 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005284 free_netdev(ndev);
5285}
5286
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005287static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005288{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005289 u32 event = e->event_code;
5290 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005291
5292 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005293 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005294 return true;
5295 }
5296
5297 return false;
5298}
5299
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005300static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005301{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005302 u32 event = e->event_code;
5303 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005304
Hante Meuleman68ca3952014-02-25 20:30:26 +01005305 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5306 (event == BRCMF_E_DISASSOC_IND) ||
5307 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005308 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005309 return true;
5310 }
5311 return false;
5312}
5313
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005314static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005315 const struct brcmf_event_msg *e)
5316{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005317 u32 event = e->event_code;
5318 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005319
5320 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005321 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5322 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005323 return true;
5324 }
5325
5326 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005327 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328 return true;
5329 }
5330
5331 return false;
5332}
5333
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005334static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005335{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005336 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005337
5338 kfree(conn_info->req_ie);
5339 conn_info->req_ie = NULL;
5340 conn_info->req_ie_len = 0;
5341 kfree(conn_info->resp_ie);
5342 conn_info->resp_ie = NULL;
5343 conn_info->resp_ie_len = 0;
5344}
5345
Hante Meuleman89286dc2013-02-08 15:53:46 +01005346static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5347 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005349 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005350 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005351 u32 req_len;
5352 u32 resp_len;
5353 s32 err = 0;
5354
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005355 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005356
Arend van Sprielac24be62012-10-22 10:36:23 -07005357 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5358 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005359 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005360 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005361 return err;
5362 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005363 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005364 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005365 req_len = le32_to_cpu(assoc_info->req_len);
5366 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005367 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005368 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005369 cfg->extra_buf,
5370 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005371 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005372 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005373 return err;
5374 }
5375 conn_info->req_ie_len = req_len;
5376 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005377 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378 GFP_KERNEL);
5379 } else {
5380 conn_info->req_ie_len = 0;
5381 conn_info->req_ie = NULL;
5382 }
5383 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005384 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005385 cfg->extra_buf,
5386 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005387 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005388 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005389 return err;
5390 }
5391 conn_info->resp_ie_len = resp_len;
5392 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005393 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005394 GFP_KERNEL);
5395 } else {
5396 conn_info->resp_ie_len = 0;
5397 conn_info->resp_ie = NULL;
5398 }
Arend van Spriel16886732012-12-05 15:26:04 +01005399 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5400 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005401
5402 return err;
5403}
5404
5405static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005406brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005407 struct net_device *ndev,
5408 const struct brcmf_event_msg *e)
5409{
Arend van Sprielc1179032012-10-22 13:55:33 -07005410 struct brcmf_if *ifp = netdev_priv(ndev);
5411 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005412 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5413 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005414 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005416 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005417 struct brcmu_chan ch;
Avraham Stern9e841a62017-04-26 10:58:49 +03005418 struct cfg80211_roam_info roam_info = {};
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419 u32 freq;
5420 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005421 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005422
Arend van Sprield96b8012012-12-05 15:26:02 +01005423 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005424
Hante Meuleman89286dc2013-02-08 15:53:46 +01005425 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005426 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005427 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005428
Franky Lina180b832012-10-10 11:13:09 -07005429 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5430 if (buf == NULL) {
5431 err = -ENOMEM;
5432 goto done;
5433 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434
Franky Lina180b832012-10-10 11:13:09 -07005435 /* data sent to dongle has to be little endian */
5436 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005437 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005438 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005439
5440 if (err)
5441 goto done;
5442
5443 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005444 ch.chspec = le16_to_cpu(bi->chanspec);
5445 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005446
Franky Lin83cf17a2013-04-11 13:28:50 +02005447 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005448 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005450 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451
Rafał Miłecki4712d882016-05-20 13:38:57 +02005452 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005453 notify_channel = ieee80211_get_channel(wiphy, freq);
5454
Franky Lina180b832012-10-10 11:13:09 -07005455done:
5456 kfree(buf);
Avraham Stern9e841a62017-04-26 10:58:49 +03005457
5458 roam_info.channel = notify_channel;
5459 roam_info.bssid = profile->bssid;
5460 roam_info.req_ie = conn_info->req_ie;
5461 roam_info.req_ie_len = conn_info->req_ie_len;
5462 roam_info.resp_ie = conn_info->resp_ie;
5463 roam_info.resp_ie_len = conn_info->resp_ie_len;
5464
5465 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005466 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005467
Arend van Sprielc1179032012-10-22 13:55:33 -07005468 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005469 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005470 return err;
5471}
5472
5473static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005474brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005475 struct net_device *ndev, const struct brcmf_event_msg *e,
5476 bool completed)
5477{
Arend van Sprielc1179032012-10-22 13:55:33 -07005478 struct brcmf_if *ifp = netdev_priv(ndev);
5479 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005480 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005481
Arend van Sprield96b8012012-12-05 15:26:02 +01005482 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005483
Arend van Sprielc1179032012-10-22 13:55:33 -07005484 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5485 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005486 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005487 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005488 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005489 brcmf_update_bss_info(cfg, ifp);
5490 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5491 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005492 }
5493 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005494 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005495 conn_info->req_ie,
5496 conn_info->req_ie_len,
5497 conn_info->resp_ie,
5498 conn_info->resp_ie_len,
5499 completed ? WLAN_STATUS_SUCCESS :
5500 WLAN_STATUS_AUTH_TIMEOUT,
5501 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005502 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5503 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005504 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005505 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005506 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005507}
5508
5509static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005510brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005511 struct net_device *ndev,
5512 const struct brcmf_event_msg *e, void *data)
5513{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005514 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005515 u32 event = e->event_code;
5516 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005517 struct station_info sinfo;
5518
Arend van Spriel16886732012-12-05 15:26:04 +01005519 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005520 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5521 ndev != cfg_to_ndev(cfg)) {
5522 brcmf_dbg(CONN, "AP mode link down\n");
5523 complete(&cfg->vif_disabled);
5524 return 0;
5525 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005526
Hante Meuleman1a873342012-09-27 14:17:54 +02005527 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005528 (reason == BRCMF_E_STATUS_SUCCESS)) {
5529 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005530 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005531 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005532 return -EINVAL;
5533 }
5534 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005535 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005536 generation++;
5537 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005538 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005539 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5540 (event == BRCMF_E_DEAUTH_IND) ||
5541 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005542 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005543 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005544 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005545}
5546
5547static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005548brcmf_notify_connect_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;
5552 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005553 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005554 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005555 s32 err = 0;
5556
Hante Meuleman8851cce2014-07-30 13:20:02 +02005557 if ((e->event_code == BRCMF_E_DEAUTH) ||
5558 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5559 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5560 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5561 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5562 }
5563
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005564 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005565 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005566 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005567 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005568 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005569 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005570 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005571 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005572 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005573 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5574 &ifp->vif->sme_state);
5575 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5576 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005577 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005578 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005579 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005580 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005581 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005582 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005583 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005584 brcmf_link_down(ifp->vif,
5585 brcmf_map_fw_linkdown_reason(e));
5586 brcmf_init_prof(ndev_to_prof(ndev));
5587 if (ndev != cfg_to_ndev(cfg))
5588 complete(&cfg->vif_disabled);
5589 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005590 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005591 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005592 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005593 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5594 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005595 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005596 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005597 }
5598
5599 return err;
5600}
5601
5602static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005603brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005604 const struct brcmf_event_msg *e, void *data)
5605{
Arend van Spriel19937322012-11-05 16:22:32 -08005606 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005607 u32 event = e->event_code;
5608 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005609
5610 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005611 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005612 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005613 else
Arend van Spriel19937322012-11-05 16:22:32 -08005614 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005615 }
5616
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005617 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005618}
5619
5620static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005621brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005622 const struct brcmf_event_msg *e, void *data)
5623{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005624 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005625 enum nl80211_key_type key_type;
5626
5627 if (flags & BRCMF_EVENT_MSG_GROUP)
5628 key_type = NL80211_KEYTYPE_GROUP;
5629 else
5630 key_type = NL80211_KEYTYPE_PAIRWISE;
5631
Arend van Spriel19937322012-11-05 16:22:32 -08005632 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005633 NULL, GFP_KERNEL);
5634
5635 return 0;
5636}
5637
Arend van Sprield3c0b632013-02-08 15:53:37 +01005638static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5639 const struct brcmf_event_msg *e, void *data)
5640{
5641 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5642 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5643 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5644 struct brcmf_cfg80211_vif *vif;
5645
Hante Meuleman37a869e2015-10-29 20:33:17 +01005646 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005647 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005648 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005649
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005650 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005651 event->action = ifevent->action;
5652 vif = event->vif;
5653
5654 switch (ifevent->action) {
5655 case BRCMF_E_IF_ADD:
5656 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005657 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005658 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005659 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005660 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005661
5662 ifp->vif = vif;
5663 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005664 if (ifp->ndev) {
5665 vif->wdev.netdev = ifp->ndev;
5666 ifp->ndev->ieee80211_ptr = &vif->wdev;
5667 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5668 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005669 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005670 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005671 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005672
5673 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005674 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005675 /* event may not be upon user request */
5676 if (brcmf_cfg80211_vif_event_armed(cfg))
5677 wake_up(&event->vif_wq);
5678 return 0;
5679
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005680 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005681 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005682 wake_up(&event->vif_wq);
5683 return 0;
5684
Arend van Sprield3c0b632013-02-08 15:53:37 +01005685 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005686 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005687 break;
5688 }
5689 return -EINVAL;
5690}
5691
Arend van Spriel5b435de2011-10-05 13:19:03 +02005692static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5693{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005694 conf->frag_threshold = (u32)-1;
5695 conf->rts_threshold = (u32)-1;
5696 conf->retry_short = (u32)-1;
5697 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005698}
5699
Arend van Spriel5c36b992012-11-14 18:46:05 -08005700static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005701{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005702 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5703 brcmf_notify_connect_status);
5704 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5705 brcmf_notify_connect_status);
5706 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5707 brcmf_notify_connect_status);
5708 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5709 brcmf_notify_connect_status);
5710 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5711 brcmf_notify_connect_status);
5712 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5713 brcmf_notify_connect_status);
5714 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5715 brcmf_notify_roaming_status);
5716 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5717 brcmf_notify_mic_status);
5718 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5719 brcmf_notify_connect_status);
5720 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5721 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005722 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5723 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005724 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005725 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005726 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5727 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005728 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5729 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005730 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5731 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005732 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5733 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005734}
5735
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005736static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005737{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005738 kfree(cfg->conf);
5739 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005740 kfree(cfg->extra_buf);
5741 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005742 kfree(cfg->wowl.nd);
5743 cfg->wowl.nd = NULL;
5744 kfree(cfg->wowl.nd_info);
5745 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005746 kfree(cfg->escan_info.escan_buf);
5747 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005748}
5749
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005750static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005751{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005752 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5753 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005754 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005755 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5756 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005757 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005758 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5759 if (!cfg->wowl.nd)
5760 goto init_priv_mem_out;
5761 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5762 sizeof(struct cfg80211_wowlan_nd_match *),
5763 GFP_KERNEL);
5764 if (!cfg->wowl.nd_info)
5765 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005766 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5767 if (!cfg->escan_info.escan_buf)
5768 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005769
5770 return 0;
5771
5772init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005773 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005774
5775 return -ENOMEM;
5776}
5777
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005778static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005779{
5780 s32 err = 0;
5781
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005782 cfg->scan_request = NULL;
5783 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005784 cfg->active_scan = true; /* we do active scan per default */
5785 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005786 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005787 if (err)
5788 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005789 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005790 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005791 brcmf_init_escan(cfg);
5792 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005793 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005794 return err;
5795}
5796
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005797static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005798{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005799 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005800 brcmf_abort_scanning(cfg);
5801 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005802}
5803
Arend van Sprield3c0b632013-02-08 15:53:37 +01005804static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5805{
5806 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005807 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005808}
5809
Hante Meuleman1119e232015-11-25 11:32:42 +01005810static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005811{
Hante Meuleman1119e232015-11-25 11:32:42 +01005812 s32 err;
5813 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005814 __le32 roamtrigger[2];
5815 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005816
Hante Meuleman1119e232015-11-25 11:32:42 +01005817 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005818 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005819 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5820 else
5821 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5822 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5823 if (err) {
5824 brcmf_err("bcn_timeout error (%d)\n", err);
5825 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005826 }
5827
Hante Meuleman1119e232015-11-25 11:32:42 +01005828 /* Enable/Disable built-in roaming to allow supplicant to take care of
5829 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005830 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005831 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005832 ifp->drvr->settings->roamoff ? "Off" : "On");
5833 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5834 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005835 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005836 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005837 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005838 }
5839
Arend van Sprielf588bc02011-10-12 20:51:22 +02005840 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5841 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005842 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005843 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005844 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005845 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005846 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005847 }
5848
Arend van Sprielf588bc02011-10-12 20:51:22 +02005849 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5850 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005852 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005853 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005854 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005855 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005856 }
5857
Hante Meuleman1119e232015-11-25 11:32:42 +01005858roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005859 return err;
5860}
5861
5862static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005863brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005864{
5865 s32 err = 0;
5866
Arend van Sprielac24be62012-10-22 10:36:23 -07005867 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005868 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005869 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005870 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005871 goto dongle_scantime_out;
5872 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005873 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005874 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005875 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005876 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005877 goto dongle_scantime_out;
5878 }
5879
Arend van Sprielac24be62012-10-22 10:36:23 -07005880 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005881 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005882 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005883 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005884 goto dongle_scantime_out;
5885 }
5886
5887dongle_scantime_out:
5888 return err;
5889}
5890
Arend van Sprielb48d8912014-07-12 08:49:41 +02005891static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5892 struct brcmu_chan *ch)
5893{
5894 u32 ht40_flag;
5895
5896 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5897 if (ch->sb == BRCMU_CHAN_SB_U) {
5898 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5899 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5900 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5901 } else {
5902 /* It should be one of
5903 * IEEE80211_CHAN_NO_HT40 or
5904 * IEEE80211_CHAN_NO_HT40PLUS
5905 */
5906 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5907 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5908 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5909 }
5910}
5911
5912static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5913 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005914{
5915 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005916 struct ieee80211_supported_band *band;
5917 struct ieee80211_channel *channel;
5918 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005919 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005920 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005921 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005922 u8 *pbuf;
5923 u32 i, j;
5924 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005925 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005926
5927 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5928
5929 if (pbuf == NULL)
5930 return -ENOMEM;
5931
5932 list = (struct brcmf_chanspec_list *)pbuf;
5933
5934 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5935 BRCMF_DCMD_MEDLEN);
5936 if (err) {
5937 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005938 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005939 }
5940
Arend van Sprielb48d8912014-07-12 08:49:41 +02005941 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005942 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005943 if (band)
5944 for (i = 0; i < band->n_channels; i++)
5945 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005946 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005947 if (band)
5948 for (i = 0; i < band->n_channels; i++)
5949 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005950
5951 total = le32_to_cpu(list->count);
5952 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005953 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5954 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005955
Franky Lin83cf17a2013-04-11 13:28:50 +02005956 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005957 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005958 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005959 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005960 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005961 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005962 continue;
5963 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005964 if (!band)
5965 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005966 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005967 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005968 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005969 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005970 ch.bw == BRCMU_CHAN_BW_80)
5971 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005972
Rafał Miłecki8ee78502017-01-04 12:09:41 +01005973 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005974 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki8ee78502017-01-04 12:09:41 +01005975 if (band->channels[j].hw_value == ch.control_ch_num) {
5976 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02005977 break;
5978 }
5979 }
Rafał Miłecki8ee78502017-01-04 12:09:41 +01005980 if (!channel) {
5981 /* It seems firmware supports some channel we never
5982 * considered. Something new in IEEE standard?
5983 */
5984 brcmf_err("Ignoring unexpected firmware channel %d\n",
5985 ch.control_ch_num);
5986 continue;
5987 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005988
Arend van Sprielb48d8912014-07-12 08:49:41 +02005989 /* assuming the chanspecs order is HT20,
5990 * HT40 upper, HT40 lower, and VHT80.
5991 */
5992 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki8ee78502017-01-04 12:09:41 +01005993 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005994 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki8ee78502017-01-04 12:09:41 +01005995 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005996 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005997 /* enable the channel and disable other bandwidths
5998 * for now as mentioned order assure they are enabled
5999 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02006000 */
Rafał Miłecki8ee78502017-01-04 12:09:41 +01006001 channel->flags = IEEE80211_CHAN_NO_HT40 |
6002 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006003 ch.bw = BRCMU_CHAN_BW_20;
6004 cfg->d11inf.encchspec(&ch);
6005 chaninfo = ch.chspec;
6006 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
6007 &chaninfo);
6008 if (!err) {
6009 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki8ee78502017-01-04 12:09:41 +01006010 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006011 (IEEE80211_CHAN_RADAR |
6012 IEEE80211_CHAN_NO_IR);
6013 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki8ee78502017-01-04 12:09:41 +01006014 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02006015 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006016 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006017 }
6018 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006019
Arend van Sprielb48d8912014-07-12 08:49:41 +02006020fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006021 kfree(pbuf);
6022 return err;
6023}
6024
Arend van Sprielb48d8912014-07-12 08:49:41 +02006025static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006026{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006027 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6028 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006029 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006030 struct brcmf_chanspec_list *list;
6031 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006032 u32 val;
6033 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006034 struct brcmu_chan ch;
6035 u32 num_chan;
6036 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006037
6038 /* verify support for bw_cap command */
6039 val = WLC_BAND_5G;
6040 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6041
6042 if (!err) {
6043 /* only set 2G bandwidth using bw_cap command */
6044 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6045 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6046 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6047 sizeof(band_bwcap));
6048 } else {
6049 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6050 val = WLC_N_BW_40ALL;
6051 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6052 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006053
6054 if (!err) {
6055 /* update channel info in 2G band */
6056 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6057
6058 if (pbuf == NULL)
6059 return -ENOMEM;
6060
6061 ch.band = BRCMU_CHAN_BAND_2G;
6062 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006063 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006064 ch.chnum = 0;
6065 cfg->d11inf.encchspec(&ch);
6066
6067 /* pass encoded chanspec in query */
6068 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6069
6070 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6071 BRCMF_DCMD_MEDLEN);
6072 if (err) {
6073 brcmf_err("get chanspecs error (%d)\n", err);
6074 kfree(pbuf);
6075 return err;
6076 }
6077
Johannes Berg57fbcce2016-04-12 15:56:15 +02006078 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006079 list = (struct brcmf_chanspec_list *)pbuf;
6080 num_chan = le32_to_cpu(list->count);
6081 for (i = 0; i < num_chan; i++) {
6082 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6083 cfg->d11inf.decchspec(&ch);
6084 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6085 continue;
6086 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6087 continue;
6088 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006089 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006090 break;
6091 }
6092 if (WARN_ON(j == band->n_channels))
6093 continue;
6094
6095 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6096 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006097 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006098 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006099 return err;
6100}
6101
Arend van Spriel2375d972014-01-06 12:40:41 +01006102static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6103{
6104 u32 band, mimo_bwcap;
6105 int err;
6106
6107 band = WLC_BAND_2G;
6108 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6109 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006110 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006111 band = WLC_BAND_5G;
6112 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6113 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006114 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006115 return;
6116 }
6117 WARN_ON(1);
6118 return;
6119 }
6120 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6121 mimo_bwcap = 0;
6122 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6123 if (err)
6124 /* assume 20MHz if firmware does not give a clue */
6125 mimo_bwcap = WLC_N_BW_20ALL;
6126
6127 switch (mimo_bwcap) {
6128 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006129 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006130 /* fall-thru */
6131 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006132 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006133 /* fall-thru */
6134 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006135 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6136 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006137 break;
6138 default:
6139 brcmf_err("invalid mimo_bw_cap value\n");
6140 }
6141}
Hante Meulemand48200b2013-04-03 12:40:29 +02006142
Arend van Spriel18d6c532014-05-12 10:47:35 +02006143static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6144 u32 bw_cap[2], u32 nchain)
6145{
6146 band->ht_cap.ht_supported = true;
6147 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6148 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6149 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6150 }
6151 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6152 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6153 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6154 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6155 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6156 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6157}
6158
6159static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6160{
6161 u16 mcs_map;
6162 int i;
6163
6164 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6165 mcs_map = (mcs_map << 2) | supp;
6166
6167 return cpu_to_le16(mcs_map);
6168}
6169
6170static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006171 u32 bw_cap[2], u32 nchain, u32 txstreams,
6172 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006173{
6174 __le16 mcs_map;
6175
6176 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006177 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006178 return;
6179
6180 band->vht_cap.vht_supported = true;
6181 /* 80MHz is mandatory */
6182 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6183 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6184 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6185 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6186 }
6187 /* all support 256-QAM */
6188 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6189 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6190 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006191
6192 /* Beamforming support information */
6193 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6194 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6195 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6196 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6197 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6198 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6199 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6200 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6201
6202 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6203 band->vht_cap.cap |=
6204 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6205 band->vht_cap.cap |= ((txstreams - 1) <<
6206 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6207 band->vht_cap.cap |=
6208 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6209 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006210}
6211
Arend van Sprielb48d8912014-07-12 08:49:41 +02006212static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006213{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006214 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006215 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006216 u32 nmode = 0;
6217 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006218 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006219 u32 rxchain;
6220 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006221 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006222 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006223 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006224 u32 txstreams = 0;
6225 u32 txbf_bfe_cap = 0;
6226 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006227
Arend van Spriel18d6c532014-05-12 10:47:35 +02006228 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006229 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6230 if (err) {
6231 brcmf_err("nmode error (%d)\n", err);
6232 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006233 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006234 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006235 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006236 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6237 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006238
Daniel Kim4aca7a12014-02-25 20:30:36 +01006239 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6240 if (err) {
6241 brcmf_err("rxchain error (%d)\n", err);
6242 nchain = 1;
6243 } else {
6244 for (nchain = 0; rxchain; nchain++)
6245 rxchain = rxchain & (rxchain - 1);
6246 }
6247 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6248
Arend van Sprielb48d8912014-07-12 08:49:41 +02006249 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006250 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006251 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006252 return err;
6253 }
6254
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006255 if (vhtmode) {
6256 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6257 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6258 &txbf_bfe_cap);
6259 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6260 &txbf_bfr_cap);
6261 }
6262
Arend van Sprielb48d8912014-07-12 08:49:41 +02006263 wiphy = cfg_to_wiphy(cfg);
6264 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6265 band = wiphy->bands[i];
6266 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006267 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006268
Arend van Spriel18d6c532014-05-12 10:47:35 +02006269 if (nmode)
6270 brcmf_update_ht_cap(band, bw_cap, nchain);
6271 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006272 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6273 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006274 }
6275
Arend van Sprielb48d8912014-07-12 08:49:41 +02006276 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006277}
6278
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006279static const struct ieee80211_txrx_stypes
6280brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6281 [NL80211_IFTYPE_STATION] = {
6282 .tx = 0xffff,
6283 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6284 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6285 },
6286 [NL80211_IFTYPE_P2P_CLIENT] = {
6287 .tx = 0xffff,
6288 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6289 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6290 },
6291 [NL80211_IFTYPE_P2P_GO] = {
6292 .tx = 0xffff,
6293 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6294 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6295 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6296 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6297 BIT(IEEE80211_STYPE_AUTH >> 4) |
6298 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6299 BIT(IEEE80211_STYPE_ACTION >> 4)
6300 },
6301 [NL80211_IFTYPE_P2P_DEVICE] = {
6302 .tx = 0xffff,
6303 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6304 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6305 }
6306};
6307
Arend van Spriel0882dda2015-08-20 22:06:03 +02006308/**
6309 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6310 *
6311 * @wiphy: wiphy object.
6312 * @ifp: interface object needed for feat module api.
6313 *
6314 * The interface modes and combinations are determined dynamically here
6315 * based on firmware functionality.
6316 *
6317 * no p2p and no mbss:
6318 *
6319 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6320 *
6321 * no p2p and mbss:
6322 *
6323 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6324 * #AP <= 4, matching BI, channels = 1, 4 total
6325 *
6326 * p2p, no mchan, and mbss:
6327 *
6328 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6329 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6330 * #AP <= 4, matching BI, channels = 1, 4 total
6331 *
6332 * p2p, mchan, and mbss:
6333 *
6334 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6335 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6336 * #AP <= 4, matching BI, channels = 1, 4 total
6337 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006338static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6339{
6340 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006341 struct ieee80211_iface_limit *c0_limits = NULL;
6342 struct ieee80211_iface_limit *p2p_limits = NULL;
6343 struct ieee80211_iface_limit *mbss_limits = NULL;
6344 bool mbss, p2p;
6345 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006346
Arend van Spriel0882dda2015-08-20 22:06:03 +02006347 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6348 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6349
6350 n_combos = 1 + !!p2p + !!mbss;
6351 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006352 if (!combo)
6353 goto err;
6354
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006355 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6356 BIT(NL80211_IFTYPE_ADHOC) |
6357 BIT(NL80211_IFTYPE_AP);
6358
Arend van Spriel0882dda2015-08-20 22:06:03 +02006359 c = 0;
6360 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006361 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6362 if (!c0_limits)
6363 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006364 c0_limits[i].max = 1;
6365 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6366 if (p2p) {
6367 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6368 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006369 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6370 BIT(NL80211_IFTYPE_P2P_GO) |
6371 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006372 c0_limits[i].max = 1;
6373 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6374 c0_limits[i].max = 1;
6375 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6376 BIT(NL80211_IFTYPE_P2P_GO);
6377 } else {
6378 c0_limits[i].max = 1;
6379 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006380 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006381 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006382 combo[c].max_interfaces = i;
6383 combo[c].n_limits = i;
6384 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006385
Arend van Spriel0882dda2015-08-20 22:06:03 +02006386 if (p2p) {
6387 c++;
6388 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006389 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6390 if (!p2p_limits)
6391 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006392 p2p_limits[i].max = 1;
6393 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6394 p2p_limits[i].max = 1;
6395 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6396 p2p_limits[i].max = 1;
6397 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6398 p2p_limits[i].max = 1;
6399 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006400 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006401 combo[c].max_interfaces = i;
6402 combo[c].n_limits = i;
6403 combo[c].limits = p2p_limits;
6404 }
6405
6406 if (mbss) {
6407 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006408 i = 0;
6409 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6410 if (!mbss_limits)
6411 goto err;
6412 mbss_limits[i].max = 4;
6413 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006414 combo[c].beacon_int_infra_match = true;
6415 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006416 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006417 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006418 combo[c].limits = mbss_limits;
6419 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006420
Arend van Spriel0882dda2015-08-20 22:06:03 +02006421 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006422 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006423 return 0;
6424
6425err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006426 kfree(c0_limits);
6427 kfree(p2p_limits);
6428 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006429 kfree(combo);
6430 return -ENOMEM;
6431}
6432
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006433static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6434{
6435 /* scheduled scan settings */
6436 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6437 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6438 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6439 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6440}
6441
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006442#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006443static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006444 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006445 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6446 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6447 .pattern_min_len = 1,
6448 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006449};
6450#endif
6451
Hante Meuleman3021ad92016-01-05 11:05:45 +01006452static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006453{
6454#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006455 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006456
6457 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006458 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6459 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6460 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006461 }
6462 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006463 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6464 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6465 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6466 }
6467
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006468 wiphy->wowlan = &brcmf_wowlan_support;
6469#endif
6470}
6471
Arend van Sprielb48d8912014-07-12 08:49:41 +02006472static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006473{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006474 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006475 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006476 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006477 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006478 __le32 bandlist[3];
6479 u32 n_bands;
6480 int err, i;
6481
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006482 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6483 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006484 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006485
6486 err = brcmf_setup_ifmodes(wiphy, ifp);
6487 if (err)
6488 return err;
6489
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006490 for (i = 0, combo = wiphy->iface_combinations;
6491 i < wiphy->n_iface_combinations; i++, combo++) {
6492 max_interfaces = max(max_interfaces, combo->max_interfaces);
6493 }
6494
6495 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6496 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006497 u8 *addr = drvr->addresses[i].addr;
6498
6499 memcpy(addr, drvr->mac, ETH_ALEN);
6500 if (i) {
6501 addr[0] |= BIT(1);
6502 addr[ETH_ALEN - 1] ^= i;
6503 }
6504 }
6505 wiphy->addresses = drvr->addresses;
6506 wiphy->n_addresses = i;
6507
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006508 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006509 wiphy->cipher_suites = brcmf_cipher_suites;
6510 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6511 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6512 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006513 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6514 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6515 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6516
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006517 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6518 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006519 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6520 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6521 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006522 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006523 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6524 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6525 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006526 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6527 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006528
6529 /* vendor commands/events support */
6530 wiphy->vendor_commands = brcmf_vendor_cmds;
6531 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6532
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006533 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006534 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006535 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6536 sizeof(bandlist));
6537 if (err) {
6538 brcmf_err("could not obtain band info: err=%d\n", err);
6539 return err;
6540 }
6541 /* first entry in bandlist is number of bands */
6542 n_bands = le32_to_cpu(bandlist[0]);
6543 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6544 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6545 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6546 GFP_KERNEL);
6547 if (!band)
6548 return -ENOMEM;
6549
6550 band->channels = kmemdup(&__wl_2ghz_channels,
6551 sizeof(__wl_2ghz_channels),
6552 GFP_KERNEL);
6553 if (!band->channels) {
6554 kfree(band);
6555 return -ENOMEM;
6556 }
6557
6558 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006559 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006560 }
6561 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6562 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6563 GFP_KERNEL);
6564 if (!band)
6565 return -ENOMEM;
6566
6567 band->channels = kmemdup(&__wl_5ghz_channels,
6568 sizeof(__wl_5ghz_channels),
6569 GFP_KERNEL);
6570 if (!band->channels) {
6571 kfree(band);
6572 return -ENOMEM;
6573 }
6574
6575 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006576 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006577 }
6578 }
Rafał Miłeckibe5125d2017-01-07 21:36:05 +01006579 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006580}
6581
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006582static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006583{
6584 struct net_device *ndev;
6585 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006586 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006587 s32 power_mode;
6588 s32 err = 0;
6589
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006590 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006591 return err;
6592
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006593 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006594 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006595 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006596
Hante Meuleman40a23292013-01-02 15:22:51 +01006597 /* make sure RF is ready for work */
6598 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6599
Hante Meuleman1678ba82015-12-10 13:43:00 +01006600 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006601
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006602 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006603 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006604 if (err)
6605 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006606 brcmf_dbg(INFO, "power save set to %s\n",
6607 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006608
Hante Meuleman1119e232015-11-25 11:32:42 +01006609 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006610 if (err)
6611 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006612 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6613 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006614 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006615 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006616
Franky Lin52f22fb2016-02-17 11:26:55 +01006617 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006618
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006619 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006620default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006621
6622 return err;
6623
6624}
6625
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006626static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006627{
Arend van Sprielc1179032012-10-22 13:55:33 -07006628 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006629
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006630 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006631}
6632
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006633static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006634{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006635 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006636
Arend van Spriel5b435de2011-10-05 13:19:03 +02006637 /*
6638 * While going down, if associated with AP disassociate
6639 * from AP to save power
6640 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006641 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006642 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006643
6644 /* Make sure WPA_Supplicant receives all the event
6645 generated due to DISASSOC call to the fw to keep
6646 the state fw and WPA_Supplicant state consistent
6647 */
6648 brcmf_delay(500);
6649 }
6650
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006651 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006652 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006653
Arend van Spriel5b435de2011-10-05 13:19:03 +02006654 return 0;
6655}
6656
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006657s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006658{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006659 struct brcmf_if *ifp = netdev_priv(ndev);
6660 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006661 s32 err = 0;
6662
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006663 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006664 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006665 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006666
6667 return err;
6668}
6669
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006670s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006671{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006672 struct brcmf_if *ifp = netdev_priv(ndev);
6673 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006674 s32 err = 0;
6675
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006676 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006677 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006678 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006679
6680 return err;
6681}
6682
Arend van Spriela7965fb2013-04-11 17:08:37 +02006683enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6684{
6685 struct wireless_dev *wdev = &ifp->vif->wdev;
6686
6687 return wdev->iftype;
6688}
6689
Hante Meulemanbfe81972014-10-28 14:56:16 +01006690bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6691 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006692{
6693 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006694
6695 list_for_each_entry(vif, &cfg->vif_list, list) {
6696 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006697 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006698 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006699 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006700}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006701
6702static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6703 u8 action)
6704{
6705 u8 evt_action;
6706
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006707 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006708 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006709 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006710 return evt_action == action;
6711}
6712
6713void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6714 struct brcmf_cfg80211_vif *vif)
6715{
6716 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6717
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006718 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006719 event->vif = vif;
6720 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006721 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006722}
6723
6724bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6725{
6726 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6727 bool armed;
6728
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006729 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006730 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006731 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006732
6733 return armed;
6734}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006735
6736int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6737 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006738{
6739 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6740
6741 return wait_event_timeout(event->vif_wq,
6742 vif_event_equals(event, action), timeout);
6743}
6744
Hante Meuleman73345fd2016-02-17 11:26:53 +01006745static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6746 struct brcmf_fil_country_le *ccreq)
6747{
Hante Meuleman4d792892016-02-17 11:27:07 +01006748 struct brcmfmac_pd_cc *country_codes;
6749 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006750 s32 found_index;
6751 int i;
6752
6753 country_codes = drvr->settings->country_codes;
6754 if (!country_codes) {
6755 brcmf_dbg(TRACE, "No country codes configured for device\n");
6756 return -EINVAL;
6757 }
6758
6759 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6760 (alpha2[1] == ccreq->country_abbrev[1])) {
6761 brcmf_dbg(TRACE, "Country code already set\n");
6762 return -EAGAIN;
6763 }
6764
6765 found_index = -1;
6766 for (i = 0; i < country_codes->table_size; i++) {
6767 cc = &country_codes->table[i];
6768 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6769 found_index = i;
6770 if ((cc->iso3166[0] == alpha2[0]) &&
6771 (cc->iso3166[1] == alpha2[1])) {
6772 found_index = i;
6773 break;
6774 }
6775 }
6776 if (found_index == -1) {
6777 brcmf_dbg(TRACE, "No country code match found\n");
6778 return -EINVAL;
6779 }
6780 memset(ccreq, 0, sizeof(*ccreq));
6781 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6782 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6783 BRCMF_COUNTRY_BUF_SZ);
6784 ccreq->country_abbrev[0] = alpha2[0];
6785 ccreq->country_abbrev[1] = alpha2[1];
6786 ccreq->country_abbrev[2] = 0;
6787
6788 return 0;
6789}
6790
Arend van Spriel63db1a42014-12-21 12:43:51 +01006791static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6792 struct regulatory_request *req)
6793{
6794 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6795 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6796 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006797 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006798 int i;
6799
Arend van Spriel63db1a42014-12-21 12:43:51 +01006800 /* ignore non-ISO3166 country codes */
Stefan Wahren78e74092018-03-14 20:02:59 +01006801 for (i = 0; i < 2; i++)
Arend van Spriel63db1a42014-12-21 12:43:51 +01006802 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006803 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6804 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006805 return;
6806 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006807
6808 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6809 req->alpha2[0], req->alpha2[1]);
6810
6811 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6812 if (err) {
6813 brcmf_err("Country code iovar returned err = %d\n", err);
6814 return;
6815 }
6816
6817 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6818 if (err)
6819 return;
6820
6821 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6822 if (err) {
6823 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006824 return;
6825 }
6826 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006827}
6828
Arend van Sprielb48d8912014-07-12 08:49:41 +02006829static void brcmf_free_wiphy(struct wiphy *wiphy)
6830{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006831 int i;
6832
Arend van Spriel58de92d2015-04-14 20:10:24 +02006833 if (!wiphy)
6834 return;
6835
Arend van Spriel0882dda2015-08-20 22:06:03 +02006836 if (wiphy->iface_combinations) {
6837 for (i = 0; i < wiphy->n_iface_combinations; i++)
6838 kfree(wiphy->iface_combinations[i].limits);
6839 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006840 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006841 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6842 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6843 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006844 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006845 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6846 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6847 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006848 }
6849 wiphy_free(wiphy);
6850}
6851
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006852struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006853 struct device *busdev,
6854 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006855{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006856 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006857 struct brcmf_cfg80211_info *cfg;
6858 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006859 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006860 struct brcmf_cfg80211_vif *vif;
6861 struct brcmf_if *ifp;
6862 s32 err = 0;
6863 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006864 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006865
6866 if (!ndev) {
6867 brcmf_err("ndev is invalid\n");
6868 return NULL;
6869 }
6870
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306871 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006872 if (!ops)
6873 return NULL;
6874
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006875 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006876#ifdef CONFIG_PM
6877 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6878 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6879#endif
6880 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006881 if (!wiphy) {
6882 brcmf_err("Could not allocate wiphy device\n");
Christophe Jailletfd325dd2017-06-21 07:45:53 +02006883 goto ops_out;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006884 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006885 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006886 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006887
6888 cfg = wiphy_priv(wiphy);
6889 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006890 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006891 cfg->pub = drvr;
6892 init_vif_event(&cfg->vif_event);
6893 INIT_LIST_HEAD(&cfg->vif_list);
6894
Rafał Miłecki26072332016-06-06 23:03:55 +02006895 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006896 if (IS_ERR(vif))
6897 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006898
6899 vif->ifp = ifp;
6900 vif->wdev.netdev = ndev;
6901 ndev->ieee80211_ptr = &vif->wdev;
6902 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6903
6904 err = wl_init_priv(cfg);
6905 if (err) {
6906 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006907 brcmf_free_vif(vif);
6908 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006909 }
6910 ifp->vif = vif;
6911
Arend van Sprielb48d8912014-07-12 08:49:41 +02006912 /* determine d11 io type before wiphy setup */
6913 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006914 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006915 brcmf_err("Failed to get D11 version (%d)\n", err);
6916 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006917 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006918 cfg->d11inf.io_type = (u8)io_type;
6919 brcmu_d11_attach(&cfg->d11inf);
6920
6921 err = brcmf_setup_wiphy(wiphy, ifp);
6922 if (err < 0)
6923 goto priv_out;
6924
6925 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006926 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006927 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6928 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6929
6930 /* firmware defaults to 40MHz disabled in 2G band. We signal
6931 * cfg80211 here that we do and have it decide we can enable
6932 * it. But first check if device does support 2G operation.
6933 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006934 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6935 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006936 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6937 }
6938 err = wiphy_register(wiphy);
6939 if (err < 0) {
6940 brcmf_err("Could not register wiphy device (%d)\n", err);
6941 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006942 }
6943
Rafał Miłeckibe5125d2017-01-07 21:36:05 +01006944 err = brcmf_setup_wiphybands(wiphy);
6945 if (err) {
6946 brcmf_err("Setting wiphy bands failed (%d)\n", err);
6947 goto wiphy_unreg_out;
6948 }
6949
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006950 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6951 * setup 40MHz in 2GHz band and enable OBSS scanning.
6952 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006953 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6954 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006955 if (!err)
6956 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6957 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006958 else
6959 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006960 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006961 /* p2p might require that "if-events" get processed by fweh. So
6962 * activate the already registered event handlers now and activate
6963 * the rest when initialization has completed. drvr->config needs to
6964 * be assigned before activating events.
6965 */
6966 drvr->config = cfg;
6967 err = brcmf_fweh_activate_events(ifp);
6968 if (err) {
6969 brcmf_err("FWEH activation failed (%d)\n", err);
6970 goto wiphy_unreg_out;
6971 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006972
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006973 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006974 if (err) {
6975 brcmf_err("P2P initilisation failed (%d)\n", err);
6976 goto wiphy_unreg_out;
6977 }
6978 err = brcmf_btcoex_attach(cfg);
6979 if (err) {
6980 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6981 brcmf_p2p_detach(&cfg->p2p);
6982 goto wiphy_unreg_out;
6983 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006984
Hante Meulemana7b82d42015-12-10 13:43:04 +01006985 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6986 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6987 if (err) {
6988 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6989 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6990 } else {
6991 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6992 brcmf_notify_tdls_peer_event);
6993 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006994 }
6995
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006996 /* (re-) activate FWEH event handling */
6997 err = brcmf_fweh_activate_events(ifp);
6998 if (err) {
6999 brcmf_err("FWEH activation failed (%d)\n", err);
7000 goto wiphy_unreg_out;
7001 }
7002
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007003 /* Fill in some of the advertised nl80211 supported features */
7004 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
7005 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7006#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01007007 if (wiphy->wowlan &&
7008 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01007009 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7010#endif
7011 }
7012
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007013 return cfg;
7014
Arend van Sprielb48d8912014-07-12 08:49:41 +02007015wiphy_unreg_out:
7016 wiphy_unregister(cfg->wiphy);
7017priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007018 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007019 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007020 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007021wiphy_out:
7022 brcmf_free_wiphy(wiphy);
Christophe Jailletfd325dd2017-06-21 07:45:53 +02007023ops_out:
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007024 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007025 return NULL;
7026}
7027
7028void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7029{
7030 if (!cfg)
7031 return;
7032
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007033 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007034 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007035 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007036 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007037 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007038}