blob: d97d6b153d6a1c5f66d339002b76010c09eafd28 [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), \
150 .flags = IEEE80211_CHAN_DISABLED, \
151 .max_antenna_gain = 0, \
152 .max_power = 30, \
153}
154
155#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200156 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200157 .center_freq = 5000 + (5 * (_channel)), \
158 .hw_value = (_channel), \
159 .flags = IEEE80211_CHAN_DISABLED, \
160 .max_antenna_gain = 0, \
161 .max_power = 30, \
162}
163
164static struct ieee80211_channel __wl_2ghz_channels[] = {
165 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
166 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
167 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
168 CHAN2G(13, 2472), CHAN2G(14, 2484)
169};
170
171static struct ieee80211_channel __wl_5ghz_channels[] = {
172 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
173 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
174 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
175 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
176 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
177 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
178};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200179
Arend van Sprielb48d8912014-07-12 08:49:41 +0200180/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200181 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200182 */
183static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200184 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200185 .bitrates = wl_g_rates,
186 .n_bitrates = wl_g_rates_size,
187};
188
Arend van Spriel58de92d2015-04-14 20:10:24 +0200189static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200190 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200191 .bitrates = wl_a_rates,
192 .n_bitrates = wl_a_rates_size,
193};
194
Hante Meulemand48200b2013-04-03 12:40:29 +0200195/* This is to override regulatory domains defined in cfg80211 module (reg.c)
196 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200197 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
198 * With respect to these flags, wpa_supplicant doesn't * start p2p
199 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200200 * domain are to be done here.
201 */
202static const struct ieee80211_regdomain brcmf_regdom = {
203 .n_reg_rules = 4,
204 .alpha2 = "99",
205 .reg_rules = {
206 /* IEEE 802.11b/g, channels 1..11 */
207 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
208 /* If any */
209 /* IEEE 802.11 channel 14 - Only JP enables
210 * this and for 802.11b only
211 */
212 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
213 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200214 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200215 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200216 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200217};
218
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
220 * are supported. A pointer to this array and the number of entries is passed
221 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
222 * So the cipher suite AES_CMAC has to be the last one in the array, and when
223 * device does not support MFP then the number of suites will be decreased by 1
224 */
225static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200226 WLAN_CIPHER_SUITE_WEP40,
227 WLAN_CIPHER_SUITE_WEP104,
228 WLAN_CIPHER_SUITE_TKIP,
229 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100230 /* Keep as last entry: */
231 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200232};
233
Hante Meuleman1a873342012-09-27 14:17:54 +0200234/* Vendor specific ie. id = 221, oui and type defines exact ie */
235struct brcmf_vs_tlv {
236 u8 id;
237 u8 len;
238 u8 oui[3];
239 u8 oui_type;
240};
241
242struct parsed_vndr_ie_info {
243 u8 *ie_ptr;
244 u32 ie_len; /* total length including id & length field */
245 struct brcmf_vs_tlv vndrie;
246};
247
248struct parsed_vndr_ies {
249 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100250 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200251};
252
Arend van Spriel7705ba62016-04-17 16:44:58 +0200253static u8 nl80211_band_to_fwil(enum nl80211_band band)
254{
255 switch (band) {
256 case NL80211_BAND_2GHZ:
257 return WLC_BAND_2G;
258 case NL80211_BAND_5GHZ:
259 return WLC_BAND_5G;
260 default:
261 WARN_ON(1);
262 break;
263 }
264 return 0;
265}
266
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200267static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
268 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200269{
270 struct brcmu_chan ch_inf;
271 s32 primary_offset;
272
273 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
274 ch->chan->center_freq, ch->center_freq1, ch->width);
275 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100276 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200277 switch (ch->width) {
278 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100279 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200280 ch_inf.bw = BRCMU_CHAN_BW_20;
281 WARN_ON(primary_offset != 0);
282 break;
283 case NL80211_CHAN_WIDTH_40:
284 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100285 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200286 ch_inf.sb = BRCMU_CHAN_SB_U;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_L;
289 break;
290 case NL80211_CHAN_WIDTH_80:
291 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100292 if (primary_offset == -30)
293 ch_inf.sb = BRCMU_CHAN_SB_LL;
294 else if (primary_offset == -10)
295 ch_inf.sb = BRCMU_CHAN_SB_LU;
296 else if (primary_offset == 10)
297 ch_inf.sb = BRCMU_CHAN_SB_UL;
298 else
299 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200300 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100301 case NL80211_CHAN_WIDTH_80P80:
302 case NL80211_CHAN_WIDTH_160:
303 case NL80211_CHAN_WIDTH_5:
304 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200309 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200310 ch_inf.band = BRCMU_CHAN_BAND_2G;
311 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200312 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200313 ch_inf.band = BRCMU_CHAN_BAND_5G;
314 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200315 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200316 default:
317 WARN_ON_ONCE(1);
318 }
319 d11inf->encchspec(&ch_inf);
320
321 return ch_inf.chspec;
322}
323
Franky Lin83cf17a2013-04-11 13:28:50 +0200324u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
325 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700326{
Franky Lin83cf17a2013-04-11 13:28:50 +0200327 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700328
Franky Lin83cf17a2013-04-11 13:28:50 +0200329 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
330 ch_inf.bw = BRCMU_CHAN_BW_20;
331 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700332
Franky Lin83cf17a2013-04-11 13:28:50 +0200333 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700334}
335
Hante Meuleman89286dc2013-02-08 15:53:46 +0100336/* Traverse a string of 1-byte tag/1-byte length/variable-length value
337 * triples, returning a pointer to the substring whose first element
338 * matches tag
339 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100340const struct brcmf_tlv *
341brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100342{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100343 const struct brcmf_tlv *elt = buf;
344 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100345
346 /* find tagged parameter */
347 while (totlen >= TLV_HDR_LEN) {
348 int len = elt->len;
349
350 /* validate remaining totlen */
351 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
352 return elt;
353
354 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
355 totlen -= (len + TLV_HDR_LEN);
356 }
357
358 return NULL;
359}
360
361/* Is any of the tlvs the expected entry? If
362 * not update the tlvs buffer pointer/length.
363 */
364static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100365brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
366 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100367{
368 /* If the contents match the OUI and the type */
369 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
370 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
371 type == ie[TLV_BODY_OFF + oui_len]) {
372 return true;
373 }
374
375 if (tlvs == NULL)
376 return false;
377 /* point to the next ie */
378 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
379 /* calculate the length of the rest of the buffer */
380 *tlvs_len -= (int)(ie - *tlvs);
381 /* update the pointer to the start of the buffer */
382 *tlvs = ie;
383
384 return false;
385}
386
387static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100388brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100389{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391
392 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100393 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100394 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
395 return (struct brcmf_vs_tlv *)ie;
396 }
397 return NULL;
398}
399
400static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100401brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100402{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100403 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100404
405 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
406 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
407 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
408 return (struct brcmf_vs_tlv *)ie;
409 }
410 return NULL;
411}
412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
414 struct brcmf_cfg80211_vif *vif,
415 enum nl80211_iftype new_type)
416{
417 int iftype_num[NUM_NL80211_IFTYPES];
418 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100419 bool check_combos = false;
420 int ret = 0;
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
422 memset(&iftype_num[0], 0, sizeof(iftype_num));
423 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424 if (pos == vif) {
Arend van Spriel39504a22015-08-20 22:06:05 +0200425 iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100426 } else {
427 /* concurrent interfaces so need check combinations */
428 check_combos = true;
Arend van Spriel39504a22015-08-20 22:06:05 +0200429 iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100430 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200431
Arend van Spriel353c46a2015-12-10 13:43:06 +0100432 if (check_combos)
433 ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
434
435 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200436}
437
438static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
439 enum nl80211_iftype new_type)
440{
441 int iftype_num[NUM_NL80211_IFTYPES];
442 struct brcmf_cfg80211_vif *pos;
443
444 memset(&iftype_num[0], 0, sizeof(iftype_num));
445 list_for_each_entry(pos, &cfg->vif_list, list)
446 iftype_num[pos->wdev.iftype]++;
447
448 iftype_num[new_type]++;
449 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
450}
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;
981 params_le->scan_type = 0;
982 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
989 /* if request is null exit so it will be all channel broadcast scan */
990 if (!request)
991 return;
992
993 n_ssids = request->n_ssids;
994 n_channels = request->n_channels;
995 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100996 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
997 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200998 if (n_channels > 0) {
999 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02001000 chanspec = channel_to_chanspec(&cfg->d11inf,
1001 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001002 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
1003 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +02001004 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +02001005 }
1006 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001007 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001008 }
1009 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001010 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001011 if (n_ssids > 0) {
1012 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1013 n_channels * sizeof(u16);
1014 offset = roundup(offset, sizeof(u32));
1015 ptr = (char *)params_le + offset;
1016 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001017 memset(&ssid_le, 0, sizeof(ssid_le));
1018 ssid_le.SSID_len =
1019 cpu_to_le32(request->ssids[i].ssid_len);
1020 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1021 request->ssids[i].ssid_len);
1022 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001023 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001024 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001025 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
1026 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001027 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1028 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001029 }
1030 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001031 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001032 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001033 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1034 params_le->ssid_le.SSID,
1035 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001036 params_le->ssid_le.SSID_len =
1037 cpu_to_le32(request->ssids->ssid_len);
1038 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1039 request->ssids->ssid_len);
1040 }
1041 }
1042 /* Adding mask to channel numbers */
1043 params_le->channel_num =
1044 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1045 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1046}
1047
1048static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001049brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001050 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001051{
1052 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1053 offsetof(struct brcmf_escan_params_le, params_le);
1054 struct brcmf_escan_params_le *params;
1055 s32 err = 0;
1056
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001057 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001058
1059 if (request != NULL) {
1060 /* Allocate space for populating ssids in struct */
1061 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1062
1063 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001064 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001065 }
1066
1067 params = kzalloc(params_size, GFP_KERNEL);
1068 if (!params) {
1069 err = -ENOMEM;
1070 goto exit;
1071 }
1072 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001073 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001074 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001075 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001076 params->sync_id = cpu_to_le16(0x1234);
1077
Arend van Spriela0f472a2013-04-05 10:57:49 +02001078 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001079 if (err) {
1080 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001081 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001082 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001083 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001084 }
1085
1086 kfree(params);
1087exit:
1088 return err;
1089}
1090
1091static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001092brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001093 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001094{
1095 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001096 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001097 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001098 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001099
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001100 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001101 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001102 escan->wiphy = wiphy;
1103 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001104 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001105 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001106 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001107 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001108 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 return err;
1110 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001111 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001112 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001113 results->version = 0;
1114 results->count = 0;
1115 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1116
Hante Meulemanc4958102015-11-25 11:32:41 +01001117 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001118 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001119 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001120 return err;
1121}
1122
1123static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001124brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001125 struct cfg80211_scan_request *request,
1126 struct cfg80211_ssid *this_ssid)
1127{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001128 struct brcmf_if *ifp = vif->ifp;
1129 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001130 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001131 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001132 bool escan_req;
1133 bool spec_scan;
1134 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001135 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001136 u32 SSID_len;
1137
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001138 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001139
Arend van Sprielc1179032012-10-22 13:55:33 -07001140 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001141 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001142 return -EAGAIN;
1143 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001144 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001145 brcmf_err("Scanning being aborted: status (%lu)\n",
1146 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001147 return -EAGAIN;
1148 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001149 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1150 brcmf_err("Scanning suppressed: status (%lu)\n",
1151 cfg->scan_status);
1152 return -EAGAIN;
1153 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001154 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001155 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001156 return -EAGAIN;
1157 }
1158
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001159 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001160 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1161 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001162
Hante Meulemane756af52012-09-11 21:18:52 +02001163 escan_req = false;
1164 if (request) {
1165 /* scan bss */
1166 ssids = request->ssids;
1167 escan_req = true;
1168 } else {
1169 /* scan in ibss */
1170 /* we don't do escan in ibss */
1171 ssids = this_ssid;
1172 }
1173
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001174 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001175 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001176 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001177 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001178 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001179 if (err)
1180 goto scan_out;
1181
Arend van Spriela0f472a2013-04-05 10:57:49 +02001182 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001183 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001184 goto scan_out;
1185 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001186 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1187 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001188 memset(&ssid_le, 0, sizeof(ssid_le));
1189 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1190 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001191 spec_scan = false;
1192 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001193 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1194 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001195 spec_scan = true;
1196 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001197 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001198
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001199 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001200 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001201 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001202 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001203 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001204 goto scan_out;
1205 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001206 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001207 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1208 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001209 if (err) {
1210 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001211 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001212 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001213 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001214 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001215
Daniel Kim5e787f72014-06-21 12:11:18 +02001216 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001217 goto scan_out;
1218 }
1219 }
1220
Hante Meuleman661fa952015-02-06 18:36:47 +01001221 /* Arm scan timeout timer */
1222 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001223 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001224
Hante Meulemane756af52012-09-11 21:18:52 +02001225 return 0;
1226
1227scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001228 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001229 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001230 return err;
1231}
1232
Arend van Spriel5b435de2011-10-05 13:19:03 +02001233static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001234brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001236 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237 s32 err = 0;
1238
Arend van Sprield96b8012012-12-05 15:26:02 +01001239 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001240 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1241 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001242 return -EIO;
1243
Arend van Spriela0f472a2013-04-05 10:57:49 +02001244 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001245
Arend van Spriel5b435de2011-10-05 13:19:03 +02001246 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001247 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248
Arend van Sprield96b8012012-12-05 15:26:02 +01001249 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250 return err;
1251}
1252
1253static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1254{
1255 s32 err = 0;
1256
Arend van Sprielac24be62012-10-22 10:36:23 -07001257 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1258 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001260 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001261
1262 return err;
1263}
1264
1265static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1266{
1267 s32 err = 0;
1268
Arend van Sprielac24be62012-10-22 10:36:23 -07001269 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1270 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001271 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001272 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001273
1274 return err;
1275}
1276
1277static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1278{
1279 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001280 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001281
Arend van Sprielac24be62012-10-22 10:36:23 -07001282 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001284 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 return err;
1286 }
1287 return err;
1288}
1289
1290static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1291{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001292 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1293 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001294 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295 s32 err = 0;
1296
Arend van Sprield96b8012012-12-05 15:26:02 +01001297 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001298 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001299 return -EIO;
1300
1301 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001302 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1303 cfg->conf->rts_threshold = wiphy->rts_threshold;
1304 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 if (!err)
1306 goto done;
1307 }
1308 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001309 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1310 cfg->conf->frag_threshold = wiphy->frag_threshold;
1311 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001312 if (!err)
1313 goto done;
1314 }
1315 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001316 && (cfg->conf->retry_long != wiphy->retry_long)) {
1317 cfg->conf->retry_long = wiphy->retry_long;
1318 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001319 if (!err)
1320 goto done;
1321 }
1322 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001323 && (cfg->conf->retry_short != wiphy->retry_short)) {
1324 cfg->conf->retry_short = wiphy->retry_short;
1325 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326 if (!err)
1327 goto done;
1328 }
1329
1330done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001331 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001332 return err;
1333}
1334
Arend van Spriel5b435de2011-10-05 13:19:03 +02001335static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1336{
1337 memset(prof, 0, sizeof(*prof));
1338}
1339
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001340static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1341{
1342 u16 reason;
1343
1344 switch (e->event_code) {
1345 case BRCMF_E_DEAUTH:
1346 case BRCMF_E_DEAUTH_IND:
1347 case BRCMF_E_DISASSOC_IND:
1348 reason = e->reason;
1349 break;
1350 case BRCMF_E_LINK:
1351 default:
1352 reason = 0;
1353 break;
1354 }
1355 return reason;
1356}
1357
1358static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001359{
Piotr Haber61730d42013-04-23 12:53:12 +02001360 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001361 s32 err = 0;
1362
Arend van Sprield96b8012012-12-05 15:26:02 +01001363 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001364
Hante Meulemanb0a79082015-12-10 13:43:07 +01001365 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001366 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001367 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001368 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001369 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001370 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001371 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001372 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1373 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1374 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1375 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001376 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001377 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001378 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1379 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001380 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001381}
1382
1383static s32
1384brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1385 struct cfg80211_ibss_params *params)
1386{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001387 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001388 struct brcmf_if *ifp = netdev_priv(ndev);
1389 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001390 struct brcmf_join_params join_params;
1391 size_t join_params_size = 0;
1392 s32 err = 0;
1393 s32 wsec = 0;
1394 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001395 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001396 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001397
Arend van Sprield96b8012012-12-05 15:26:02 +01001398 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001399 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001400 return -EIO;
1401
1402 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001403 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001405 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001406 return -EOPNOTSUPP;
1407 }
1408
Arend van Sprielc1179032012-10-22 13:55:33 -07001409 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410
1411 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001412 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001413 else
Arend van Spriel16886732012-12-05 15:26:04 +01001414 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415
Johannes Berg683b6d32012-11-08 21:25:48 +01001416 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001417 brcmf_dbg(CONN, "channel: %d\n",
1418 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001419 else
Arend van Spriel16886732012-12-05 15:26:04 +01001420 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001421
1422 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001423 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 else
Arend van Spriel16886732012-12-05 15:26:04 +01001425 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001426
1427 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001428 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 else
Arend van Spriel16886732012-12-05 15:26:04 +01001430 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431
1432 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001433 brcmf_dbg(CONN, "beacon interval: %d\n",
1434 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001435 else
Arend van Spriel16886732012-12-05 15:26:04 +01001436 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001437
1438 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001439 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 else
Arend van Spriel16886732012-12-05 15:26:04 +01001441 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442
1443 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001444 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001445 else
Arend van Spriel16886732012-12-05 15:26:04 +01001446 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001447
1448 /* Configure Privacy for starter */
1449 if (params->privacy)
1450 wsec |= WEP_ENABLED;
1451
Arend van Sprielc1179032012-10-22 13:55:33 -07001452 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001454 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001455 goto done;
1456 }
1457
1458 /* Configure Beacon Interval for starter */
1459 if (params->beacon_interval)
1460 bcnprd = params->beacon_interval;
1461 else
1462 bcnprd = 100;
1463
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001464 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001465 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001466 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467 goto done;
1468 }
1469
1470 /* Configure required join parameter */
1471 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1472
1473 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001474 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1475 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1476 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001477 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001478
1479 /* BSSID */
1480 if (params->bssid) {
1481 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001482 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001483 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001484 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001485 eth_broadcast_addr(join_params.params_le.bssid);
1486 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487 }
1488
Arend van Spriel5b435de2011-10-05 13:19:03 +02001489 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001490 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001491 u32 target_channel;
1492
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001493 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001495 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001496 if (params->channel_fixed) {
1497 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001498 chanspec = chandef_to_chanspec(&cfg->d11inf,
1499 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001500 join_params.params_le.chanspec_list[0] =
1501 cpu_to_le16(chanspec);
1502 join_params.params_le.chanspec_num = cpu_to_le32(1);
1503 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001504 }
1505
1506 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001507 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001508 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001509 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001511 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512 goto done;
1513 }
1514 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001515 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001516
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001517 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518
1519
Arend van Sprielc1179032012-10-22 13:55:33 -07001520 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001521 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001522 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001523 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524 goto done;
1525 }
1526
1527done:
1528 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001529 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001530 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531 return err;
1532}
1533
1534static s32
1535brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1536{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001537 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538
Arend van Sprield96b8012012-12-05 15:26:02 +01001539 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001540 if (!check_vif_up(ifp->vif)) {
1541 /* When driver is being unloaded, it can end up here. If an
1542 * error is returned then later on a debug trace in the wireless
1543 * core module will be printed. To avoid this 0 is returned.
1544 */
1545 return 0;
1546 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001547
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001548 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001549 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001550
Arend van Sprield96b8012012-12-05 15:26:02 +01001551 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001552
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001553 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001554}
1555
1556static s32 brcmf_set_wpa_version(struct net_device *ndev,
1557 struct cfg80211_connect_params *sme)
1558{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001559 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001560 struct brcmf_cfg80211_security *sec;
1561 s32 val = 0;
1562 s32 err = 0;
1563
1564 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1565 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1566 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1567 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1568 else
1569 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001570 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001571 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001572 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001573 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 return err;
1575 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001576 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577 sec->wpa_versions = sme->crypto.wpa_versions;
1578 return err;
1579}
1580
1581static s32 brcmf_set_auth_type(struct net_device *ndev,
1582 struct cfg80211_connect_params *sme)
1583{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001584 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001585 struct brcmf_cfg80211_security *sec;
1586 s32 val = 0;
1587 s32 err = 0;
1588
1589 switch (sme->auth_type) {
1590 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1591 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001592 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001593 break;
1594 case NL80211_AUTHTYPE_SHARED_KEY:
1595 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001596 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001597 break;
1598 case NL80211_AUTHTYPE_AUTOMATIC:
1599 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001600 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001601 break;
1602 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001603 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001604 default:
1605 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001606 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001607 break;
1608 }
1609
Hante Meuleman89286dc2013-02-08 15:53:46 +01001610 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001611 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001612 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001613 return err;
1614 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001615 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001616 sec->auth_type = sme->auth_type;
1617 return err;
1618}
1619
1620static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001621brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001622 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001624 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 struct brcmf_cfg80211_security *sec;
1626 s32 pval = 0;
1627 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001628 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629 s32 err = 0;
1630
1631 if (sme->crypto.n_ciphers_pairwise) {
1632 switch (sme->crypto.ciphers_pairwise[0]) {
1633 case WLAN_CIPHER_SUITE_WEP40:
1634 case WLAN_CIPHER_SUITE_WEP104:
1635 pval = WEP_ENABLED;
1636 break;
1637 case WLAN_CIPHER_SUITE_TKIP:
1638 pval = TKIP_ENABLED;
1639 break;
1640 case WLAN_CIPHER_SUITE_CCMP:
1641 pval = AES_ENABLED;
1642 break;
1643 case WLAN_CIPHER_SUITE_AES_CMAC:
1644 pval = AES_ENABLED;
1645 break;
1646 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001647 brcmf_err("invalid cipher pairwise (%d)\n",
1648 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001649 return -EINVAL;
1650 }
1651 }
1652 if (sme->crypto.cipher_group) {
1653 switch (sme->crypto.cipher_group) {
1654 case WLAN_CIPHER_SUITE_WEP40:
1655 case WLAN_CIPHER_SUITE_WEP104:
1656 gval = WEP_ENABLED;
1657 break;
1658 case WLAN_CIPHER_SUITE_TKIP:
1659 gval = TKIP_ENABLED;
1660 break;
1661 case WLAN_CIPHER_SUITE_CCMP:
1662 gval = AES_ENABLED;
1663 break;
1664 case WLAN_CIPHER_SUITE_AES_CMAC:
1665 gval = AES_ENABLED;
1666 break;
1667 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001668 brcmf_err("invalid cipher group (%d)\n",
1669 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001670 return -EINVAL;
1671 }
1672 }
1673
Arend van Spriel16886732012-12-05 15:26:04 +01001674 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001675 /* In case of privacy, but no security and WPS then simulate */
1676 /* setting AES. WPS-2.0 allows no security */
1677 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1678 sme->privacy)
1679 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001680
Hante Meuleman240d61a2016-02-17 11:27:10 +01001681 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001682 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001683 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001684 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001685 return err;
1686 }
1687
Arend van Spriel06bb1232012-09-27 14:17:56 +02001688 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001689 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1690 sec->cipher_group = sme->crypto.cipher_group;
1691
1692 return err;
1693}
1694
1695static s32
1696brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1697{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001698 struct brcmf_if *ifp = netdev_priv(ndev);
1699 s32 val;
1700 s32 err;
1701 const struct brcmf_tlv *rsn_ie;
1702 const u8 *ie;
1703 u32 ie_len;
1704 u32 offset;
1705 u16 rsn_cap;
1706 u32 mfp;
1707 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001708
Hante Meuleman240d61a2016-02-17 11:27:10 +01001709 if (!sme->crypto.n_akm_suites)
1710 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001711
Hante Meuleman240d61a2016-02-17 11:27:10 +01001712 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1713 if (err) {
1714 brcmf_err("could not get wpa_auth (%d)\n", err);
1715 return err;
1716 }
1717 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1718 switch (sme->crypto.akm_suites[0]) {
1719 case WLAN_AKM_SUITE_8021X:
1720 val = WPA_AUTH_UNSPECIFIED;
1721 break;
1722 case WLAN_AKM_SUITE_PSK:
1723 val = WPA_AUTH_PSK;
1724 break;
1725 default:
1726 brcmf_err("invalid cipher group (%d)\n",
1727 sme->crypto.cipher_group);
1728 return -EINVAL;
1729 }
1730 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1731 switch (sme->crypto.akm_suites[0]) {
1732 case WLAN_AKM_SUITE_8021X:
1733 val = WPA2_AUTH_UNSPECIFIED;
1734 break;
1735 case WLAN_AKM_SUITE_8021X_SHA256:
1736 val = WPA2_AUTH_1X_SHA256;
1737 break;
1738 case WLAN_AKM_SUITE_PSK_SHA256:
1739 val = WPA2_AUTH_PSK_SHA256;
1740 break;
1741 case WLAN_AKM_SUITE_PSK:
1742 val = WPA2_AUTH_PSK;
1743 break;
1744 default:
1745 brcmf_err("invalid cipher group (%d)\n",
1746 sme->crypto.cipher_group);
1747 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001748 }
1749 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001750
1751 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1752 goto skip_mfp_config;
1753 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1754 * IE will not be verified, just a quick search for MFP config
1755 */
1756 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1757 WLAN_EID_RSN);
1758 if (!rsn_ie)
1759 goto skip_mfp_config;
1760 ie = (const u8 *)rsn_ie;
1761 ie_len = rsn_ie->len + TLV_HDR_LEN;
1762 /* Skip unicast suite */
1763 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1764 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1765 goto skip_mfp_config;
1766 /* Skip multicast suite */
1767 count = ie[offset] + (ie[offset + 1] << 8);
1768 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1769 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1770 goto skip_mfp_config;
1771 /* Skip auth key management suite(s) */
1772 count = ie[offset] + (ie[offset + 1] << 8);
1773 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1774 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1775 goto skip_mfp_config;
1776 /* Ready to read capabilities */
1777 mfp = BRCMF_MFP_NONE;
1778 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1779 if (rsn_cap & RSN_CAP_MFPR_MASK)
1780 mfp = BRCMF_MFP_REQUIRED;
1781 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1782 mfp = BRCMF_MFP_CAPABLE;
1783 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1784
1785skip_mfp_config:
1786 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1787 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1788 if (err) {
1789 brcmf_err("could not set wpa_auth (%d)\n", err);
1790 return err;
1791 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001792
1793 return err;
1794}
1795
1796static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001797brcmf_set_sharedkey(struct net_device *ndev,
1798 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001799{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001800 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001801 struct brcmf_cfg80211_security *sec;
1802 struct brcmf_wsec_key key;
1803 s32 val;
1804 s32 err = 0;
1805
Arend van Spriel16886732012-12-05 15:26:04 +01001806 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001807
Roland Vossena718e2f2011-10-12 20:51:24 +02001808 if (sme->key_len == 0)
1809 return 0;
1810
Arend van Spriel06bb1232012-09-27 14:17:56 +02001811 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001812 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1813 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001814
1815 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1816 return 0;
1817
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001818 if (!(sec->cipher_pairwise &
1819 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1820 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001821
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001822 memset(&key, 0, sizeof(key));
1823 key.len = (u32) sme->key_len;
1824 key.index = (u32) sme->key_idx;
1825 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001826 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001827 return -EINVAL;
1828 }
1829 memcpy(key.data, sme->key, key.len);
1830 key.flags = BRCMF_PRIMARY_KEY;
1831 switch (sec->cipher_pairwise) {
1832 case WLAN_CIPHER_SUITE_WEP40:
1833 key.algo = CRYPTO_ALGO_WEP1;
1834 break;
1835 case WLAN_CIPHER_SUITE_WEP104:
1836 key.algo = CRYPTO_ALGO_WEP128;
1837 break;
1838 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001839 brcmf_err("Invalid algorithm (%d)\n",
1840 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001841 return -EINVAL;
1842 }
1843 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001844 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1845 key.len, key.index, key.algo);
1846 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001847 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001848 if (err)
1849 return err;
1850
1851 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001852 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001853 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001854 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001855 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001856 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001857 }
1858 return err;
1859}
1860
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001861static
1862enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1863 enum nl80211_auth_type type)
1864{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001865 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1866 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1867 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1868 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001869 }
1870 return type;
1871}
1872
Arend van Spriel7705ba62016-04-17 16:44:58 +02001873static void brcmf_set_join_pref(struct brcmf_if *ifp,
1874 struct cfg80211_bss_selection *bss_select)
1875{
1876 struct brcmf_join_pref_params join_pref_params[2];
1877 enum nl80211_band band;
1878 int err, i = 0;
1879
1880 join_pref_params[i].len = 2;
1881 join_pref_params[i].rssi_gain = 0;
1882
1883 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1884 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1885
1886 switch (bss_select->behaviour) {
1887 case __NL80211_BSS_SELECT_ATTR_INVALID:
1888 brcmf_c_set_joinpref_default(ifp);
1889 return;
1890 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1891 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1892 band = bss_select->param.band_pref;
1893 join_pref_params[i].band = nl80211_band_to_fwil(band);
1894 i++;
1895 break;
1896 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1897 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1898 band = bss_select->param.adjust.band;
1899 join_pref_params[i].band = nl80211_band_to_fwil(band);
1900 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1901 i++;
1902 break;
1903 case NL80211_BSS_SELECT_ATTR_RSSI:
1904 default:
1905 break;
1906 }
1907 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1908 join_pref_params[i].len = 2;
1909 join_pref_params[i].rssi_gain = 0;
1910 join_pref_params[i].band = 0;
1911 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1912 sizeof(join_pref_params));
1913 if (err)
1914 brcmf_err("Set join_pref error (%d)\n", err);
1915}
1916
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917static s32
1918brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001919 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001920{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001921 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001922 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001923 struct ieee80211_channel *chan = sme->channel;
1924 struct brcmf_join_params join_params;
1925 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001926 const struct brcmf_tlv *rsn_ie;
1927 const struct brcmf_vs_tlv *wpa_ie;
1928 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001929 u32 ie_len;
1930 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001931 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001932 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001933 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001934
Arend van Sprield96b8012012-12-05 15:26:02 +01001935 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001936 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001937 return -EIO;
1938
1939 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001940 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001941 return -EOPNOTSUPP;
1942 }
1943
Hante Meuleman89286dc2013-02-08 15:53:46 +01001944 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1945 /* A normal (non P2P) connection request setup. */
1946 ie = NULL;
1947 ie_len = 0;
1948 /* find the WPA_IE */
1949 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1950 if (wpa_ie) {
1951 ie = wpa_ie;
1952 ie_len = wpa_ie->len + TLV_HDR_LEN;
1953 } else {
1954 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001955 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1956 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001957 WLAN_EID_RSN);
1958 if (rsn_ie) {
1959 ie = rsn_ie;
1960 ie_len = rsn_ie->len + TLV_HDR_LEN;
1961 }
1962 }
1963 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1964 }
1965
1966 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1967 sme->ie, sme->ie_len);
1968 if (err)
1969 brcmf_err("Set Assoc REQ IE Failed\n");
1970 else
1971 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1972
Arend van Sprielc1179032012-10-22 13:55:33 -07001973 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001974
1975 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001976 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001977 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001978 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001979 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1980 cfg->channel, chan->center_freq, chanspec);
1981 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001982 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001983 chanspec = 0;
1984 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001986 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001987
1988 err = brcmf_set_wpa_version(ndev, sme);
1989 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001990 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001991 goto done;
1992 }
1993
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001994 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001995 err = brcmf_set_auth_type(ndev, sme);
1996 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001997 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001998 goto done;
1999 }
2000
Hante Meuleman240d61a2016-02-17 11:27:10 +01002001 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002002 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002003 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002004 goto done;
2005 }
2006
2007 err = brcmf_set_key_mgmt(ndev, sme);
2008 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002009 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002010 goto done;
2011 }
2012
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002013 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002014 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002015 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002016 goto done;
2017 }
2018
Hante Meuleman89286dc2013-02-08 15:53:46 +01002019 /* Join with specific BSSID and cached SSID
2020 * If SSID is zero join based on BSSID only
2021 */
2022 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2023 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2024 if (cfg->channel)
2025 join_params_size += sizeof(u16);
2026 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2027 if (ext_join_params == NULL) {
2028 err = -ENOMEM;
2029 goto done;
2030 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002031 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2032 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2033 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2034 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2035 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2036 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002037
Hante Meuleman89286dc2013-02-08 15:53:46 +01002038 /* Set up join scan parameters */
2039 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002040 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2041
2042 if (sme->bssid)
2043 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2044 else
Joe Perches93803b32015-03-02 19:54:49 -08002045 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002046
2047 if (cfg->channel) {
2048 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2049
2050 ext_join_params->assoc_le.chanspec_list[0] =
2051 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002052 /* Increase dwell time to receive probe response or detect
2053 * beacon from target AP at a noisy air only during connect
2054 * command.
2055 */
2056 ext_join_params->scan_le.active_time =
2057 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2058 ext_join_params->scan_le.passive_time =
2059 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2060 /* To sync with presence period of VSDB GO send probe request
2061 * more frequently. Probe request will be stopped when it gets
2062 * probe response from target AP/GO.
2063 */
2064 ext_join_params->scan_le.nprobes =
2065 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2066 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2067 } else {
2068 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2069 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2070 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002071 }
2072
Arend van Spriel7705ba62016-04-17 16:44:58 +02002073 brcmf_set_join_pref(ifp, &sme->bss_select);
2074
Hante Meuleman89286dc2013-02-08 15:53:46 +01002075 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2076 join_params_size);
2077 kfree(ext_join_params);
2078 if (!err)
2079 /* This is it. join command worked, we are done */
2080 goto done;
2081
2082 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002083 memset(&join_params, 0, sizeof(join_params));
2084 join_params_size = sizeof(join_params.ssid_le);
2085
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002086 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2087 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088
Hante Meuleman89286dc2013-02-08 15:53:46 +01002089 if (sme->bssid)
2090 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2091 else
Joe Perches93803b32015-03-02 19:54:49 -08002092 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002093
Hante Meuleman17012612013-02-06 18:40:44 +01002094 if (cfg->channel) {
2095 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2096 join_params.params_le.chanspec_num = cpu_to_le32(1);
2097 join_params_size += sizeof(join_params.params_le);
2098 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002099 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002100 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002101 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002102 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002103
2104done:
2105 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002106 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002107 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002108 return err;
2109}
2110
2111static s32
2112brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2113 u16 reason_code)
2114{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002115 struct brcmf_if *ifp = netdev_priv(ndev);
2116 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117 struct brcmf_scb_val_le scbval;
2118 s32 err = 0;
2119
Arend van Sprield96b8012012-12-05 15:26:02 +01002120 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002121 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002122 return -EIO;
2123
Arend van Sprielc1179032012-10-22 13:55:33 -07002124 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002125 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002126 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127
Arend van Spriel06bb1232012-09-27 14:17:56 +02002128 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002130 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002131 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002133 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002134
Arend van Sprield96b8012012-12-05 15:26:02 +01002135 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136 return err;
2137}
2138
2139static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002140brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002141 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002143 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002144 struct net_device *ndev = cfg_to_ndev(cfg);
2145 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002146 s32 err;
2147 s32 disable;
2148 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002150 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002151 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152 return -EIO;
2153
2154 switch (type) {
2155 case NL80211_TX_POWER_AUTOMATIC:
2156 break;
2157 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002158 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002159 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002160 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002161 err = -EINVAL;
2162 goto done;
2163 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002164 qdbm = MBM_TO_DBM(4 * mbm);
2165 if (qdbm > 127)
2166 qdbm = 127;
2167 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002168 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002169 default:
2170 brcmf_err("Unsupported type %d\n", type);
2171 err = -EINVAL;
2172 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173 }
2174 /* Make sure radio is off or on as far as software is concerned */
2175 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002176 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002177 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002178 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002179
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002180 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002182 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002183
2184done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002185 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002186 return err;
2187}
2188
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002189static s32
2190brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2191 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002192{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002193 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002194 struct net_device *ndev = cfg_to_ndev(cfg);
2195 struct brcmf_if *ifp = netdev_priv(ndev);
2196 s32 qdbm = 0;
2197 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002198
Arend van Sprield96b8012012-12-05 15:26:02 +01002199 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002200 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201 return -EIO;
2202
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002203 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002204 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002205 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002206 goto done;
2207 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002208 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002209
2210done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002211 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002212 return err;
2213}
2214
2215static s32
2216brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002217 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002218{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002219 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220 u32 index;
2221 u32 wsec;
2222 s32 err = 0;
2223
Arend van Sprield96b8012012-12-05 15:26:02 +01002224 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002225 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002226 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002227 return -EIO;
2228
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002229 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002230 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002231 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 goto done;
2233 }
2234
2235 if (wsec & WEP_ENABLED) {
2236 /* Just select a new current key */
2237 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002238 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002239 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002240 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002241 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002242 }
2243done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002244 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 return err;
2246}
2247
2248static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002249brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2250 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251{
Hante Meuleman992f6062013-04-02 21:06:17 +02002252 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002253 struct brcmf_wsec_key *key;
2254 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002255
2256 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002257 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2258
Hante Meuleman219e0f72016-02-17 11:27:09 +01002259 if (!check_vif_up(ifp->vif))
2260 return -EIO;
2261
2262 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2263 /* we ignore this key index in this case */
2264 return -EINVAL;
2265 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002266
Hante Meuleman240d61a2016-02-17 11:27:10 +01002267 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002268
Hante Meuleman240d61a2016-02-17 11:27:10 +01002269 if (key->algo == CRYPTO_ALGO_OFF) {
2270 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2271 return -EINVAL;
2272 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002273
Hante Meuleman240d61a2016-02-17 11:27:10 +01002274 memset(key, 0, sizeof(*key));
2275 key->index = (u32)key_idx;
2276 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277
Hante Meuleman240d61a2016-02-17 11:27:10 +01002278 /* Clear the key/index */
2279 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002280
Hante Meuleman219e0f72016-02-17 11:27:09 +01002281 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002282 return err;
2283}
2284
2285static s32
2286brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002287 u8 key_idx, bool pairwise, const u8 *mac_addr,
2288 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002290 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002291 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 s32 val;
2293 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002294 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002295 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002296 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002297
Arend van Sprield96b8012012-12-05 15:26:02 +01002298 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002299 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002300 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 return -EIO;
2302
Hante Meuleman118eb302014-12-21 12:43:49 +01002303 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2304 /* we ignore this key index in this case */
2305 brcmf_err("invalid key index (%d)\n", key_idx);
2306 return -EINVAL;
2307 }
2308
Hante Meuleman219e0f72016-02-17 11:27:09 +01002309 if (params->key_len == 0)
2310 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2311 mac_addr);
2312
2313 if (params->key_len > sizeof(key->data)) {
2314 brcmf_err("Too long key length (%u)\n", params->key_len);
2315 return -EINVAL;
2316 }
2317
2318 ext_key = false;
2319 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2320 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2321 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2322 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324
Hante Meuleman118eb302014-12-21 12:43:49 +01002325 key = &ifp->vif->profile.key[key_idx];
2326 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002327 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2328 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002329 key->len = params->key_len;
2330 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002331 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002332 if (!ext_key)
2333 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002334
Arend van Spriel5b435de2011-10-05 13:19:03 +02002335 switch (params->cipher) {
2336 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002337 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002338 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002339 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002340 break;
2341 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002342 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002343 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002344 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002345 break;
2346 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002347 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002348 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002349 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2350 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2351 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002352 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002353 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002354 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002355 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356 break;
2357 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002358 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002359 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002360 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002361 break;
2362 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002363 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002364 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002365 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 break;
2367 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002368 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 err = -EINVAL;
2370 goto done;
2371 }
2372
Hante Meuleman118eb302014-12-21 12:43:49 +01002373 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002374 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002375 goto done;
2376
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002377 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002379 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002380 goto done;
2381 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002383 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002384 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002385 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 goto done;
2387 }
2388
Arend van Spriel5b435de2011-10-05 13:19:03 +02002389done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002390 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002391 return err;
2392}
2393
2394static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002395brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2396 bool pairwise, const u8 *mac_addr, void *cookie,
2397 void (*callback)(void *cookie,
2398 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399{
2400 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002401 struct brcmf_if *ifp = netdev_priv(ndev);
2402 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002403 struct brcmf_cfg80211_security *sec;
2404 s32 wsec;
2405 s32 err = 0;
2406
Arend van Sprield96b8012012-12-05 15:26:02 +01002407 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002408 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002409 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002410 return -EIO;
2411
2412 memset(&params, 0, sizeof(params));
2413
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002414 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002416 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002417 /* Ignore this error, may happen during DISASSOC */
2418 err = -EAGAIN;
2419 goto done;
2420 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002421 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002422 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002423 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2424 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002425 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002426 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2427 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002428 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002429 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002430 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002431 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002432 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002433 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002435 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002436 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002437 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002438 err = -EINVAL;
2439 goto done;
2440 }
2441 callback(cookie, &params);
2442
2443done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002444 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002445 return err;
2446}
2447
2448static s32
2449brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002450 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002451{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002452 struct brcmf_if *ifp = netdev_priv(ndev);
2453
2454 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2455
2456 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2457 return 0;
2458
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002459 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002460
2461 return -EOPNOTSUPP;
2462}
2463
Hante Meuleman118eb302014-12-21 12:43:49 +01002464static void
2465brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2466{
2467 s32 err;
2468 u8 key_idx;
2469 struct brcmf_wsec_key *key;
2470 s32 wsec;
2471
2472 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2473 key = &ifp->vif->profile.key[key_idx];
2474 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2475 (key->algo == CRYPTO_ALGO_WEP128))
2476 break;
2477 }
2478 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2479 return;
2480
2481 err = send_key_to_dongle(ifp, key);
2482 if (err) {
2483 brcmf_err("Setting WEP key failed (%d)\n", err);
2484 return;
2485 }
2486 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2487 if (err) {
2488 brcmf_err("get wsec error (%d)\n", err);
2489 return;
2490 }
2491 wsec |= WEP_ENABLED;
2492 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2493 if (err)
2494 brcmf_err("set wsec error (%d)\n", err);
2495}
2496
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002497static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2498{
2499 struct nl80211_sta_flag_update *sfu;
2500
2501 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2502 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2503 sfu = &si->sta_flags;
2504 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2505 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2506 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2507 BIT(NL80211_STA_FLAG_AUTHORIZED);
2508 if (fw_sta_flags & BRCMF_STA_WME)
2509 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2510 if (fw_sta_flags & BRCMF_STA_AUTHE)
2511 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2512 if (fw_sta_flags & BRCMF_STA_ASSOC)
2513 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2514 if (fw_sta_flags & BRCMF_STA_AUTHO)
2515 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2516}
2517
2518static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2519{
2520 struct {
2521 __le32 len;
2522 struct brcmf_bss_info_le bss_le;
2523 } *buf;
2524 u16 capability;
2525 int err;
2526
2527 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2528 if (!buf)
2529 return;
2530
2531 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2532 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2533 WL_BSS_INFO_MAX);
2534 if (err) {
2535 brcmf_err("Failed to get bss info (%d)\n", err);
2536 return;
2537 }
2538 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2539 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2540 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2541 capability = le16_to_cpu(buf->bss_le.capability);
2542 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2543 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2544 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2545 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2546 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2547 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2548}
2549
Arend van Spriel5b435de2011-10-05 13:19:03 +02002550static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002551brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2552 struct station_info *sinfo)
2553{
2554 struct brcmf_scb_val_le scbval;
2555 struct brcmf_pktcnt_le pktcnt;
2556 s32 err;
2557 u32 rate;
2558 u32 rssi;
2559
2560 /* Get the current tx rate */
2561 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2562 if (err < 0) {
2563 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2564 return err;
2565 }
2566 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2567 sinfo->txrate.legacy = rate * 5;
2568
2569 memset(&scbval, 0, sizeof(scbval));
2570 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2571 sizeof(scbval));
2572 if (err) {
2573 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2574 return err;
2575 }
2576 rssi = le32_to_cpu(scbval.val);
2577 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2578 sinfo->signal = rssi;
2579
2580 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2581 sizeof(pktcnt));
2582 if (err) {
2583 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2584 return err;
2585 }
2586 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2587 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2588 BIT(NL80211_STA_INFO_TX_PACKETS) |
2589 BIT(NL80211_STA_INFO_TX_FAILED);
2590 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2591 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2592 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2593 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2594
2595 return 0;
2596}
2597
2598static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002599brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002600 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002601{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002602 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002603 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002604 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002605 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002606 u32 sta_flags;
2607 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002608 s32 total_rssi;
2609 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002610 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002611 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002612
Arend van Sprield96b8012012-12-05 15:26:02 +01002613 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002614 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002615 return -EIO;
2616
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002617 if (brcmf_is_ibssmode(ifp->vif))
2618 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2619
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002620 memset(&sta_info_le, 0, sizeof(sta_info_le));
2621 memcpy(&sta_info_le, mac, ETH_ALEN);
2622 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2623 &sta_info_le,
2624 sizeof(sta_info_le));
2625 is_tdls_peer = !err;
2626 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002627 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002628 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002629 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002630 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002631 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002632 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002633 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002634 }
2635 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2636 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2637 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2638 sta_flags = le32_to_cpu(sta_info_le.flags);
2639 brcmf_convert_sta_flags(sta_flags, sinfo);
2640 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2641 if (is_tdls_peer)
2642 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2643 else
2644 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2645 if (sta_flags & BRCMF_STA_ASSOC) {
2646 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2647 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2648 brcmf_fill_bss_param(ifp, sinfo);
2649 }
2650 if (sta_flags & BRCMF_STA_SCBSTATS) {
2651 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2652 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2653 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2654 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2655 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2656 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2657 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2658 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2659 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002660 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002661 sinfo->txrate.legacy =
2662 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002663 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002664 if (sinfo->rx_packets) {
2665 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002666 sinfo->rxrate.legacy =
2667 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002668 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002669 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2670 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2671 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2672 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2673 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2674 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002675 total_rssi = 0;
2676 count_rssi = 0;
2677 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2678 if (sta_info_le.rssi[i]) {
2679 sinfo->chain_signal_avg[count_rssi] =
2680 sta_info_le.rssi[i];
2681 sinfo->chain_signal[count_rssi] =
2682 sta_info_le.rssi[i];
2683 total_rssi += sta_info_le.rssi[i];
2684 count_rssi++;
2685 }
2686 }
2687 if (count_rssi) {
2688 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2689 sinfo->chains = count_rssi;
2690
2691 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2692 total_rssi /= count_rssi;
2693 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002694 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2695 &ifp->vif->sme_state)) {
2696 memset(&scb_val, 0, sizeof(scb_val));
2697 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2698 &scb_val, sizeof(scb_val));
2699 if (err) {
2700 brcmf_err("Could not get rssi (%d)\n", err);
2701 goto done;
2702 } else {
2703 rssi = le32_to_cpu(scb_val.val);
2704 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2705 sinfo->signal = rssi;
2706 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2707 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002708 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002709 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002711 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002712 return err;
2713}
2714
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002715static int
2716brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2717 int idx, u8 *mac, struct station_info *sinfo)
2718{
2719 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2720 struct brcmf_if *ifp = netdev_priv(ndev);
2721 s32 err;
2722
2723 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2724
2725 if (idx == 0) {
2726 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2727 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2728 &cfg->assoclist,
2729 sizeof(cfg->assoclist));
2730 if (err) {
2731 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2732 err);
2733 cfg->assoclist.count = 0;
2734 return -EOPNOTSUPP;
2735 }
2736 }
2737 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2738 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2739 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2740 }
2741 return -ENOENT;
2742}
2743
Arend van Spriel5b435de2011-10-05 13:19:03 +02002744static s32
2745brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2746 bool enabled, s32 timeout)
2747{
2748 s32 pm;
2749 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002750 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002751 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002752
Arend van Sprield96b8012012-12-05 15:26:02 +01002753 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002754
2755 /*
2756 * Powersave enable/disable request is coming from the
2757 * cfg80211 even before the interface is up. In that
2758 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002759 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002760 * FW later while initializing the dongle
2761 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002762 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002763 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002764
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002765 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766 goto done;
2767 }
2768
2769 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002770 /* Do not enable the power save after assoc if it is a p2p interface */
2771 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2772 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2773 pm = PM_OFF;
2774 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002775 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002776
Arend van Sprielc1179032012-10-22 13:55:33 -07002777 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002778 if (err) {
2779 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002780 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002781 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002782 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002783 }
2784done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002785 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002786 return err;
2787}
2788
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002789static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002790 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002791{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002792 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002793 struct ieee80211_channel *notify_channel;
2794 struct cfg80211_bss *bss;
2795 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002796 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 u16 channel;
2798 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002799 u16 notify_capability;
2800 u16 notify_interval;
2801 u8 *notify_ie;
2802 size_t notify_ielen;
2803 s32 notify_signal;
2804
2805 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002806 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807 return 0;
2808 }
2809
Franky Lin83cf17a2013-04-11 13:28:50 +02002810 if (!bi->ctl_ch) {
2811 ch.chspec = le16_to_cpu(bi->chanspec);
2812 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002813 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002814 }
2815 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002816
2817 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002818 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002820 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002821
2822 freq = ieee80211_channel_to_frequency(channel, band->band);
2823 notify_channel = ieee80211_get_channel(wiphy, freq);
2824
Arend van Spriel5b435de2011-10-05 13:19:03 +02002825 notify_capability = le16_to_cpu(bi->capability);
2826 notify_interval = le16_to_cpu(bi->beacon_period);
2827 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2828 notify_ielen = le32_to_cpu(bi->ie_length);
2829 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2830
Arend van Spriel16886732012-12-05 15:26:04 +01002831 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2832 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2833 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2834 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2835 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002836
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002837 bss = cfg80211_inform_bss(wiphy, notify_channel,
2838 CFG80211_BSS_FTYPE_UNKNOWN,
2839 (const u8 *)bi->BSSID,
2840 0, notify_capability,
2841 notify_interval, notify_ie,
2842 notify_ielen, notify_signal,
2843 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844
Franky Line78946e2011-11-10 20:30:34 +01002845 if (!bss)
2846 return -ENOMEM;
2847
Johannes Berg5b112d32013-02-01 01:49:58 +01002848 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002849
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002850 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851}
2852
Roland Vossen6f09be02011-10-18 14:03:02 +02002853static struct brcmf_bss_info_le *
2854next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2855{
2856 if (bss == NULL)
2857 return list->bss_info_le;
2858 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2859 le32_to_cpu(bss->length));
2860}
2861
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002862static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002863{
2864 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002865 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002866 s32 err = 0;
2867 int i;
2868
Hante Meulemanef8596e2014-09-30 10:23:13 +02002869 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002870 if (bss_list->count != 0 &&
2871 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002872 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2873 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002874 return -EOPNOTSUPP;
2875 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002876 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002877 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002878 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002879 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002880 if (err)
2881 break;
2882 }
2883 return err;
2884}
2885
Hante Meulemanb0a79082015-12-10 13:43:07 +01002886static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2887 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002888{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002889 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002890 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002891 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002892 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002893 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002894 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002895 u8 *buf = NULL;
2896 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002897 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898 u16 notify_capability;
2899 u16 notify_interval;
2900 u8 *notify_ie;
2901 size_t notify_ielen;
2902 s32 notify_signal;
2903
Arend van Sprield96b8012012-12-05 15:26:02 +01002904 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002905
2906 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2907 if (buf == NULL) {
2908 err = -ENOMEM;
2909 goto CleanUp;
2910 }
2911
2912 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2913
Arend van Sprielac24be62012-10-22 10:36:23 -07002914 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2915 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002916 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002917 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002918 goto CleanUp;
2919 }
2920
Roland Vossend34bf642011-10-18 14:03:01 +02002921 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002922
Franky Lin83cf17a2013-04-11 13:28:50 +02002923 ch.chspec = le16_to_cpu(bi->chanspec);
2924 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002925
Franky Lin83cf17a2013-04-11 13:28:50 +02002926 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002927 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002929 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002930
Rafał Miłecki4712d882016-05-20 13:38:57 +02002931 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002932 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002933 notify_channel = ieee80211_get_channel(wiphy, freq);
2934
Arend van Spriel5b435de2011-10-05 13:19:03 +02002935 notify_capability = le16_to_cpu(bi->capability);
2936 notify_interval = le16_to_cpu(bi->beacon_period);
2937 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2938 notify_ielen = le32_to_cpu(bi->ie_length);
2939 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2940
Rafał Miłecki4712d882016-05-20 13:38:57 +02002941 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002942 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2943 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2944 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002945
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002946 bss = cfg80211_inform_bss(wiphy, notify_channel,
2947 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2948 notify_capability, notify_interval,
2949 notify_ie, notify_ielen, notify_signal,
2950 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002951
Franky Line78946e2011-11-10 20:30:34 +01002952 if (!bss) {
2953 err = -ENOMEM;
2954 goto CleanUp;
2955 }
2956
Johannes Berg5b112d32013-02-01 01:49:58 +01002957 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002958
Arend van Spriel5b435de2011-10-05 13:19:03 +02002959CleanUp:
2960
2961 kfree(buf);
2962
Arend van Sprield96b8012012-12-05 15:26:02 +01002963 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002964
2965 return err;
2966}
2967
Hante Meuleman89286dc2013-02-08 15:53:46 +01002968static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2969 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002970{
Roland Vossend34bf642011-10-18 14:03:01 +02002971 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002972 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002973 u16 beacon_interval;
2974 u8 dtim_period;
2975 size_t ie_len;
2976 u8 *ie;
2977 s32 err = 0;
2978
Arend van Sprield96b8012012-12-05 15:26:02 +01002979 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002980 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002981 return err;
2982
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002983 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002984 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002985 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002986 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002987 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002988 goto update_bss_info_out;
2989 }
2990
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002991 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2992 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002993 if (err)
2994 goto update_bss_info_out;
2995
2996 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2997 ie_len = le32_to_cpu(bi->ie_length);
2998 beacon_interval = le16_to_cpu(bi->beacon_period);
2999
Alwin Beukersf8e4b412011-10-12 20:51:28 +02003000 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003001 if (tim)
3002 dtim_period = tim->data[1];
3003 else {
3004 /*
3005 * active scan was done so we could not get dtim
3006 * information out of probe response.
3007 * so we speficially query dtim information to dongle.
3008 */
3009 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07003010 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003011 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003012 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003013 goto update_bss_info_out;
3014 }
3015 dtim_period = (u8)var;
3016 }
3017
Arend van Spriel5b435de2011-10-05 13:19:03 +02003018update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003019 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003020 return err;
3021}
3022
Hante Meuleman18e2f612013-02-08 15:53:49 +01003023void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003024{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003025 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003026
Arend van Sprielc1179032012-10-22 13:55:33 -07003027 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08003028 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003029 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003030 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003031 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003032 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3033 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003034}
3035
Hante Meulemane756af52012-09-11 21:18:52 +02003036static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3037{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003038 struct brcmf_cfg80211_info *cfg =
3039 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003040 escan_timeout_work);
3041
Hante Meulemanef8596e2014-09-30 10:23:13 +02003042 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003043 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003044}
3045
3046static void brcmf_escan_timeout(unsigned long data)
3047{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003048 struct brcmf_cfg80211_info *cfg =
3049 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003050
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003051 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003052 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003053 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003054 }
3055}
3056
3057static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003058brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3059 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003060 struct brcmf_bss_info_le *bss_info_le)
3061{
Franky Lin83cf17a2013-04-11 13:28:50 +02003062 struct brcmu_chan ch_bss, ch_bss_info_le;
3063
3064 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3065 cfg->d11inf.decchspec(&ch_bss);
3066 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3067 cfg->d11inf.decchspec(&ch_bss_info_le);
3068
Hante Meulemane756af52012-09-11 21:18:52 +02003069 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003070 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003071 bss_info_le->SSID_len == bss->SSID_len &&
3072 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003073 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3074 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003075 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3076 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3077
Hante Meulemane756af52012-09-11 21:18:52 +02003078 /* preserve max RSSI if the measurements are
3079 * both on-channel or both off-channel
3080 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003081 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003082 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003083 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3084 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003085 /* preserve the on-channel rssi measurement
3086 * if the new measurement is off channel
3087 */
3088 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003089 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003090 }
3091 return 1;
3092 }
3093 return 0;
3094}
3095
3096static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003097brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003098 const struct brcmf_event_msg *e, void *data)
3099{
Arend van Spriel19937322012-11-05 16:22:32 -08003100 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003101 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003102 struct brcmf_escan_result_le *escan_result_le;
3103 struct brcmf_bss_info_le *bss_info_le;
3104 struct brcmf_bss_info_le *bss = NULL;
3105 u32 bi_length;
3106 struct brcmf_scan_results *list;
3107 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003108 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003109
Arend van Spriel5c36b992012-11-14 18:46:05 -08003110 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003111
Arend van Spriela0f472a2013-04-05 10:57:49 +02003112 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003113 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003114 return -EPERM;
3115 }
3116
3117 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003118 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003119 escan_result_le = (struct brcmf_escan_result_le *) data;
3120 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003121 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003122 goto exit;
3123 }
Hante Meulemane756af52012-09-11 21:18:52 +02003124 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003125 brcmf_err("Invalid bss_count %d: ignoring\n",
3126 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003127 goto exit;
3128 }
3129 bss_info_le = &escan_result_le->bss_info_le;
3130
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003131 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3132 goto exit;
3133
3134 if (!cfg->scan_request) {
3135 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3136 goto exit;
3137 }
3138
Hante Meulemane756af52012-09-11 21:18:52 +02003139 bi_length = le32_to_cpu(bss_info_le->length);
3140 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3141 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003142 brcmf_err("Invalid bss_info length %d: ignoring\n",
3143 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003144 goto exit;
3145 }
3146
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003147 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003148 BIT(NL80211_IFTYPE_ADHOC))) {
3149 if (le16_to_cpu(bss_info_le->capability) &
3150 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003151 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003152 goto exit;
3153 }
3154 }
3155
3156 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003157 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003158 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003159 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003160 goto exit;
3161 }
3162
3163 for (i = 0; i < list->count; i++) {
3164 bss = bss ? (struct brcmf_bss_info_le *)
3165 ((unsigned char *)bss +
3166 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003167 if (brcmf_compare_update_same_bss(cfg, bss,
3168 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003169 goto exit;
3170 }
Hante Meulemand5367332016-02-17 11:26:51 +01003171 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3172 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003173 list->version = le32_to_cpu(bss_info_le->version);
3174 list->buflen += bi_length;
3175 list->count++;
3176 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003177 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003178 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3179 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003180 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003181 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003182 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003183 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003184 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003185 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3186 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003187 }
3188exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003189 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003190}
3191
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003192static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003193{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003194 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3195 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003196 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3197 /* Init scan_timeout timer */
3198 init_timer(&cfg->escan_timeout);
3199 cfg->escan_timeout.data = (unsigned long) cfg;
3200 cfg->escan_timeout.function = brcmf_escan_timeout;
3201 INIT_WORK(&cfg->escan_timeout_work,
3202 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003203}
3204
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003205/* PFN result doesn't have all the info which are required by the supplicant
3206 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3207 * via wl_inform_single_bss in the required format. Escan does require the
3208 * scan request in the form of cfg80211_scan_request. For timebeing, create
3209 * cfg80211_scan_request one out of the received PNO event.
3210 */
3211static s32
3212brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3213 const struct brcmf_event_msg *e, void *data)
3214{
3215 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3216 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3217 struct cfg80211_scan_request *request = NULL;
3218 struct cfg80211_ssid *ssid = NULL;
3219 struct ieee80211_channel *channel = NULL;
3220 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3221 int err = 0;
3222 int channel_req = 0;
3223 int band = 0;
3224 struct brcmf_pno_scanresults_le *pfn_result;
3225 u32 result_count;
3226 u32 status;
3227
3228 brcmf_dbg(SCAN, "Enter\n");
3229
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003230 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3231 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3232 return 0;
3233 }
3234
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003235 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3236 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3237 return 0;
3238 }
3239
3240 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3241 result_count = le32_to_cpu(pfn_result->count);
3242 status = le32_to_cpu(pfn_result->status);
3243
3244 /* PFN event is limited to fit 512 bytes so we may get
3245 * multiple NET_FOUND events. For now place a warning here.
3246 */
3247 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3248 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3249 if (result_count > 0) {
3250 int i;
3251
3252 request = kzalloc(sizeof(*request), GFP_KERNEL);
3253 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3254 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3255 if (!request || !ssid || !channel) {
3256 err = -ENOMEM;
3257 goto out_err;
3258 }
3259
3260 request->wiphy = wiphy;
3261 data += sizeof(struct brcmf_pno_scanresults_le);
3262 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3263
3264 for (i = 0; i < result_count; i++) {
3265 netinfo = &netinfo_start[i];
3266 if (!netinfo) {
3267 brcmf_err("Invalid netinfo ptr. index: %d\n",
3268 i);
3269 err = -EINVAL;
3270 goto out_err;
3271 }
3272
3273 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3274 netinfo->SSID, netinfo->channel);
3275 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3276 ssid[i].ssid_len = netinfo->SSID_len;
3277 request->n_ssids++;
3278
3279 channel_req = netinfo->channel;
3280 if (channel_req <= CH_MAX_2G_CHANNEL)
3281 band = NL80211_BAND_2GHZ;
3282 else
3283 band = NL80211_BAND_5GHZ;
3284 channel[i].center_freq =
3285 ieee80211_channel_to_frequency(channel_req,
3286 band);
3287 channel[i].band = band;
3288 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3289 request->channels[i] = &channel[i];
3290 request->n_channels++;
3291 }
3292
3293 /* assign parsed ssid array */
3294 if (request->n_ssids)
3295 request->ssids = &ssid[0];
3296
3297 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3298 /* Abort any on-going scan */
3299 brcmf_abort_scanning(cfg);
3300 }
3301
3302 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3303 cfg->escan_info.run = brcmf_run_escan;
3304 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3305 if (err) {
3306 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3307 goto out_err;
3308 }
3309 cfg->sched_escan = true;
3310 cfg->scan_request = request;
3311 } else {
3312 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3313 goto out_err;
3314 }
3315
3316 kfree(ssid);
3317 kfree(channel);
3318 kfree(request);
3319 return 0;
3320
3321out_err:
3322 kfree(ssid);
3323 kfree(channel);
3324 kfree(request);
3325 cfg80211_sched_scan_stopped(wiphy);
3326 return err;
3327}
3328
3329static int brcmf_dev_pno_clean(struct net_device *ndev)
3330{
3331 int ret;
3332
3333 /* Disable pfn */
3334 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3335 if (ret == 0) {
3336 /* clear pfn */
3337 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3338 NULL, 0);
3339 }
3340 if (ret < 0)
3341 brcmf_err("failed code %d\n", ret);
3342
3343 return ret;
3344}
3345
3346static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3347 struct cfg80211_sched_scan_request *request)
3348{
3349 struct brcmf_pno_param_le pfn_param;
3350 struct brcmf_pno_macaddr_le pfn_mac;
3351 s32 err;
3352 u8 *mac_mask;
3353 int i;
3354
3355 memset(&pfn_param, 0, sizeof(pfn_param));
3356 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3357
3358 /* set extra pno params */
3359 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3360 pfn_param.repeat = BRCMF_PNO_REPEAT;
3361 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3362
3363 /* set up pno scan fr */
3364 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3365
3366 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3367 sizeof(pfn_param));
3368 if (err) {
3369 brcmf_err("pfn_set failed, err=%d\n", err);
3370 return err;
3371 }
3372
3373 /* Find out if mac randomization should be turned on */
3374 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3375 return 0;
3376
3377 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3378 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3379
3380 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3381 mac_mask = request->mac_addr_mask;
3382 for (i = 0; i < ETH_ALEN; i++) {
3383 pfn_mac.mac[i] &= mac_mask[i];
3384 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3385 }
3386 /* Clear multi bit */
3387 pfn_mac.mac[0] &= 0xFE;
3388 /* Set locally administered */
3389 pfn_mac.mac[0] |= 0x02;
3390
3391 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3392 sizeof(pfn_mac));
3393 if (err)
3394 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3395
3396 return err;
3397}
3398
3399static int
3400brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3401 struct net_device *ndev,
3402 struct cfg80211_sched_scan_request *request)
3403{
3404 struct brcmf_if *ifp = netdev_priv(ndev);
3405 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3406 struct brcmf_pno_net_param_le pfn;
3407 int i;
3408 int ret = 0;
3409
3410 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3411 request->n_match_sets, request->n_ssids);
3412 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3413 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3414 return -EAGAIN;
3415 }
3416 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3417 brcmf_err("Scanning suppressed: status (%lu)\n",
3418 cfg->scan_status);
3419 return -EAGAIN;
3420 }
3421
3422 if (!request->n_ssids || !request->n_match_sets) {
3423 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3424 request->n_ssids);
3425 return -EINVAL;
3426 }
3427
3428 if (request->n_ssids > 0) {
3429 for (i = 0; i < request->n_ssids; i++) {
3430 /* Active scan req for ssids */
3431 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3432 request->ssids[i].ssid);
3433
3434 /* match_set ssids is a supert set of n_ssid list,
3435 * so we need not add these set separately.
3436 */
3437 }
3438 }
3439
3440 if (request->n_match_sets > 0) {
3441 /* clean up everything */
3442 ret = brcmf_dev_pno_clean(ndev);
3443 if (ret < 0) {
3444 brcmf_err("failed error=%d\n", ret);
3445 return ret;
3446 }
3447
3448 /* configure pno */
3449 if (brcmf_dev_pno_config(ifp, request))
3450 return -EINVAL;
3451
3452 /* configure each match set */
3453 for (i = 0; i < request->n_match_sets; i++) {
3454 struct cfg80211_ssid *ssid;
3455 u32 ssid_len;
3456
3457 ssid = &request->match_sets[i].ssid;
3458 ssid_len = ssid->ssid_len;
3459
3460 if (!ssid_len) {
3461 brcmf_err("skip broadcast ssid\n");
3462 continue;
3463 }
3464 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3465 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3466 pfn.wsec = cpu_to_le32(0);
3467 pfn.infra = cpu_to_le32(1);
3468 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3469 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3470 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3471 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3472 sizeof(pfn));
3473 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3474 ret == 0 ? "set" : "failed", ssid->ssid);
3475 }
3476 /* Enable the PNO */
3477 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3478 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3479 return -EINVAL;
3480 }
3481 } else {
3482 return -EINVAL;
3483 }
3484
3485 return 0;
3486}
3487
3488static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3489 struct net_device *ndev)
3490{
3491 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3492
3493 brcmf_dbg(SCAN, "enter\n");
3494 brcmf_dev_pno_clean(ndev);
3495 if (cfg->sched_escan)
3496 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3497 return 0;
3498}
3499
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003500static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003501{
3502 if (ms < 1000 / HZ) {
3503 cond_resched();
3504 mdelay(ms);
3505 } else {
3506 msleep(ms);
3507 }
3508}
3509
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003510static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3511 u8 *pattern, u32 patternsize, u8 *mask,
3512 u32 packet_offset)
3513{
3514 struct brcmf_fil_wowl_pattern_le *filter;
3515 u32 masksize;
3516 u32 patternoffset;
3517 u8 *buf;
3518 u32 bufsize;
3519 s32 ret;
3520
3521 masksize = (patternsize + 7) / 8;
3522 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3523
3524 bufsize = sizeof(*filter) + patternsize + masksize;
3525 buf = kzalloc(bufsize, GFP_KERNEL);
3526 if (!buf)
3527 return -ENOMEM;
3528 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3529
3530 memcpy(filter->cmd, cmd, 4);
3531 filter->masksize = cpu_to_le32(masksize);
3532 filter->offset = cpu_to_le32(packet_offset);
3533 filter->patternoffset = cpu_to_le32(patternoffset);
3534 filter->patternsize = cpu_to_le32(patternsize);
3535 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3536
3537 if ((mask) && (masksize))
3538 memcpy(buf + sizeof(*filter), mask, masksize);
3539 if ((pattern) && (patternsize))
3540 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3541
3542 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3543
3544 kfree(buf);
3545 return ret;
3546}
3547
Hante Meuleman3021ad92016-01-05 11:05:45 +01003548static s32
3549brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3550 void *data)
3551{
3552 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3553 struct brcmf_pno_scanresults_le *pfn_result;
3554 struct brcmf_pno_net_info_le *netinfo;
3555
3556 brcmf_dbg(SCAN, "Enter\n");
3557
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003558 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3559 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3560 return 0;
3561 }
3562
Hante Meuleman3021ad92016-01-05 11:05:45 +01003563 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3564
3565 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3566 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3567 return 0;
3568 }
3569
3570 if (le32_to_cpu(pfn_result->count) < 1) {
3571 brcmf_err("Invalid result count, expected 1 (%d)\n",
3572 le32_to_cpu(pfn_result->count));
3573 return -EINVAL;
3574 }
3575
3576 data += sizeof(struct brcmf_pno_scanresults_le);
3577 netinfo = (struct brcmf_pno_net_info_le *)data;
3578 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3579 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3580 cfg->wowl.nd->n_channels = 1;
3581 cfg->wowl.nd->channels[0] =
3582 ieee80211_channel_to_frequency(netinfo->channel,
3583 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3584 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3585 cfg->wowl.nd_info->n_matches = 1;
3586 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3587
3588 /* Inform (the resume task) that the net detect information was recvd */
3589 cfg->wowl.nd_data_completed = true;
3590 wake_up(&cfg->wowl.nd_data_wait);
3591
3592 return 0;
3593}
3594
Hante Meulemanaeb64222015-10-29 20:33:19 +01003595#ifdef CONFIG_PM
3596
3597static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3598{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003599 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003600 struct brcmf_wowl_wakeind_le wake_ind_le;
3601 struct cfg80211_wowlan_wakeup wakeup_data;
3602 struct cfg80211_wowlan_wakeup *wakeup;
3603 u32 wakeind;
3604 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003605 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003606
3607 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3608 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003609 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003610 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3611 return;
3612 }
3613
3614 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3615 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003616 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3617 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003618 wakeup = &wakeup_data;
3619 memset(&wakeup_data, 0, sizeof(wakeup_data));
3620 wakeup_data.pattern_idx = -1;
3621
3622 if (wakeind & BRCMF_WOWL_MAGIC) {
3623 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3624 wakeup_data.magic_pkt = true;
3625 }
3626 if (wakeind & BRCMF_WOWL_DIS) {
3627 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3628 wakeup_data.disconnect = true;
3629 }
3630 if (wakeind & BRCMF_WOWL_BCN) {
3631 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3632 wakeup_data.disconnect = true;
3633 }
3634 if (wakeind & BRCMF_WOWL_RETR) {
3635 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3636 wakeup_data.disconnect = true;
3637 }
3638 if (wakeind & BRCMF_WOWL_NET) {
3639 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3640 /* For now always map to pattern 0, no API to get
3641 * correct information available at the moment.
3642 */
3643 wakeup_data.pattern_idx = 0;
3644 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003645 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3646 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3647 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3648 cfg->wowl.nd_data_completed,
3649 BRCMF_ND_INFO_TIMEOUT);
3650 if (!timeout)
3651 brcmf_err("No result for wowl net detect\n");
3652 else
3653 wakeup_data.net_detect = cfg->wowl.nd_info;
3654 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003655 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3656 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3657 wakeup_data.gtk_rekey_failure = true;
3658 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003659 } else {
3660 wakeup = NULL;
3661 }
3662 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3663}
3664
3665#else
3666
3667static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3668{
3669}
3670
3671#endif /* CONFIG_PM */
3672
Arend van Spriel5b435de2011-10-05 13:19:03 +02003673static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3674{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003675 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3676 struct net_device *ndev = cfg_to_ndev(cfg);
3677 struct brcmf_if *ifp = netdev_priv(ndev);
3678
Arend van Sprield96b8012012-12-05 15:26:02 +01003679 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003680
Hante Meuleman3021ad92016-01-05 11:05:45 +01003681 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003682 brcmf_report_wowl_wakeind(wiphy, ifp);
3683 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3684 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003685 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3686 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003687 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003688 cfg->wowl.pre_pmmode);
3689 cfg->wowl.active = false;
3690 if (cfg->wowl.nd_enabled) {
3691 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3692 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3693 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3694 brcmf_notify_sched_scan_results);
3695 cfg->wowl.nd_enabled = false;
3696 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003697 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003698 return 0;
3699}
3700
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003701static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3702 struct brcmf_if *ifp,
3703 struct cfg80211_wowlan *wowl)
3704{
3705 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003706 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003707 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003708
3709 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3710
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003711 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3712 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003713 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003714 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3715
3716 wowl_config = 0;
3717 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003718 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003719 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003720 wowl_config |= BRCMF_WOWL_MAGIC;
3721 if ((wowl->patterns) && (wowl->n_patterns)) {
3722 wowl_config |= BRCMF_WOWL_NET;
3723 for (i = 0; i < wowl->n_patterns; i++) {
3724 brcmf_config_wowl_pattern(ifp, "add",
3725 (u8 *)wowl->patterns[i].pattern,
3726 wowl->patterns[i].pattern_len,
3727 (u8 *)wowl->patterns[i].mask,
3728 wowl->patterns[i].pkt_offset);
3729 }
3730 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003731 if (wowl->nd_config) {
3732 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3733 wowl->nd_config);
3734 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3735
3736 cfg->wowl.nd_data_completed = false;
3737 cfg->wowl.nd_enabled = true;
3738 /* Now reroute the event for PFN to the wowl function. */
3739 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3740 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3741 brcmf_wowl_nd_results);
3742 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003743 if (wowl->gtk_rekey_failure)
3744 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003745 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3746 wowl_config |= BRCMF_WOWL_UNASSOC;
3747
Hante Meulemana7ed7822016-09-19 12:09:58 +01003748 memcpy(&wowl_wakeind, "clear", 6);
3749 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3750 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003751 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3752 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3753 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003754 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003755}
3756
Arend van Spriel5b435de2011-10-05 13:19:03 +02003757static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003758 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003759{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003760 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3761 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003762 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003763 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764
Arend van Sprield96b8012012-12-05 15:26:02 +01003765 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003766
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003767 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003768 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003770 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003771 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003772
Hante Meuleman3021ad92016-01-05 11:05:45 +01003773 /* Stop scheduled scan */
3774 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3775 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3776
Arend van Spriel7d641072012-10-22 13:55:39 -07003777 /* end any scanning */
3778 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003779 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003781 if (wowl == NULL) {
3782 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3783 list_for_each_entry(vif, &cfg->vif_list, list) {
3784 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3785 continue;
3786 /* While going to suspend if associated with AP
3787 * disassociate from AP to save power while system is
3788 * in suspended state
3789 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003790 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003791 /* Make sure WPA_Supplicant receives all the event
3792 * generated due to DISASSOC call to the fw to keep
3793 * the state fw and WPA_Supplicant state consistent
3794 */
3795 brcmf_delay(500);
3796 }
3797 /* Configure MPC */
3798 brcmf_set_mpc(ifp, 1);
3799
3800 } else {
3801 /* Configure WOWL paramaters */
3802 brcmf_configure_wowl(cfg, ifp, wowl);
3803 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003804
Arend van Spriel7d641072012-10-22 13:55:39 -07003805exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003806 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003807 /* clear any scanning activity */
3808 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003809 return 0;
3810}
3811
3812static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003813brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003814{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003815 struct brcmf_pmk_list_le *pmk_list;
3816 int i;
3817 u32 npmk;
3818 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003819
Hante Meuleman6c404f32015-12-10 13:43:03 +01003820 pmk_list = &cfg->pmk_list;
3821 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003822
Hante Meuleman6c404f32015-12-10 13:43:03 +01003823 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3824 for (i = 0; i < npmk; i++)
3825 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003826
Hante Meuleman6c404f32015-12-10 13:43:03 +01003827 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3828 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829
3830 return err;
3831}
3832
3833static s32
3834brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3835 struct cfg80211_pmksa *pmksa)
3836{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003837 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003838 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003839 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3840 s32 err;
3841 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003842
Arend van Sprield96b8012012-12-05 15:26:02 +01003843 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003844 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003845 return -EIO;
3846
Hante Meuleman6c404f32015-12-10 13:43:03 +01003847 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3848 for (i = 0; i < npmk; i++)
3849 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003850 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003851 if (i < BRCMF_MAXPMKID) {
3852 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3853 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3854 if (i == npmk) {
3855 npmk++;
3856 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003857 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003858 } else {
3859 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3860 return -EINVAL;
3861 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003862
Hante Meuleman6c404f32015-12-10 13:43:03 +01003863 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3864 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3865 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3866 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3867 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003868
Hante Meuleman6c404f32015-12-10 13:43:03 +01003869 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003870
Arend van Sprield96b8012012-12-05 15:26:02 +01003871 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003872 return err;
3873}
3874
3875static s32
3876brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003877 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003878{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003879 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003880 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003881 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3882 s32 err;
3883 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003884
Arend van Sprield96b8012012-12-05 15:26:02 +01003885 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003886 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003887 return -EIO;
3888
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003889 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003890
Hante Meuleman6c404f32015-12-10 13:43:03 +01003891 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3892 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003893 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003894 break;
3895
Hante Meuleman6c404f32015-12-10 13:43:03 +01003896 if ((npmk > 0) && (i < npmk)) {
3897 for (; i < (npmk - 1); i++) {
3898 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3899 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003900 WLAN_PMKID_LEN);
3901 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003902 memset(&pmk[i], 0, sizeof(*pmk));
3903 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3904 } else {
3905 brcmf_err("Cache entry not found\n");
3906 return -EINVAL;
3907 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003908
Hante Meuleman6c404f32015-12-10 13:43:03 +01003909 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003910
Arend van Sprield96b8012012-12-05 15:26:02 +01003911 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003912 return err;
3913
3914}
3915
3916static s32
3917brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3918{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003919 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003920 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003921 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003922
Arend van Sprield96b8012012-12-05 15:26:02 +01003923 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003924 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003925 return -EIO;
3926
Hante Meuleman6c404f32015-12-10 13:43:03 +01003927 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3928 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003929
Arend van Sprield96b8012012-12-05 15:26:02 +01003930 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003931 return err;
3932
3933}
3934
Hante Meuleman1f170112013-02-06 18:40:38 +01003935static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003936{
3937 s32 err;
3938
3939 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003940 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003941 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003942 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003943 return err;
3944 }
3945 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003946 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003947 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003948 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003949 return err;
3950 }
3951 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003952 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003953 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003954 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003955 return err;
3956 }
3957
3958 return 0;
3959}
3960
3961static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3962{
3963 if (is_rsn_ie)
3964 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3965
3966 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3967}
3968
3969static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003970brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003971 const struct brcmf_vs_tlv *wpa_ie,
3972 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003973{
3974 u32 auth = 0; /* d11 open authentication */
3975 u16 count;
3976 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003977 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003978 u32 i;
3979 u32 wsec;
3980 u32 pval = 0;
3981 u32 gval = 0;
3982 u32 wpa_auth = 0;
3983 u32 offset;
3984 u8 *data;
3985 u16 rsn_cap;
3986 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003987 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003988
Arend van Sprield96b8012012-12-05 15:26:02 +01003989 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003990 if (wpa_ie == NULL)
3991 goto exit;
3992
3993 len = wpa_ie->len + TLV_HDR_LEN;
3994 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003995 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003996 if (!is_rsn_ie)
3997 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003998 else
3999 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004000
4001 /* check for multicast cipher suite */
4002 if (offset + WPA_IE_MIN_OUI_LEN > len) {
4003 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004004 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004005 goto exit;
4006 }
4007
4008 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4009 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004010 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004011 goto exit;
4012 }
4013 offset += TLV_OUI_LEN;
4014
4015 /* pick up multicast cipher */
4016 switch (data[offset]) {
4017 case WPA_CIPHER_NONE:
4018 gval = 0;
4019 break;
4020 case WPA_CIPHER_WEP_40:
4021 case WPA_CIPHER_WEP_104:
4022 gval = WEP_ENABLED;
4023 break;
4024 case WPA_CIPHER_TKIP:
4025 gval = TKIP_ENABLED;
4026 break;
4027 case WPA_CIPHER_AES_CCM:
4028 gval = AES_ENABLED;
4029 break;
4030 default:
4031 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004032 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004033 goto exit;
4034 }
4035
4036 offset++;
4037 /* walk thru unicast cipher list and pick up what we recognize */
4038 count = data[offset] + (data[offset + 1] << 8);
4039 offset += WPA_IE_SUITE_COUNT_LEN;
4040 /* Check for unicast suite(s) */
4041 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4042 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004043 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004044 goto exit;
4045 }
4046 for (i = 0; i < count; i++) {
4047 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4048 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004049 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004050 goto exit;
4051 }
4052 offset += TLV_OUI_LEN;
4053 switch (data[offset]) {
4054 case WPA_CIPHER_NONE:
4055 break;
4056 case WPA_CIPHER_WEP_40:
4057 case WPA_CIPHER_WEP_104:
4058 pval |= WEP_ENABLED;
4059 break;
4060 case WPA_CIPHER_TKIP:
4061 pval |= TKIP_ENABLED;
4062 break;
4063 case WPA_CIPHER_AES_CCM:
4064 pval |= AES_ENABLED;
4065 break;
4066 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004067 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004068 }
4069 offset++;
4070 }
4071 /* walk thru auth management suite list and pick up what we recognize */
4072 count = data[offset] + (data[offset + 1] << 8);
4073 offset += WPA_IE_SUITE_COUNT_LEN;
4074 /* Check for auth key management suite(s) */
4075 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4076 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004077 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004078 goto exit;
4079 }
4080 for (i = 0; i < count; i++) {
4081 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4082 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004083 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004084 goto exit;
4085 }
4086 offset += TLV_OUI_LEN;
4087 switch (data[offset]) {
4088 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004089 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004090 wpa_auth |= WPA_AUTH_NONE;
4091 break;
4092 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004093 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004094 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4095 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4096 break;
4097 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004098 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004099 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4100 (wpa_auth |= WPA_AUTH_PSK);
4101 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004102 case RSN_AKM_SHA256_PSK:
4103 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4104 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4105 break;
4106 case RSN_AKM_SHA256_1X:
4107 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4108 wpa_auth |= WPA2_AUTH_1X_SHA256;
4109 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004110 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004111 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004112 }
4113 offset++;
4114 }
4115
Hante Meuleman240d61a2016-02-17 11:27:10 +01004116 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004117 if (is_rsn_ie) {
4118 wme_bss_disable = 1;
4119 if ((offset + RSN_CAP_LEN) <= len) {
4120 rsn_cap = data[offset] + (data[offset + 1] << 8);
4121 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4122 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004123 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4124 brcmf_dbg(TRACE, "MFP Required\n");
4125 mfp = BRCMF_MFP_REQUIRED;
4126 /* Firmware only supports mfp required in
4127 * combination with WPA2_AUTH_PSK_SHA256 or
4128 * WPA2_AUTH_1X_SHA256.
4129 */
4130 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4131 WPA2_AUTH_1X_SHA256))) {
4132 err = -EINVAL;
4133 goto exit;
4134 }
4135 /* Firmware has requirement that WPA2_AUTH_PSK/
4136 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4137 * is to be included in the rsn ie.
4138 */
4139 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4140 wpa_auth |= WPA2_AUTH_PSK;
4141 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4142 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4143 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4144 brcmf_dbg(TRACE, "MFP Capable\n");
4145 mfp = BRCMF_MFP_CAPABLE;
4146 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004147 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004148 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004149 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004150 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004151 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004152 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004153 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004154 goto exit;
4155 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004156
4157 /* Skip PMKID cnt as it is know to be 0 for AP. */
4158 offset += RSN_PMKID_COUNT_LEN;
4159
4160 /* See if there is BIP wpa suite left for MFP */
4161 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4162 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4163 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4164 &data[offset],
4165 WPA_IE_MIN_OUI_LEN);
4166 if (err < 0) {
4167 brcmf_err("bip error %d\n", err);
4168 goto exit;
4169 }
4170 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004171 }
4172 /* FOR WPS , set SES_OW_ENABLED */
4173 wsec = (pval | gval | SES_OW_ENABLED);
4174
4175 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004176 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004177 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004178 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004179 goto exit;
4180 }
4181 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004182 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004183 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004184 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004185 goto exit;
4186 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004187 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4188 * will overwrite the values set by MFP
4189 */
4190 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4191 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4192 if (err < 0) {
4193 brcmf_err("mfp error %d\n", err);
4194 goto exit;
4195 }
4196 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004197 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004198 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004199 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004200 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004201 goto exit;
4202 }
4203
4204exit:
4205 return err;
4206}
4207
4208static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004209brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004210 struct parsed_vndr_ies *vndr_ies)
4211{
Hante Meuleman1a873342012-09-27 14:17:54 +02004212 struct brcmf_vs_tlv *vndrie;
4213 struct brcmf_tlv *ie;
4214 struct parsed_vndr_ie_info *parsed_info;
4215 s32 remaining_len;
4216
4217 remaining_len = (s32)vndr_ie_len;
4218 memset(vndr_ies, 0, sizeof(*vndr_ies));
4219
4220 ie = (struct brcmf_tlv *)vndr_ie_buf;
4221 while (ie) {
4222 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4223 goto next;
4224 vndrie = (struct brcmf_vs_tlv *)ie;
4225 /* len should be bigger than OUI length + one */
4226 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004227 brcmf_err("invalid vndr ie. length is too small %d\n",
4228 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004229 goto next;
4230 }
4231 /* if wpa or wme ie, do not add ie */
4232 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4233 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4234 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004235 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004236 goto next;
4237 }
4238
4239 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4240
4241 /* save vndr ie information */
4242 parsed_info->ie_ptr = (char *)vndrie;
4243 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4244 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4245
4246 vndr_ies->count++;
4247
Arend van Sprield96b8012012-12-05 15:26:02 +01004248 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4249 parsed_info->vndrie.oui[0],
4250 parsed_info->vndrie.oui[1],
4251 parsed_info->vndrie.oui[2],
4252 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004253
Arend van Spriel9f440b72013-02-08 15:53:36 +01004254 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004255 break;
4256next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004257 remaining_len -= (ie->len + TLV_HDR_LEN);
4258 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004259 ie = NULL;
4260 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004261 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4262 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004263 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004264 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004265}
4266
4267static u32
4268brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4269{
4270
Hante Meuleman1a873342012-09-27 14:17:54 +02004271 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4272 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4273
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304274 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004275
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304276 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004277
4278 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4279
4280 return ie_len + VNDR_IE_HDR_SIZE;
4281}
4282
Arend van Spriel1332e262012-11-05 16:22:18 -08004283s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4284 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004285{
Arend van Spriel1332e262012-11-05 16:22:18 -08004286 struct brcmf_if *ifp;
4287 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004288 s32 err = 0;
4289 u8 *iovar_ie_buf;
4290 u8 *curr_ie_buf;
4291 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004292 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004293 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004294 u32 del_add_ie_buf_len = 0;
4295 u32 total_ie_buf_len = 0;
4296 u32 parsed_ie_buf_len = 0;
4297 struct parsed_vndr_ies old_vndr_ies;
4298 struct parsed_vndr_ies new_vndr_ies;
4299 struct parsed_vndr_ie_info *vndrie_info;
4300 s32 i;
4301 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004302 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004303
Arend van Spriel1332e262012-11-05 16:22:18 -08004304 if (!vif)
4305 return -ENODEV;
4306 ifp = vif->ifp;
4307 saved_ie = &vif->saved_ie;
4308
Hante Meuleman37a869e2015-10-29 20:33:17 +01004309 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4310 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004311 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4312 if (!iovar_ie_buf)
4313 return -ENOMEM;
4314 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004315 switch (pktflag) {
4316 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4317 mgmt_ie_buf = saved_ie->probe_req_ie;
4318 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4319 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4320 break;
4321 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4322 mgmt_ie_buf = saved_ie->probe_res_ie;
4323 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4324 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4325 break;
4326 case BRCMF_VNDR_IE_BEACON_FLAG:
4327 mgmt_ie_buf = saved_ie->beacon_ie;
4328 mgmt_ie_len = &saved_ie->beacon_ie_len;
4329 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4330 break;
4331 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4332 mgmt_ie_buf = saved_ie->assoc_req_ie;
4333 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4334 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4335 break;
4336 default:
4337 err = -EPERM;
4338 brcmf_err("not suitable type\n");
4339 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004340 }
4341
4342 if (vndr_ie_len > mgmt_ie_buf_len) {
4343 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004344 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004345 goto exit;
4346 }
4347
4348 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4349 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4350 ptr = curr_ie_buf;
4351 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4352 for (i = 0; i < new_vndr_ies.count; i++) {
4353 vndrie_info = &new_vndr_ies.ie_info[i];
4354 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4355 vndrie_info->ie_len);
4356 parsed_ie_buf_len += vndrie_info->ie_len;
4357 }
4358 }
4359
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004360 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004361 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4362 (memcmp(mgmt_ie_buf, curr_ie_buf,
4363 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004364 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004365 goto exit;
4366 }
4367
4368 /* parse old vndr_ie */
4369 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4370
4371 /* make a command to delete old ie */
4372 for (i = 0; i < old_vndr_ies.count; i++) {
4373 vndrie_info = &old_vndr_ies.ie_info[i];
4374
Arend van Sprield96b8012012-12-05 15:26:02 +01004375 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4376 vndrie_info->vndrie.id,
4377 vndrie_info->vndrie.len,
4378 vndrie_info->vndrie.oui[0],
4379 vndrie_info->vndrie.oui[1],
4380 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004381
4382 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4383 vndrie_info->ie_ptr,
4384 vndrie_info->ie_len,
4385 "del");
4386 curr_ie_buf += del_add_ie_buf_len;
4387 total_ie_buf_len += del_add_ie_buf_len;
4388 }
4389 }
4390
4391 *mgmt_ie_len = 0;
4392 /* Add if there is any extra IE */
4393 if (mgmt_ie_buf && parsed_ie_buf_len) {
4394 ptr = mgmt_ie_buf;
4395
4396 remained_buf_len = mgmt_ie_buf_len;
4397
4398 /* make a command to add new ie */
4399 for (i = 0; i < new_vndr_ies.count; i++) {
4400 vndrie_info = &new_vndr_ies.ie_info[i];
4401
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004402 /* verify remained buf size before copy data */
4403 if (remained_buf_len < (vndrie_info->vndrie.len +
4404 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004405 brcmf_err("no space in mgmt_ie_buf: len left %d",
4406 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004407 break;
4408 }
4409 remained_buf_len -= (vndrie_info->ie_len +
4410 VNDR_IE_VSIE_OFFSET);
4411
Arend van Sprield96b8012012-12-05 15:26:02 +01004412 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4413 vndrie_info->vndrie.id,
4414 vndrie_info->vndrie.len,
4415 vndrie_info->vndrie.oui[0],
4416 vndrie_info->vndrie.oui[1],
4417 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004418
4419 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4420 vndrie_info->ie_ptr,
4421 vndrie_info->ie_len,
4422 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004423
4424 /* save the parsed IE in wl struct */
4425 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4426 vndrie_info->ie_len);
4427 *mgmt_ie_len += vndrie_info->ie_len;
4428
4429 curr_ie_buf += del_add_ie_buf_len;
4430 total_ie_buf_len += del_add_ie_buf_len;
4431 }
4432 }
4433 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004434 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004435 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004436 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004437 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004438 }
4439
4440exit:
4441 kfree(iovar_ie_buf);
4442 return err;
4443}
4444
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004445s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4446{
4447 s32 pktflags[] = {
4448 BRCMF_VNDR_IE_PRBREQ_FLAG,
4449 BRCMF_VNDR_IE_PRBRSP_FLAG,
4450 BRCMF_VNDR_IE_BEACON_FLAG
4451 };
4452 int i;
4453
4454 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4455 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4456
4457 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4458 return 0;
4459}
4460
Hante Meuleman1a873342012-09-27 14:17:54 +02004461static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004462brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4463 struct cfg80211_beacon_data *beacon)
4464{
4465 s32 err;
4466
4467 /* Set Beacon IEs to FW */
4468 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4469 beacon->tail, beacon->tail_len);
4470 if (err) {
4471 brcmf_err("Set Beacon IE Failed\n");
4472 return err;
4473 }
4474 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4475
4476 /* Set Probe Response IEs to FW */
4477 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4478 beacon->proberesp_ies,
4479 beacon->proberesp_ies_len);
4480 if (err)
4481 brcmf_err("Set Probe Resp IE Failed\n");
4482 else
4483 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4484
4485 return err;
4486}
4487
4488static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004489brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4490 struct cfg80211_ap_settings *settings)
4491{
4492 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004493 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004494 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004495 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004496 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004497 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004498 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004499 const struct brcmf_tlv *rsn_ie;
4500 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004501 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004502 enum nl80211_iftype dev_role;
4503 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004504 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004505 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004506 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004507 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004508
Arend van Spriel06c01582014-05-12 10:47:37 +02004509 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4510 settings->chandef.chan->hw_value,
4511 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004512 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004513 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4514 settings->ssid, settings->ssid_len, settings->auth_type,
4515 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004516 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004517 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004518
Arend van Spriel98027762014-12-21 12:43:53 +01004519 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004520 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4521 &ifp->vif->is_11d)) {
4522 supports_11d = false;
4523 } else {
4524 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4525 settings->beacon.tail_len,
4526 WLAN_EID_COUNTRY);
4527 is_11d = country_ie ? 1 : 0;
4528 supports_11d = true;
4529 }
Arend van Spriel98027762014-12-21 12:43:53 +01004530
Hante Meuleman1a873342012-09-27 14:17:54 +02004531 memset(&ssid_le, 0, sizeof(ssid_le));
4532 if (settings->ssid == NULL || settings->ssid_len == 0) {
4533 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4534 ssid_ie = brcmf_parse_tlvs(
4535 (u8 *)&settings->beacon.head[ie_offset],
4536 settings->beacon.head_len - ie_offset,
4537 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004538 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004539 return -EINVAL;
4540
4541 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4542 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004543 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004544 } else {
4545 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4546 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4547 }
4548
Hante Meulemana44aa402014-12-03 21:05:33 +01004549 if (!mbss) {
4550 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004551 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004552 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004553
4554 /* find the RSN_IE */
4555 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4556 settings->beacon.tail_len, WLAN_EID_RSN);
4557
4558 /* find the WPA_IE */
4559 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4560 settings->beacon.tail_len);
4561
Hante Meuleman1a873342012-09-27 14:17:54 +02004562 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004563 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004564 if (wpa_ie != NULL) {
4565 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004566 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004567 if (err < 0)
4568 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004569 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004570 struct brcmf_vs_tlv *tmp_ie;
4571
4572 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4573
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004575 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004576 if (err < 0)
4577 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004578 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004579 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004580 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004581 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004582 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004583
Hante Meulemana0f07952013-02-08 15:53:47 +01004584 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004585
Rafał Miłecki8707e082016-05-27 21:07:19 +02004586 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004587 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004588 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004589 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4590 is_11d);
4591 if (err < 0) {
4592 brcmf_err("Regulatory Set Error, %d\n", err);
4593 goto exit;
4594 }
4595 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004596 if (settings->beacon_interval) {
4597 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4598 settings->beacon_interval);
4599 if (err < 0) {
4600 brcmf_err("Beacon Interval Set Error, %d\n",
4601 err);
4602 goto exit;
4603 }
4604 }
4605 if (settings->dtim_period) {
4606 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4607 settings->dtim_period);
4608 if (err < 0) {
4609 brcmf_err("DTIM Interval Set Error, %d\n", err);
4610 goto exit;
4611 }
4612 }
4613
Hante Meuleman8abffd82015-10-29 20:33:16 +01004614 if ((dev_role == NL80211_IFTYPE_AP) &&
4615 ((ifp->ifidx == 0) ||
4616 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004617 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4618 if (err < 0) {
4619 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4620 goto exit;
4621 }
4622 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4623 }
4624
4625 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004626 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004627 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004628 goto exit;
4629 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004630 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004631 /* Multiple-BSS should use same 11d configuration */
4632 err = -EINVAL;
4633 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004634 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004635
4636 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004637 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004638 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4639 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4640
Hante Meulemana0f07952013-02-08 15:53:47 +01004641 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4642 if (err < 0) {
4643 brcmf_err("setting AP mode failed %d\n", err);
4644 goto exit;
4645 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004646 if (!mbss) {
4647 /* Firmware 10.x requires setting channel after enabling
4648 * AP and before bringing interface up.
4649 */
4650 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4651 if (err < 0) {
4652 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4653 chanspec, err);
4654 goto exit;
4655 }
4656 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004657 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4658 if (err < 0) {
4659 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4660 goto exit;
4661 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004662 /* On DOWN the firmware removes the WEP keys, reconfigure
4663 * them if they were set.
4664 */
4665 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004666
4667 memset(&join_params, 0, sizeof(join_params));
4668 /* join parameters starts with ssid */
4669 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4670 /* create softap */
4671 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4672 &join_params, sizeof(join_params));
4673 if (err < 0) {
4674 brcmf_err("SET SSID error (%d)\n", err);
4675 goto exit;
4676 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004677
4678 if (settings->hidden_ssid) {
4679 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4680 if (err) {
4681 brcmf_err("closednet error (%d)\n", err);
4682 goto exit;
4683 }
4684 }
4685
Hante Meulemana0f07952013-02-08 15:53:47 +01004686 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004687 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4688 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4689 if (err < 0) {
4690 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4691 chanspec, err);
4692 goto exit;
4693 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004694 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4695 sizeof(ssid_le));
4696 if (err < 0) {
4697 brcmf_err("setting ssid failed %d\n", err);
4698 goto exit;
4699 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004700 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004701 bss_enable.enable = cpu_to_le32(1);
4702 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4703 sizeof(bss_enable));
4704 if (err < 0) {
4705 brcmf_err("bss_enable config failed %d\n", err);
4706 goto exit;
4707 }
4708
4709 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004710 } else {
4711 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004712 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004713
Arend van Sprielc1179032012-10-22 13:55:33 -07004714 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004715 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004716
4717exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004718 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004719 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004720 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004721 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004722 return err;
4723}
4724
4725static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4726{
Arend van Sprielc1179032012-10-22 13:55:33 -07004727 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004728 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004729 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004730 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004731
Arend van Sprield96b8012012-12-05 15:26:02 +01004732 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004733
Hante Meuleman426d0a52013-02-08 15:53:53 +01004734 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004735 /* Due to most likely deauths outstanding we sleep */
4736 /* first to make sure they get processed by fw. */
4737 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004738
Hante Meulemana44aa402014-12-03 21:05:33 +01004739 if (ifp->vif->mbss) {
4740 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4741 return err;
4742 }
4743
Rafał Miłeckic940de12016-07-06 12:22:54 +02004744 /* First BSS doesn't get a full reset */
4745 if (ifp->bsscfgidx == 0)
4746 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4747
Hante Meuleman5c33a942013-04-02 21:06:18 +02004748 memset(&join_params, 0, sizeof(join_params));
4749 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4750 &join_params, sizeof(join_params));
4751 if (err < 0)
4752 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004753 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004754 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004755 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004756 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4757 if (err < 0)
4758 brcmf_err("setting AP mode failed %d\n", err);
4759 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4760 if (err < 0)
4761 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004762 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4763 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004764 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4765 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004766 /* Bring device back up so it can be used again */
4767 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4768 if (err < 0)
4769 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004770 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004771 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004772 bss_enable.enable = cpu_to_le32(0);
4773 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4774 sizeof(bss_enable));
4775 if (err < 0)
4776 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004777 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004778 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004779 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004780 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004781 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004782
Hante Meuleman1a873342012-09-27 14:17:54 +02004783 return err;
4784}
4785
Hante Meulemana0f07952013-02-08 15:53:47 +01004786static s32
4787brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4788 struct cfg80211_beacon_data *info)
4789{
Hante Meulemana0f07952013-02-08 15:53:47 +01004790 struct brcmf_if *ifp = netdev_priv(ndev);
4791 s32 err;
4792
4793 brcmf_dbg(TRACE, "Enter\n");
4794
Hante Meulemana0f07952013-02-08 15:53:47 +01004795 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4796
4797 return err;
4798}
4799
Hante Meuleman1a873342012-09-27 14:17:54 +02004800static int
4801brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004802 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004803{
Hante Meulemana0f07952013-02-08 15:53:47 +01004804 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004805 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004806 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004807 s32 err;
4808
Jouni Malinen89c771e2014-10-10 20:52:40 +03004809 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004810 return -EFAULT;
4811
Jouni Malinen89c771e2014-10-10 20:52:40 +03004812 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004813
Hante Meulemana0f07952013-02-08 15:53:47 +01004814 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4815 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004816 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004817 return -EIO;
4818
Jouni Malinen89c771e2014-10-10 20:52:40 +03004819 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004820 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004821 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004822 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004823 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004824 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004825
Arend van Sprield96b8012012-12-05 15:26:02 +01004826 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004827 return err;
4828}
4829
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004830static int
4831brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4832 const u8 *mac, struct station_parameters *params)
4833{
4834 struct brcmf_if *ifp = netdev_priv(ndev);
4835 s32 err;
4836
4837 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4838 params->sta_flags_mask, params->sta_flags_set);
4839
4840 /* Ignore all 00 MAC */
4841 if (is_zero_ether_addr(mac))
4842 return 0;
4843
4844 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4845 return 0;
4846
4847 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4848 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4849 (void *)mac, ETH_ALEN);
4850 else
4851 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4852 (void *)mac, ETH_ALEN);
4853 if (err < 0)
4854 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4855
4856 return err;
4857}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004858
4859static void
4860brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4861 struct wireless_dev *wdev,
4862 u16 frame_type, bool reg)
4863{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004864 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004865 u16 mgmt_type;
4866
4867 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4868
4869 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004870 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004871 if (reg)
4872 vif->mgmt_rx_reg |= BIT(mgmt_type);
4873 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004874 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004875}
4876
4877
4878static int
4879brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004880 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004881{
4882 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004883 struct ieee80211_channel *chan = params->chan;
4884 const u8 *buf = params->buf;
4885 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004886 const struct ieee80211_mgmt *mgmt;
4887 struct brcmf_cfg80211_vif *vif;
4888 s32 err = 0;
4889 s32 ie_offset;
4890 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004891 struct brcmf_fil_action_frame_le *action_frame;
4892 struct brcmf_fil_af_params_le *af_params;
4893 bool ack;
4894 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004895 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004896
4897 brcmf_dbg(TRACE, "Enter\n");
4898
4899 *cookie = 0;
4900
4901 mgmt = (const struct ieee80211_mgmt *)buf;
4902
Hante Meulemana0f07952013-02-08 15:53:47 +01004903 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4904 brcmf_err("Driver only allows MGMT packet type\n");
4905 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004906 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004907
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004908 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4909
Hante Meulemana0f07952013-02-08 15:53:47 +01004910 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4911 /* Right now the only reason to get a probe response */
4912 /* is for p2p listen response or for p2p GO from */
4913 /* wpa_supplicant. Unfortunately the probe is send */
4914 /* on primary ndev, while dongle wants it on the p2p */
4915 /* vif. Since this is only reason for a probe */
4916 /* response to be sent, the vif is taken from cfg. */
4917 /* If ever desired to send proberesp for non p2p */
4918 /* response then data should be checked for */
4919 /* "DIRECT-". Note in future supplicant will take */
4920 /* dedicated p2p wdev to do this and then this 'hack'*/
4921 /* is not needed anymore. */
4922 ie_offset = DOT11_MGMT_HDR_LEN +
4923 DOT11_BCN_PRB_FIXED_LEN;
4924 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004925 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4926 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4927 err = brcmf_vif_set_mgmt_ie(vif,
4928 BRCMF_VNDR_IE_PRBRSP_FLAG,
4929 &buf[ie_offset],
4930 ie_len);
4931 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4932 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004933 } else if (ieee80211_is_action(mgmt->frame_control)) {
4934 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;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005418 u32 freq;
5419 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005420 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005421
Arend van Sprield96b8012012-12-05 15:26:02 +01005422 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005423
Hante Meuleman89286dc2013-02-08 15:53:46 +01005424 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005425 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005426 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005427
Franky Lina180b832012-10-10 11:13:09 -07005428 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5429 if (buf == NULL) {
5430 err = -ENOMEM;
5431 goto done;
5432 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005433
Franky Lina180b832012-10-10 11:13:09 -07005434 /* data sent to dongle has to be little endian */
5435 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005436 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005437 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005438
5439 if (err)
5440 goto done;
5441
5442 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005443 ch.chspec = le16_to_cpu(bi->chanspec);
5444 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005445
Franky Lin83cf17a2013-04-11 13:28:50 +02005446 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005447 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005448 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005449 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005450
Rafał Miłecki4712d882016-05-20 13:38:57 +02005451 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005452 notify_channel = ieee80211_get_channel(wiphy, freq);
5453
Franky Lina180b832012-10-10 11:13:09 -07005454done:
5455 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005456 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005457 conn_info->req_ie, conn_info->req_ie_len,
5458 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005459 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005460
Arend van Sprielc1179032012-10-22 13:55:33 -07005461 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005462 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005463 return err;
5464}
5465
5466static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005467brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005468 struct net_device *ndev, const struct brcmf_event_msg *e,
5469 bool completed)
5470{
Arend van Sprielc1179032012-10-22 13:55:33 -07005471 struct brcmf_if *ifp = netdev_priv(ndev);
5472 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005473 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005474
Arend van Sprield96b8012012-12-05 15:26:02 +01005475 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005476
Arend van Sprielc1179032012-10-22 13:55:33 -07005477 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5478 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005479 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005480 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005481 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005482 brcmf_update_bss_info(cfg, ifp);
5483 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5484 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005485 }
5486 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005487 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005488 conn_info->req_ie,
5489 conn_info->req_ie_len,
5490 conn_info->resp_ie,
5491 conn_info->resp_ie_len,
5492 completed ? WLAN_STATUS_SUCCESS :
5493 WLAN_STATUS_AUTH_TIMEOUT,
5494 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005495 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5496 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005497 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005498 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005499 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005500}
5501
5502static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005503brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005504 struct net_device *ndev,
5505 const struct brcmf_event_msg *e, void *data)
5506{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005507 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005508 u32 event = e->event_code;
5509 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005510 struct station_info sinfo;
5511
Arend van Spriel16886732012-12-05 15:26:04 +01005512 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005513 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5514 ndev != cfg_to_ndev(cfg)) {
5515 brcmf_dbg(CONN, "AP mode link down\n");
5516 complete(&cfg->vif_disabled);
5517 return 0;
5518 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005519
Hante Meuleman1a873342012-09-27 14:17:54 +02005520 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005521 (reason == BRCMF_E_STATUS_SUCCESS)) {
5522 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005523 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005524 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005525 return -EINVAL;
5526 }
5527 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005528 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005529 generation++;
5530 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005531 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005532 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5533 (event == BRCMF_E_DEAUTH_IND) ||
5534 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005535 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005536 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005537 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005538}
5539
5540static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005541brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005542 const struct brcmf_event_msg *e, void *data)
5543{
Arend van Spriel19937322012-11-05 16:22:32 -08005544 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5545 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005546 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005547 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005548 s32 err = 0;
5549
Hante Meuleman8851cce2014-07-30 13:20:02 +02005550 if ((e->event_code == BRCMF_E_DEAUTH) ||
5551 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5552 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5553 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5554 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5555 }
5556
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005557 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005558 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005559 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005560 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005561 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005562 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005563 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005564 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005565 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005566 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5567 &ifp->vif->sme_state);
5568 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5569 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005570 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005571 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005572 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005573 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005574 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005575 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005576 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005577 brcmf_link_down(ifp->vif,
5578 brcmf_map_fw_linkdown_reason(e));
5579 brcmf_init_prof(ndev_to_prof(ndev));
5580 if (ndev != cfg_to_ndev(cfg))
5581 complete(&cfg->vif_disabled);
5582 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005583 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005584 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005585 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005586 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5587 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005588 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005589 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005590 }
5591
5592 return err;
5593}
5594
5595static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005596brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005597 const struct brcmf_event_msg *e, void *data)
5598{
Arend van Spriel19937322012-11-05 16:22:32 -08005599 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005600 u32 event = e->event_code;
5601 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005602
5603 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005604 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005605 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005606 else
Arend van Spriel19937322012-11-05 16:22:32 -08005607 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005608 }
5609
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005610 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005611}
5612
5613static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005614brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005615 const struct brcmf_event_msg *e, void *data)
5616{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005617 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005618 enum nl80211_key_type key_type;
5619
5620 if (flags & BRCMF_EVENT_MSG_GROUP)
5621 key_type = NL80211_KEYTYPE_GROUP;
5622 else
5623 key_type = NL80211_KEYTYPE_PAIRWISE;
5624
Arend van Spriel19937322012-11-05 16:22:32 -08005625 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005626 NULL, GFP_KERNEL);
5627
5628 return 0;
5629}
5630
Arend van Sprield3c0b632013-02-08 15:53:37 +01005631static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5632 const struct brcmf_event_msg *e, void *data)
5633{
5634 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5635 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5636 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5637 struct brcmf_cfg80211_vif *vif;
5638
Hante Meuleman37a869e2015-10-29 20:33:17 +01005639 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005640 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005641 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005642
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005643 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005644 event->action = ifevent->action;
5645 vif = event->vif;
5646
5647 switch (ifevent->action) {
5648 case BRCMF_E_IF_ADD:
5649 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005650 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005651 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005652 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005653 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005654
5655 ifp->vif = vif;
5656 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005657 if (ifp->ndev) {
5658 vif->wdev.netdev = ifp->ndev;
5659 ifp->ndev->ieee80211_ptr = &vif->wdev;
5660 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5661 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005662 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005663 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005664 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005665
5666 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005667 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005668 /* event may not be upon user request */
5669 if (brcmf_cfg80211_vif_event_armed(cfg))
5670 wake_up(&event->vif_wq);
5671 return 0;
5672
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005673 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005674 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005675 wake_up(&event->vif_wq);
5676 return 0;
5677
Arend van Sprield3c0b632013-02-08 15:53:37 +01005678 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005679 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005680 break;
5681 }
5682 return -EINVAL;
5683}
5684
Arend van Spriel5b435de2011-10-05 13:19:03 +02005685static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5686{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005687 conf->frag_threshold = (u32)-1;
5688 conf->rts_threshold = (u32)-1;
5689 conf->retry_short = (u32)-1;
5690 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005691}
5692
Arend van Spriel5c36b992012-11-14 18:46:05 -08005693static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005694{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005695 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5696 brcmf_notify_connect_status);
5697 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5698 brcmf_notify_connect_status);
5699 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5700 brcmf_notify_connect_status);
5701 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5702 brcmf_notify_connect_status);
5703 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5704 brcmf_notify_connect_status);
5705 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5706 brcmf_notify_connect_status);
5707 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5708 brcmf_notify_roaming_status);
5709 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5710 brcmf_notify_mic_status);
5711 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5712 brcmf_notify_connect_status);
5713 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5714 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005715 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5716 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005717 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005718 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005719 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5720 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005721 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5722 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005723 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5724 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005725 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5726 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005727}
5728
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005729static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005730{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005731 kfree(cfg->conf);
5732 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005733 kfree(cfg->extra_buf);
5734 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005735 kfree(cfg->wowl.nd);
5736 cfg->wowl.nd = NULL;
5737 kfree(cfg->wowl.nd_info);
5738 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005739 kfree(cfg->escan_info.escan_buf);
5740 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005741}
5742
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005743static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005744{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005745 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5746 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005747 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005748 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5749 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005750 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005751 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5752 if (!cfg->wowl.nd)
5753 goto init_priv_mem_out;
5754 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5755 sizeof(struct cfg80211_wowlan_nd_match *),
5756 GFP_KERNEL);
5757 if (!cfg->wowl.nd_info)
5758 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005759 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5760 if (!cfg->escan_info.escan_buf)
5761 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005762
5763 return 0;
5764
5765init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005766 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005767
5768 return -ENOMEM;
5769}
5770
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005771static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005772{
5773 s32 err = 0;
5774
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005775 cfg->scan_request = NULL;
5776 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005777 cfg->active_scan = true; /* we do active scan per default */
5778 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005779 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005780 if (err)
5781 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005782 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005783 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005784 brcmf_init_escan(cfg);
5785 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005786 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005787 return err;
5788}
5789
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005790static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005791{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005792 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005793 brcmf_abort_scanning(cfg);
5794 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005795}
5796
Arend van Sprield3c0b632013-02-08 15:53:37 +01005797static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5798{
5799 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005800 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005801}
5802
Hante Meuleman1119e232015-11-25 11:32:42 +01005803static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005804{
Hante Meuleman1119e232015-11-25 11:32:42 +01005805 s32 err;
5806 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005807 __le32 roamtrigger[2];
5808 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005809
Hante Meuleman1119e232015-11-25 11:32:42 +01005810 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005811 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005812 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5813 else
5814 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5815 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5816 if (err) {
5817 brcmf_err("bcn_timeout error (%d)\n", err);
5818 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005819 }
5820
Hante Meuleman1119e232015-11-25 11:32:42 +01005821 /* Enable/Disable built-in roaming to allow supplicant to take care of
5822 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005823 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005824 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005825 ifp->drvr->settings->roamoff ? "Off" : "On");
5826 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5827 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005828 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005829 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005830 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005831 }
5832
Arend van Sprielf588bc02011-10-12 20:51:22 +02005833 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5834 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005835 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005836 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005837 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005838 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005839 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005840 }
5841
Arend van Sprielf588bc02011-10-12 20:51:22 +02005842 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5843 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005844 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005845 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005846 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005847 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005848 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005849 }
5850
Hante Meuleman1119e232015-11-25 11:32:42 +01005851roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005852 return err;
5853}
5854
5855static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005856brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005857{
5858 s32 err = 0;
5859
Arend van Sprielac24be62012-10-22 10:36:23 -07005860 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005861 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005862 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005863 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005864 goto dongle_scantime_out;
5865 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005866 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005867 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005868 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005869 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005870 goto dongle_scantime_out;
5871 }
5872
Arend van Sprielac24be62012-10-22 10:36:23 -07005873 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005874 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005875 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005876 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005877 goto dongle_scantime_out;
5878 }
5879
5880dongle_scantime_out:
5881 return err;
5882}
5883
Arend van Sprielb48d8912014-07-12 08:49:41 +02005884static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5885 struct brcmu_chan *ch)
5886{
5887 u32 ht40_flag;
5888
5889 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5890 if (ch->sb == BRCMU_CHAN_SB_U) {
5891 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5892 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5893 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5894 } else {
5895 /* It should be one of
5896 * IEEE80211_CHAN_NO_HT40 or
5897 * IEEE80211_CHAN_NO_HT40PLUS
5898 */
5899 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5900 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5901 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5902 }
5903}
5904
5905static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5906 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005907{
5908 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005909 struct ieee80211_supported_band *band;
5910 struct ieee80211_channel *channel;
5911 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005912 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005913 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005914 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005915 u8 *pbuf;
5916 u32 i, j;
5917 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005918 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005919 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005920
5921 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5922
5923 if (pbuf == NULL)
5924 return -ENOMEM;
5925
5926 list = (struct brcmf_chanspec_list *)pbuf;
5927
5928 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5929 BRCMF_DCMD_MEDLEN);
5930 if (err) {
5931 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005932 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005933 }
5934
Arend van Sprielb48d8912014-07-12 08:49:41 +02005935 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005936 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005937 if (band)
5938 for (i = 0; i < band->n_channels; i++)
5939 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005940 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005941 if (band)
5942 for (i = 0; i < band->n_channels; i++)
5943 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005944
5945 total = le32_to_cpu(list->count);
5946 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005947 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5948 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005949
Franky Lin83cf17a2013-04-11 13:28:50 +02005950 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005951 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005952 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005953 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005954 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005955 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005956 continue;
5957 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005958 if (!band)
5959 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005960 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005961 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005962 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005963 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005964 ch.bw == BRCMU_CHAN_BW_80)
5965 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005966
5967 channel = band->channels;
5968 index = band->n_channels;
5969 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02005970 if (channel[j].hw_value == ch.control_ch_num) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005971 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005972 break;
5973 }
5974 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005975 channel[index].center_freq =
Rafał Miłecki4712d882016-05-20 13:38:57 +02005976 ieee80211_channel_to_frequency(ch.control_ch_num,
5977 band->band);
5978 channel[index].hw_value = ch.control_ch_num;
Hante Meulemand48200b2013-04-03 12:40:29 +02005979
Arend van Sprielb48d8912014-07-12 08:49:41 +02005980 /* assuming the chanspecs order is HT20,
5981 * HT40 upper, HT40 lower, and VHT80.
5982 */
5983 if (ch.bw == BRCMU_CHAN_BW_80) {
5984 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5985 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5986 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5987 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005988 /* enable the channel and disable other bandwidths
5989 * for now as mentioned order assure they are enabled
5990 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005991 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005992 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5993 IEEE80211_CHAN_NO_80MHZ;
5994 ch.bw = BRCMU_CHAN_BW_20;
5995 cfg->d11inf.encchspec(&ch);
5996 chaninfo = ch.chspec;
5997 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5998 &chaninfo);
5999 if (!err) {
6000 if (chaninfo & WL_CHAN_RADAR)
6001 channel[index].flags |=
6002 (IEEE80211_CHAN_RADAR |
6003 IEEE80211_CHAN_NO_IR);
6004 if (chaninfo & WL_CHAN_PASSIVE)
6005 channel[index].flags |=
6006 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02006007 }
Hante Meulemand48200b2013-04-03 12:40:29 +02006008 }
6009 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006010
Arend van Sprielb48d8912014-07-12 08:49:41 +02006011fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02006012 kfree(pbuf);
6013 return err;
6014}
6015
Arend van Sprielb48d8912014-07-12 08:49:41 +02006016static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006017{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006018 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6019 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006020 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006021 struct brcmf_chanspec_list *list;
6022 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006023 u32 val;
6024 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006025 struct brcmu_chan ch;
6026 u32 num_chan;
6027 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006028
6029 /* verify support for bw_cap command */
6030 val = WLC_BAND_5G;
6031 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
6032
6033 if (!err) {
6034 /* only set 2G bandwidth using bw_cap command */
6035 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
6036 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
6037 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
6038 sizeof(band_bwcap));
6039 } else {
6040 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
6041 val = WLC_N_BW_40ALL;
6042 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
6043 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006044
6045 if (!err) {
6046 /* update channel info in 2G band */
6047 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
6048
6049 if (pbuf == NULL)
6050 return -ENOMEM;
6051
6052 ch.band = BRCMU_CHAN_BAND_2G;
6053 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006054 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006055 ch.chnum = 0;
6056 cfg->d11inf.encchspec(&ch);
6057
6058 /* pass encoded chanspec in query */
6059 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6060
6061 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6062 BRCMF_DCMD_MEDLEN);
6063 if (err) {
6064 brcmf_err("get chanspecs error (%d)\n", err);
6065 kfree(pbuf);
6066 return err;
6067 }
6068
Johannes Berg57fbcce2016-04-12 15:56:15 +02006069 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006070 list = (struct brcmf_chanspec_list *)pbuf;
6071 num_chan = le32_to_cpu(list->count);
6072 for (i = 0; i < num_chan; i++) {
6073 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6074 cfg->d11inf.decchspec(&ch);
6075 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6076 continue;
6077 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6078 continue;
6079 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006080 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006081 break;
6082 }
6083 if (WARN_ON(j == band->n_channels))
6084 continue;
6085
6086 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6087 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006088 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006089 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006090 return err;
6091}
6092
Arend van Spriel2375d972014-01-06 12:40:41 +01006093static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6094{
6095 u32 band, mimo_bwcap;
6096 int err;
6097
6098 band = WLC_BAND_2G;
6099 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6100 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006101 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006102 band = WLC_BAND_5G;
6103 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6104 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006105 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006106 return;
6107 }
6108 WARN_ON(1);
6109 return;
6110 }
6111 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6112 mimo_bwcap = 0;
6113 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6114 if (err)
6115 /* assume 20MHz if firmware does not give a clue */
6116 mimo_bwcap = WLC_N_BW_20ALL;
6117
6118 switch (mimo_bwcap) {
6119 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006120 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006121 /* fall-thru */
6122 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006123 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006124 /* fall-thru */
6125 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006126 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6127 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006128 break;
6129 default:
6130 brcmf_err("invalid mimo_bw_cap value\n");
6131 }
6132}
Hante Meulemand48200b2013-04-03 12:40:29 +02006133
Arend van Spriel18d6c532014-05-12 10:47:35 +02006134static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6135 u32 bw_cap[2], u32 nchain)
6136{
6137 band->ht_cap.ht_supported = true;
6138 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6139 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6140 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6141 }
6142 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6143 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6144 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6145 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6146 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6147 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6148}
6149
6150static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6151{
6152 u16 mcs_map;
6153 int i;
6154
6155 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6156 mcs_map = (mcs_map << 2) | supp;
6157
6158 return cpu_to_le16(mcs_map);
6159}
6160
6161static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006162 u32 bw_cap[2], u32 nchain, u32 txstreams,
6163 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006164{
6165 __le16 mcs_map;
6166
6167 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006168 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006169 return;
6170
6171 band->vht_cap.vht_supported = true;
6172 /* 80MHz is mandatory */
6173 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6174 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6175 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6176 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6177 }
6178 /* all support 256-QAM */
6179 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6180 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6181 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006182
6183 /* Beamforming support information */
6184 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6185 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6186 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6187 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6188 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6189 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6190 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6191 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6192
6193 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6194 band->vht_cap.cap |=
6195 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6196 band->vht_cap.cap |= ((txstreams - 1) <<
6197 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6198 band->vht_cap.cap |=
6199 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6200 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006201}
6202
Arend van Sprielb48d8912014-07-12 08:49:41 +02006203static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006204{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006205 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006206 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006207 u32 nmode = 0;
6208 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006209 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006210 u32 rxchain;
6211 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006212 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006213 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006214 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006215 u32 txstreams = 0;
6216 u32 txbf_bfe_cap = 0;
6217 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006218
Arend van Spriel18d6c532014-05-12 10:47:35 +02006219 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006220 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6221 if (err) {
6222 brcmf_err("nmode error (%d)\n", err);
6223 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006224 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006225 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006226 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006227 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6228 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006229
Daniel Kim4aca7a12014-02-25 20:30:36 +01006230 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6231 if (err) {
6232 brcmf_err("rxchain error (%d)\n", err);
6233 nchain = 1;
6234 } else {
6235 for (nchain = 0; rxchain; nchain++)
6236 rxchain = rxchain & (rxchain - 1);
6237 }
6238 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6239
Arend van Sprielb48d8912014-07-12 08:49:41 +02006240 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006241 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006242 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006243 return err;
6244 }
6245
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006246 if (vhtmode) {
6247 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6248 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6249 &txbf_bfe_cap);
6250 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6251 &txbf_bfr_cap);
6252 }
6253
Arend van Sprielb48d8912014-07-12 08:49:41 +02006254 wiphy = cfg_to_wiphy(cfg);
6255 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6256 band = wiphy->bands[i];
6257 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006258 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006259
Arend van Spriel18d6c532014-05-12 10:47:35 +02006260 if (nmode)
6261 brcmf_update_ht_cap(band, bw_cap, nchain);
6262 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006263 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6264 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006265 }
6266
Arend van Sprielb48d8912014-07-12 08:49:41 +02006267 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006268}
6269
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006270static const struct ieee80211_txrx_stypes
6271brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6272 [NL80211_IFTYPE_STATION] = {
6273 .tx = 0xffff,
6274 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6275 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6276 },
6277 [NL80211_IFTYPE_P2P_CLIENT] = {
6278 .tx = 0xffff,
6279 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6280 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6281 },
6282 [NL80211_IFTYPE_P2P_GO] = {
6283 .tx = 0xffff,
6284 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6285 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6286 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6287 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6288 BIT(IEEE80211_STYPE_AUTH >> 4) |
6289 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6290 BIT(IEEE80211_STYPE_ACTION >> 4)
6291 },
6292 [NL80211_IFTYPE_P2P_DEVICE] = {
6293 .tx = 0xffff,
6294 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6295 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6296 }
6297};
6298
Arend van Spriel0882dda2015-08-20 22:06:03 +02006299/**
6300 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6301 *
6302 * @wiphy: wiphy object.
6303 * @ifp: interface object needed for feat module api.
6304 *
6305 * The interface modes and combinations are determined dynamically here
6306 * based on firmware functionality.
6307 *
6308 * no p2p and no mbss:
6309 *
6310 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6311 *
6312 * no p2p and mbss:
6313 *
6314 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6315 * #AP <= 4, matching BI, channels = 1, 4 total
6316 *
6317 * p2p, no mchan, and mbss:
6318 *
6319 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6320 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6321 * #AP <= 4, matching BI, channels = 1, 4 total
6322 *
6323 * p2p, mchan, and mbss:
6324 *
6325 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6326 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6327 * #AP <= 4, matching BI, channels = 1, 4 total
6328 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006329static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6330{
6331 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006332 struct ieee80211_iface_limit *c0_limits = NULL;
6333 struct ieee80211_iface_limit *p2p_limits = NULL;
6334 struct ieee80211_iface_limit *mbss_limits = NULL;
6335 bool mbss, p2p;
6336 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006337
Arend van Spriel0882dda2015-08-20 22:06:03 +02006338 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6339 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6340
6341 n_combos = 1 + !!p2p + !!mbss;
6342 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006343 if (!combo)
6344 goto err;
6345
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006346 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6347 BIT(NL80211_IFTYPE_ADHOC) |
6348 BIT(NL80211_IFTYPE_AP);
6349
Arend van Spriel0882dda2015-08-20 22:06:03 +02006350 c = 0;
6351 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006352 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6353 if (!c0_limits)
6354 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006355 c0_limits[i].max = 1;
6356 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6357 if (p2p) {
6358 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6359 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006360 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6361 BIT(NL80211_IFTYPE_P2P_GO) |
6362 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006363 c0_limits[i].max = 1;
6364 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6365 c0_limits[i].max = 1;
6366 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6367 BIT(NL80211_IFTYPE_P2P_GO);
6368 } else {
6369 c0_limits[i].max = 1;
6370 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006371 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006372 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006373 combo[c].max_interfaces = i;
6374 combo[c].n_limits = i;
6375 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006376
Arend van Spriel0882dda2015-08-20 22:06:03 +02006377 if (p2p) {
6378 c++;
6379 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006380 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6381 if (!p2p_limits)
6382 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006383 p2p_limits[i].max = 1;
6384 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6385 p2p_limits[i].max = 1;
6386 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6387 p2p_limits[i].max = 1;
6388 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6389 p2p_limits[i].max = 1;
6390 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006391 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006392 combo[c].max_interfaces = i;
6393 combo[c].n_limits = i;
6394 combo[c].limits = p2p_limits;
6395 }
6396
6397 if (mbss) {
6398 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006399 i = 0;
6400 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6401 if (!mbss_limits)
6402 goto err;
6403 mbss_limits[i].max = 4;
6404 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006405 combo[c].beacon_int_infra_match = true;
6406 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006407 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006408 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006409 combo[c].limits = mbss_limits;
6410 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006411
Arend van Spriel0882dda2015-08-20 22:06:03 +02006412 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006413 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006414 return 0;
6415
6416err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006417 kfree(c0_limits);
6418 kfree(p2p_limits);
6419 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006420 kfree(combo);
6421 return -ENOMEM;
6422}
6423
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006424static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6425{
6426 /* scheduled scan settings */
6427 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6428 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6429 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6430 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6431}
6432
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006433#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006434static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006435 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006436 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6437 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6438 .pattern_min_len = 1,
6439 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006440};
6441#endif
6442
Hante Meuleman3021ad92016-01-05 11:05:45 +01006443static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006444{
6445#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006446 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006447
6448 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006449 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6450 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6451 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006452 }
6453 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006454 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6455 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6456 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6457 }
6458
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006459 wiphy->wowlan = &brcmf_wowlan_support;
6460#endif
6461}
6462
Arend van Sprielb48d8912014-07-12 08:49:41 +02006463static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006464{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006465 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006466 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006467 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006468 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006469 __le32 bandlist[3];
6470 u32 n_bands;
6471 int err, i;
6472
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006473 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6474 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006475 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006476
6477 err = brcmf_setup_ifmodes(wiphy, ifp);
6478 if (err)
6479 return err;
6480
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006481 for (i = 0, combo = wiphy->iface_combinations;
6482 i < wiphy->n_iface_combinations; i++, combo++) {
6483 max_interfaces = max(max_interfaces, combo->max_interfaces);
6484 }
6485
6486 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6487 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006488 u8 *addr = drvr->addresses[i].addr;
6489
6490 memcpy(addr, drvr->mac, ETH_ALEN);
6491 if (i) {
6492 addr[0] |= BIT(1);
6493 addr[ETH_ALEN - 1] ^= i;
6494 }
6495 }
6496 wiphy->addresses = drvr->addresses;
6497 wiphy->n_addresses = i;
6498
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006499 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006500 wiphy->cipher_suites = brcmf_cipher_suites;
6501 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6502 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6503 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006504 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6505 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6506 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6507
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006508 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6509 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006510 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6511 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6512 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006513 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006514 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6515 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6516 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006517 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6518 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006519
6520 /* vendor commands/events support */
6521 wiphy->vendor_commands = brcmf_vendor_cmds;
6522 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6523
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006524 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006525 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006526 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6527 sizeof(bandlist));
6528 if (err) {
6529 brcmf_err("could not obtain band info: err=%d\n", err);
6530 return err;
6531 }
6532 /* first entry in bandlist is number of bands */
6533 n_bands = le32_to_cpu(bandlist[0]);
6534 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6535 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6536 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6537 GFP_KERNEL);
6538 if (!band)
6539 return -ENOMEM;
6540
6541 band->channels = kmemdup(&__wl_2ghz_channels,
6542 sizeof(__wl_2ghz_channels),
6543 GFP_KERNEL);
6544 if (!band->channels) {
6545 kfree(band);
6546 return -ENOMEM;
6547 }
6548
6549 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006550 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006551 }
6552 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6553 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6554 GFP_KERNEL);
6555 if (!band)
6556 return -ENOMEM;
6557
6558 band->channels = kmemdup(&__wl_5ghz_channels,
6559 sizeof(__wl_5ghz_channels),
6560 GFP_KERNEL);
6561 if (!band->channels) {
6562 kfree(band);
6563 return -ENOMEM;
6564 }
6565
6566 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006567 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006568 }
6569 }
6570 err = brcmf_setup_wiphybands(wiphy);
6571 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006572}
6573
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006574static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006575{
6576 struct net_device *ndev;
6577 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006578 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006579 s32 power_mode;
6580 s32 err = 0;
6581
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006582 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006583 return err;
6584
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006585 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006586 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006587 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006588
Hante Meuleman40a23292013-01-02 15:22:51 +01006589 /* make sure RF is ready for work */
6590 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6591
Hante Meuleman1678ba82015-12-10 13:43:00 +01006592 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006593
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006594 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006595 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006596 if (err)
6597 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006598 brcmf_dbg(INFO, "power save set to %s\n",
6599 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006600
Hante Meuleman1119e232015-11-25 11:32:42 +01006601 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006602 if (err)
6603 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006604 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6605 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006606 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006607 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006608
Franky Lin52f22fb2016-02-17 11:26:55 +01006609 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006610
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006611 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006612default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006613
6614 return err;
6615
6616}
6617
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006618static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006619{
Arend van Sprielc1179032012-10-22 13:55:33 -07006620 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006621
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006622 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006623}
6624
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006625static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006626{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006627 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006628
Arend van Spriel5b435de2011-10-05 13:19:03 +02006629 /*
6630 * While going down, if associated with AP disassociate
6631 * from AP to save power
6632 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006633 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006634 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006635
6636 /* Make sure WPA_Supplicant receives all the event
6637 generated due to DISASSOC call to the fw to keep
6638 the state fw and WPA_Supplicant state consistent
6639 */
6640 brcmf_delay(500);
6641 }
6642
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006643 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006644 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006645
Arend van Spriel5b435de2011-10-05 13:19:03 +02006646 return 0;
6647}
6648
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006649s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006650{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006651 struct brcmf_if *ifp = netdev_priv(ndev);
6652 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006653 s32 err = 0;
6654
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006655 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006656 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006657 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006658
6659 return err;
6660}
6661
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006662s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006663{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006664 struct brcmf_if *ifp = netdev_priv(ndev);
6665 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006666 s32 err = 0;
6667
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006668 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006669 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006670 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006671
6672 return err;
6673}
6674
Arend van Spriela7965fb2013-04-11 17:08:37 +02006675enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6676{
6677 struct wireless_dev *wdev = &ifp->vif->wdev;
6678
6679 return wdev->iftype;
6680}
6681
Hante Meulemanbfe81972014-10-28 14:56:16 +01006682bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6683 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006684{
6685 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006686
6687 list_for_each_entry(vif, &cfg->vif_list, list) {
6688 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006689 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006690 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006691 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006692}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006693
6694static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6695 u8 action)
6696{
6697 u8 evt_action;
6698
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006699 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006700 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006701 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006702 return evt_action == action;
6703}
6704
6705void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6706 struct brcmf_cfg80211_vif *vif)
6707{
6708 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6709
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006710 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006711 event->vif = vif;
6712 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006713 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006714}
6715
6716bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6717{
6718 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6719 bool armed;
6720
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006721 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006722 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006723 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006724
6725 return armed;
6726}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006727
6728int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6729 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006730{
6731 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6732
6733 return wait_event_timeout(event->vif_wq,
6734 vif_event_equals(event, action), timeout);
6735}
6736
Hante Meuleman73345fd2016-02-17 11:26:53 +01006737static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6738 struct brcmf_fil_country_le *ccreq)
6739{
Hante Meuleman4d792892016-02-17 11:27:07 +01006740 struct brcmfmac_pd_cc *country_codes;
6741 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006742 s32 found_index;
6743 int i;
6744
6745 country_codes = drvr->settings->country_codes;
6746 if (!country_codes) {
6747 brcmf_dbg(TRACE, "No country codes configured for device\n");
6748 return -EINVAL;
6749 }
6750
6751 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6752 (alpha2[1] == ccreq->country_abbrev[1])) {
6753 brcmf_dbg(TRACE, "Country code already set\n");
6754 return -EAGAIN;
6755 }
6756
6757 found_index = -1;
6758 for (i = 0; i < country_codes->table_size; i++) {
6759 cc = &country_codes->table[i];
6760 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6761 found_index = i;
6762 if ((cc->iso3166[0] == alpha2[0]) &&
6763 (cc->iso3166[1] == alpha2[1])) {
6764 found_index = i;
6765 break;
6766 }
6767 }
6768 if (found_index == -1) {
6769 brcmf_dbg(TRACE, "No country code match found\n");
6770 return -EINVAL;
6771 }
6772 memset(ccreq, 0, sizeof(*ccreq));
6773 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6774 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6775 BRCMF_COUNTRY_BUF_SZ);
6776 ccreq->country_abbrev[0] = alpha2[0];
6777 ccreq->country_abbrev[1] = alpha2[1];
6778 ccreq->country_abbrev[2] = 0;
6779
6780 return 0;
6781}
6782
Arend van Spriel63db1a42014-12-21 12:43:51 +01006783static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6784 struct regulatory_request *req)
6785{
6786 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6787 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6788 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006789 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006790 int i;
6791
Arend van Spriel63db1a42014-12-21 12:43:51 +01006792 /* ignore non-ISO3166 country codes */
6793 for (i = 0; i < sizeof(req->alpha2); i++)
6794 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006795 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6796 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006797 return;
6798 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006799
6800 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6801 req->alpha2[0], req->alpha2[1]);
6802
6803 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6804 if (err) {
6805 brcmf_err("Country code iovar returned err = %d\n", err);
6806 return;
6807 }
6808
6809 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6810 if (err)
6811 return;
6812
6813 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6814 if (err) {
6815 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006816 return;
6817 }
6818 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006819}
6820
Arend van Sprielb48d8912014-07-12 08:49:41 +02006821static void brcmf_free_wiphy(struct wiphy *wiphy)
6822{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006823 int i;
6824
Arend van Spriel58de92d2015-04-14 20:10:24 +02006825 if (!wiphy)
6826 return;
6827
Arend van Spriel0882dda2015-08-20 22:06:03 +02006828 if (wiphy->iface_combinations) {
6829 for (i = 0; i < wiphy->n_iface_combinations; i++)
6830 kfree(wiphy->iface_combinations[i].limits);
6831 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006832 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006833 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6834 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6835 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006836 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006837 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6838 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6839 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006840 }
6841 wiphy_free(wiphy);
6842}
6843
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006844struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006845 struct device *busdev,
6846 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006847{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006848 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006849 struct brcmf_cfg80211_info *cfg;
6850 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006851 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006852 struct brcmf_cfg80211_vif *vif;
6853 struct brcmf_if *ifp;
6854 s32 err = 0;
6855 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006856 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006857
6858 if (!ndev) {
6859 brcmf_err("ndev is invalid\n");
6860 return NULL;
6861 }
6862
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306863 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006864 if (!ops)
6865 return NULL;
6866
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006867 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006868#ifdef CONFIG_PM
6869 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6870 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6871#endif
6872 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006873 if (!wiphy) {
6874 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006875 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006876 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006877 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006878 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006879
6880 cfg = wiphy_priv(wiphy);
6881 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006882 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006883 cfg->pub = drvr;
6884 init_vif_event(&cfg->vif_event);
6885 INIT_LIST_HEAD(&cfg->vif_list);
6886
Rafał Miłecki26072332016-06-06 23:03:55 +02006887 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006888 if (IS_ERR(vif))
6889 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006890
6891 vif->ifp = ifp;
6892 vif->wdev.netdev = ndev;
6893 ndev->ieee80211_ptr = &vif->wdev;
6894 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6895
6896 err = wl_init_priv(cfg);
6897 if (err) {
6898 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006899 brcmf_free_vif(vif);
6900 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006901 }
6902 ifp->vif = vif;
6903
Arend van Sprielb48d8912014-07-12 08:49:41 +02006904 /* determine d11 io type before wiphy setup */
6905 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006906 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006907 brcmf_err("Failed to get D11 version (%d)\n", err);
6908 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006909 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006910 cfg->d11inf.io_type = (u8)io_type;
6911 brcmu_d11_attach(&cfg->d11inf);
6912
6913 err = brcmf_setup_wiphy(wiphy, ifp);
6914 if (err < 0)
6915 goto priv_out;
6916
6917 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006918 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006919 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6920 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6921
6922 /* firmware defaults to 40MHz disabled in 2G band. We signal
6923 * cfg80211 here that we do and have it decide we can enable
6924 * it. But first check if device does support 2G operation.
6925 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006926 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6927 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006928 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6929 }
6930 err = wiphy_register(wiphy);
6931 if (err < 0) {
6932 brcmf_err("Could not register wiphy device (%d)\n", err);
6933 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006934 }
6935
6936 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6937 * setup 40MHz in 2GHz band and enable OBSS scanning.
6938 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006939 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6940 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006941 if (!err)
6942 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6943 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006944 else
6945 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006946 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006947 /* p2p might require that "if-events" get processed by fweh. So
6948 * activate the already registered event handlers now and activate
6949 * the rest when initialization has completed. drvr->config needs to
6950 * be assigned before activating events.
6951 */
6952 drvr->config = cfg;
6953 err = brcmf_fweh_activate_events(ifp);
6954 if (err) {
6955 brcmf_err("FWEH activation failed (%d)\n", err);
6956 goto wiphy_unreg_out;
6957 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006958
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006959 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006960 if (err) {
6961 brcmf_err("P2P initilisation failed (%d)\n", err);
6962 goto wiphy_unreg_out;
6963 }
6964 err = brcmf_btcoex_attach(cfg);
6965 if (err) {
6966 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6967 brcmf_p2p_detach(&cfg->p2p);
6968 goto wiphy_unreg_out;
6969 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006970
Hante Meulemana7b82d42015-12-10 13:43:04 +01006971 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6972 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6973 if (err) {
6974 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6975 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6976 } else {
6977 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6978 brcmf_notify_tdls_peer_event);
6979 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006980 }
6981
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006982 /* (re-) activate FWEH event handling */
6983 err = brcmf_fweh_activate_events(ifp);
6984 if (err) {
6985 brcmf_err("FWEH activation failed (%d)\n", err);
6986 goto wiphy_unreg_out;
6987 }
6988
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006989 /* Fill in some of the advertised nl80211 supported features */
6990 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6991 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6992#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006993 if (wiphy->wowlan &&
6994 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006995 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6996#endif
6997 }
6998
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006999 return cfg;
7000
Arend van Sprielb48d8912014-07-12 08:49:41 +02007001wiphy_unreg_out:
7002 wiphy_unregister(cfg->wiphy);
7003priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007004 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007005 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02007006 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02007007wiphy_out:
7008 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007009 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007010 return NULL;
7011}
7012
7013void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
7014{
7015 if (!cfg)
7016 return;
7017
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007018 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02007019 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01007020 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007021 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02007022 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02007023}