blob: bd245a6c70d948ed865982b453e4c68e5ff2a761 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Franky Lin1bacb042014-06-21 12:11:16 +020022#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020024#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
Hante Meuleman122d3d02014-10-28 14:56:18 +010029#include "core.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010030#include "debug.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020031#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010032#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010033#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020034#include "btcoex.h"
Arend Van Sprielac551362016-11-23 10:25:22 +000035#include "pno.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010036#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020037#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070038#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020039#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020040#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010041#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010042#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020043
Arend van Spriele5806072012-09-19 22:21:08 +020044#define BRCMF_SCAN_IE_LEN_MAX 2048
Arend van Spriele5806072012-09-19 22:21:08 +020045
Hante Meuleman1a873342012-09-27 14:17:54 +020046#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
47#define WPA_OUI_TYPE 1
48#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
49#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010050#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020051
52#define VS_IE_FIXED_HDR_LEN 6
53#define WPA_IE_VERSION_LEN 2
54#define WPA_IE_MIN_OUI_LEN 4
55#define WPA_IE_SUITE_COUNT_LEN 2
56
57#define WPA_CIPHER_NONE 0 /* None */
58#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
59#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
60#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
61#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
62
63#define RSN_AKM_NONE 0 /* None (IBSS) */
64#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
65#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010066#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
67#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020068#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010069#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
70#define RSN_CAP_MFPR_MASK BIT(6)
71#define RSN_CAP_MFPC_MASK BIT(7)
72#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020073
74#define VNDR_IE_CMD_LEN 4 /* length of the set command
75 * string :"add", "del" (+ NUL)
76 */
77#define VNDR_IE_COUNT_OFFSET 4
78#define VNDR_IE_PKTFLAG_OFFSET 8
79#define VNDR_IE_VSIE_OFFSET 12
80#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010081#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
84#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020085
Hante Meuleman89286dc2013-02-08 15:53:46 +010086#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
87#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
88#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
89
Hante Meuleman1678ba82015-12-10 13:43:00 +010090#define BRCMF_SCAN_CHANNEL_TIME 40
91#define BRCMF_SCAN_UNASSOC_TIME 40
92#define BRCMF_SCAN_PASSIVE_TIME 120
93
Hante Meuleman3021ad92016-01-05 11:05:45 +010094#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
95
Arend van Spriel5b435de2011-10-05 13:19:03 +020096#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
97 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
98
Arend van Sprielce81e312012-10-22 13:55:37 -070099static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200100{
Arend van Sprielc1179032012-10-22 13:55:33 -0700101 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100102 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
103 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200104 return false;
105 }
106 return true;
107}
108
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
110#define RATETAB_ENT(_rateid, _flags) \
111 { \
112 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
113 .hw_value = (_rateid), \
114 .flags = (_flags), \
115 }
116
117static struct ieee80211_rate __wl_rates[] = {
118 RATETAB_ENT(BRCM_RATE_1M, 0),
119 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
120 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
121 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
122 RATETAB_ENT(BRCM_RATE_6M, 0),
123 RATETAB_ENT(BRCM_RATE_9M, 0),
124 RATETAB_ENT(BRCM_RATE_12M, 0),
125 RATETAB_ENT(BRCM_RATE_18M, 0),
126 RATETAB_ENT(BRCM_RATE_24M, 0),
127 RATETAB_ENT(BRCM_RATE_36M, 0),
128 RATETAB_ENT(BRCM_RATE_48M, 0),
129 RATETAB_ENT(BRCM_RATE_54M, 0),
130};
131
Arend van Spriel5b435de2011-10-05 13:19:03 +0200132#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200133#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
134#define wl_a_rates (__wl_rates + 4)
135#define wl_a_rates_size (wl_g_rates_size - 4)
136
137#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200138 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200139 .center_freq = (_freq), \
140 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200141 .max_antenna_gain = 0, \
142 .max_power = 30, \
143}
144
145#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200146 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200147 .center_freq = 5000 + (5 * (_channel)), \
148 .hw_value = (_channel), \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200149 .max_antenna_gain = 0, \
150 .max_power = 30, \
151}
152
153static struct ieee80211_channel __wl_2ghz_channels[] = {
154 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
155 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
156 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
157 CHAN2G(13, 2472), CHAN2G(14, 2484)
158};
159
160static struct ieee80211_channel __wl_5ghz_channels[] = {
161 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
162 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
163 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
164 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
165 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
166 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
167};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200168
Arend van Sprielb48d8912014-07-12 08:49:41 +0200169/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200170 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200171 */
172static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200173 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200174 .bitrates = wl_g_rates,
175 .n_bitrates = wl_g_rates_size,
176};
177
Arend van Spriel58de92d2015-04-14 20:10:24 +0200178static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200179 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180 .bitrates = wl_a_rates,
181 .n_bitrates = wl_a_rates_size,
182};
183
Hante Meulemand48200b2013-04-03 12:40:29 +0200184/* This is to override regulatory domains defined in cfg80211 module (reg.c)
185 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200186 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
187 * With respect to these flags, wpa_supplicant doesn't * start p2p
188 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200189 * domain are to be done here.
190 */
191static const struct ieee80211_regdomain brcmf_regdom = {
192 .n_reg_rules = 4,
193 .alpha2 = "99",
194 .reg_rules = {
195 /* IEEE 802.11b/g, channels 1..11 */
196 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
197 /* If any */
198 /* IEEE 802.11 channel 14 - Only JP enables
199 * this and for 802.11b only
200 */
201 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
202 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200203 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200204 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200205 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200206};
207
Hante Meuleman240d61a2016-02-17 11:27:10 +0100208/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
209 * are supported. A pointer to this array and the number of entries is passed
210 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
211 * So the cipher suite AES_CMAC has to be the last one in the array, and when
212 * device does not support MFP then the number of suites will be decreased by 1
213 */
214static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200215 WLAN_CIPHER_SUITE_WEP40,
216 WLAN_CIPHER_SUITE_WEP104,
217 WLAN_CIPHER_SUITE_TKIP,
218 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219 /* Keep as last entry: */
220 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200221};
222
Hante Meuleman1a873342012-09-27 14:17:54 +0200223/* Vendor specific ie. id = 221, oui and type defines exact ie */
224struct brcmf_vs_tlv {
225 u8 id;
226 u8 len;
227 u8 oui[3];
228 u8 oui_type;
229};
230
231struct parsed_vndr_ie_info {
232 u8 *ie_ptr;
233 u32 ie_len; /* total length including id & length field */
234 struct brcmf_vs_tlv vndrie;
235};
236
237struct parsed_vndr_ies {
238 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100239 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200240};
241
Arend van Spriel7705ba62016-04-17 16:44:58 +0200242static u8 nl80211_band_to_fwil(enum nl80211_band band)
243{
244 switch (band) {
245 case NL80211_BAND_2GHZ:
246 return WLC_BAND_2G;
247 case NL80211_BAND_5GHZ:
248 return WLC_BAND_5G;
249 default:
250 WARN_ON(1);
251 break;
252 }
253 return 0;
254}
255
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200256static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
257 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200258{
259 struct brcmu_chan ch_inf;
260 s32 primary_offset;
261
262 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
263 ch->chan->center_freq, ch->center_freq1, ch->width);
264 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100265 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200266 switch (ch->width) {
267 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100268 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200269 ch_inf.bw = BRCMU_CHAN_BW_20;
270 WARN_ON(primary_offset != 0);
271 break;
272 case NL80211_CHAN_WIDTH_40:
273 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100274 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200275 ch_inf.sb = BRCMU_CHAN_SB_U;
276 else
277 ch_inf.sb = BRCMU_CHAN_SB_L;
278 break;
279 case NL80211_CHAN_WIDTH_80:
280 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100281 if (primary_offset == -30)
282 ch_inf.sb = BRCMU_CHAN_SB_LL;
283 else if (primary_offset == -10)
284 ch_inf.sb = BRCMU_CHAN_SB_LU;
285 else if (primary_offset == 10)
286 ch_inf.sb = BRCMU_CHAN_SB_UL;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200289 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100290 case NL80211_CHAN_WIDTH_80P80:
291 case NL80211_CHAN_WIDTH_160:
292 case NL80211_CHAN_WIDTH_5:
293 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200294 default:
295 WARN_ON_ONCE(1);
296 }
297 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200298 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200299 ch_inf.band = BRCMU_CHAN_BAND_2G;
300 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200301 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200302 ch_inf.band = BRCMU_CHAN_BAND_5G;
303 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200304 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 d11inf->encchspec(&ch_inf);
309
310 return ch_inf.chspec;
311}
312
Franky Lin83cf17a2013-04-11 13:28:50 +0200313u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
314 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700315{
Franky Lin83cf17a2013-04-11 13:28:50 +0200316 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700317
Franky Lin83cf17a2013-04-11 13:28:50 +0200318 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
319 ch_inf.bw = BRCMU_CHAN_BW_20;
320 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700321
Franky Lin83cf17a2013-04-11 13:28:50 +0200322 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700323}
324
Hante Meuleman89286dc2013-02-08 15:53:46 +0100325/* Traverse a string of 1-byte tag/1-byte length/variable-length value
326 * triples, returning a pointer to the substring whose first element
327 * matches tag
328 */
Rafał Miłeckic8d87072017-01-18 11:48:51 +0100329static const struct brcmf_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100330brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100331{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100332 const struct brcmf_tlv *elt = buf;
333 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100334
335 /* find tagged parameter */
336 while (totlen >= TLV_HDR_LEN) {
337 int len = elt->len;
338
339 /* validate remaining totlen */
340 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
341 return elt;
342
343 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
344 totlen -= (len + TLV_HDR_LEN);
345 }
346
347 return NULL;
348}
349
350/* Is any of the tlvs the expected entry? If
351 * not update the tlvs buffer pointer/length.
352 */
353static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100354brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
355 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100356{
357 /* If the contents match the OUI and the type */
358 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
359 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
360 type == ie[TLV_BODY_OFF + oui_len]) {
361 return true;
362 }
363
364 if (tlvs == NULL)
365 return false;
366 /* point to the next ie */
367 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
368 /* calculate the length of the rest of the buffer */
369 *tlvs_len -= (int)(ie - *tlvs);
370 /* update the pointer to the start of the buffer */
371 *tlvs = ie;
372
373 return false;
374}
375
376static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100377brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100378{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100379 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100380
381 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100382 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100383 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
384 return (struct brcmf_vs_tlv *)ie;
385 }
386 return NULL;
387}
388
389static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100392 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100393
394 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
395 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
396 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
397 return (struct brcmf_vs_tlv *)ie;
398 }
399 return NULL;
400}
401
Arend van Spriel39504a22015-08-20 22:06:05 +0200402static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
403 struct brcmf_cfg80211_vif *vif,
404 enum nl80211_iftype new_type)
405{
Arend van Spriel39504a22015-08-20 22:06:05 +0200406 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100407 bool check_combos = false;
408 int ret = 0;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530409 struct iface_combination_params params = {
410 .num_different_channels = 1,
411 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100414 if (pos == vif) {
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530415 params.iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100416 } else {
417 /* concurrent interfaces so need check combinations */
418 check_combos = true;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530419 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100420 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
Arend van Spriel353c46a2015-12-10 13:43:06 +0100422 if (check_combos)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530423 ret = cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424
425 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200426}
427
428static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
429 enum nl80211_iftype new_type)
430{
Arend van Spriel39504a22015-08-20 22:06:05 +0200431 struct brcmf_cfg80211_vif *pos;
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530432 struct iface_combination_params params = {
433 .num_different_channels = 1,
434 };
Arend van Spriel39504a22015-08-20 22:06:05 +0200435
Arend van Spriel39504a22015-08-20 22:06:05 +0200436 list_for_each_entry(pos, &cfg->vif_list, list)
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530437 params.iftype_num[pos->wdev.iftype]++;
Arend van Spriel39504a22015-08-20 22:06:05 +0200438
Purushottam Kushwahae2273002016-10-12 18:25:35 +0530439 params.iftype_num[new_type]++;
440 return cfg80211_check_combinations(cfg->wiphy, &params);
Arend van Spriel39504a22015-08-20 22:06:05 +0200441}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100442
Arend van Spriel5b435de2011-10-05 13:19:03 +0200443static void convert_key_from_CPU(struct brcmf_wsec_key *key,
444 struct brcmf_wsec_key_le *key_le)
445{
446 key_le->index = cpu_to_le32(key->index);
447 key_le->len = cpu_to_le32(key->len);
448 key_le->algo = cpu_to_le32(key->algo);
449 key_le->flags = cpu_to_le32(key->flags);
450 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
451 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
452 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
453 memcpy(key_le->data, key->data, sizeof(key->data));
454 memcpy(key_le->ea, key->ea, sizeof(key->ea));
455}
456
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200457static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100458send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459{
460 int err;
461 struct brcmf_wsec_key_le key_le;
462
463 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200464
Hante Meuleman118eb302014-12-21 12:43:49 +0100465 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700466
Hante Meuleman118eb302014-12-21 12:43:49 +0100467 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700468 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200469
Arend van Spriel5b435de2011-10-05 13:19:03 +0200470 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100471 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 return err;
473}
474
Hante Meulemanb3657452013-05-27 21:09:53 +0200475static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100476brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200477{
478 s32 err;
479 u32 mode;
480
481 if (enable)
482 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
483 else
484 mode = 0;
485
486 /* Try to set and enable ARP offload feature, this may fail, then it */
487 /* is simply not supported and err 0 will be returned */
488 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
489 if (err) {
490 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
491 mode, err);
492 err = 0;
493 } else {
494 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
495 if (err) {
496 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
497 enable, err);
498 err = 0;
499 } else
500 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
501 enable, mode);
502 }
503
Franky Lin52f22fb2016-02-17 11:26:55 +0100504 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
505 if (err) {
506 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
507 enable, err);
508 err = 0;
509 } else
510 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
511 enable, mode);
512
Hante Meulemanb3657452013-05-27 21:09:53 +0200513 return err;
514}
515
Hante Meuleman8851cce2014-07-30 13:20:02 +0200516static void
517brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
518{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200519 struct brcmf_cfg80211_vif *vif;
520 struct brcmf_if *ifp;
521
522 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
523 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200524
525 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
526 (wdev->iftype == NL80211_IFTYPE_AP) ||
527 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
528 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
529 ADDR_DIRECT);
530 else
531 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
532 ADDR_INDIRECT);
533}
534
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200535static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
536{
537 int bsscfgidx;
538
539 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
540 /* bsscfgidx 1 is reserved for legacy P2P */
541 if (bsscfgidx == 1)
542 continue;
543 if (!drvr->iflist[bsscfgidx])
544 return bsscfgidx;
545 }
546
547 return -ENOMEM;
548}
549
Hante Meulemana44aa402014-12-03 21:05:33 +0100550static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
551{
552 struct brcmf_mbss_ssid_le mbss_ssid_le;
553 int bsscfgidx;
554 int err;
555
556 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200557 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100558 if (bsscfgidx < 0)
559 return bsscfgidx;
560
561 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
562 mbss_ssid_le.SSID_len = cpu_to_le32(5);
563 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
564
565 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
566 sizeof(mbss_ssid_le));
567 if (err < 0)
568 brcmf_err("setting ssid failed %d\n", err);
569
570 return err;
571}
572
573/**
574 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
575 *
576 * @wiphy: wiphy device of new interface.
577 * @name: name of the new interface.
Hante Meulemana44aa402014-12-03 21:05:33 +0100578 * @params: contains mac address for AP device.
579 */
580static
581struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
Johannes Berg818a9862017-04-12 11:23:28 +0200582 struct vif_params *params)
Hante Meulemana44aa402014-12-03 21:05:33 +0100583{
584 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
585 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
586 struct brcmf_cfg80211_vif *vif;
587 int err;
588
589 if (brcmf_cfg80211_vif_event_armed(cfg))
590 return ERR_PTR(-EBUSY);
591
592 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
593
Rafał Miłecki26072332016-06-06 23:03:55 +0200594 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100595 if (IS_ERR(vif))
596 return (struct wireless_dev *)vif;
597
598 brcmf_cfg80211_arm_vif_event(cfg, vif);
599
600 err = brcmf_cfg80211_request_ap_if(ifp);
601 if (err) {
602 brcmf_cfg80211_arm_vif_event(cfg, NULL);
603 goto fail;
604 }
605
606 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100607 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
608 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100609 brcmf_cfg80211_arm_vif_event(cfg, NULL);
610 if (!err) {
611 brcmf_err("timeout occurred\n");
612 err = -EIO;
613 goto fail;
614 }
615
616 /* interface created in firmware */
617 ifp = vif->ifp;
618 if (!ifp) {
619 brcmf_err("no if pointer provided\n");
620 err = -ENOENT;
621 goto fail;
622 }
623
624 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
625 err = brcmf_net_attach(ifp, true);
626 if (err) {
627 brcmf_err("Registering netdevice failed\n");
628 goto fail;
629 }
630
631 return &ifp->vif->wdev;
632
633fail:
634 brcmf_free_vif(vif);
635 return ERR_PTR(err);
636}
637
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100638static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
639{
640 enum nl80211_iftype iftype;
641
642 iftype = vif->wdev.iftype;
643 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
644}
645
646static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
647{
648 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
649}
650
Arend van Spriel9f440b72013-02-08 15:53:36 +0100651static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
652 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100653 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100654 enum nl80211_iftype type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100655 struct vif_params *params)
656{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200657 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200658 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200659
Arend van Spriel9f440b72013-02-08 15:53:36 +0100660 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200661 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
662 if (err) {
663 brcmf_err("iface validation failed: err=%d\n", err);
664 return ERR_PTR(err);
665 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100666 switch (type) {
667 case NL80211_IFTYPE_ADHOC:
668 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100669 case NL80211_IFTYPE_AP_VLAN:
670 case NL80211_IFTYPE_WDS:
671 case NL80211_IFTYPE_MONITOR:
672 case NL80211_IFTYPE_MESH_POINT:
673 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100674 case NL80211_IFTYPE_AP:
Johannes Berg818a9862017-04-12 11:23:28 +0200675 wdev = brcmf_ap_add_vif(wiphy, name, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200676 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100677 case NL80211_IFTYPE_P2P_CLIENT:
678 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200679 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg818a9862017-04-12 11:23:28 +0200680 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200681 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100682 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100683 default:
684 return ERR_PTR(-EINVAL);
685 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200686
687 if (IS_ERR(wdev))
688 brcmf_err("add iface %s type %d failed: err=%d\n",
689 name, type, (int)PTR_ERR(wdev));
690 else
691 brcmf_cfg80211_update_proto_addr_mode(wdev);
692
693 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100694}
695
Daniel Kim5e787f72014-06-21 12:11:18 +0200696static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
697{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200698 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200699 brcmf_set_mpc(ifp, mpc);
700}
701
Arend van Sprielf96aa072013-04-05 10:57:48 +0200702void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100703{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100704 s32 err = 0;
705
706 if (check_vif_up(ifp->vif)) {
707 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
708 if (err) {
709 brcmf_err("fail to set mpc\n");
710 return;
711 }
712 brcmf_dbg(INFO, "MPC : %d\n", mpc);
713 }
714}
715
Arend van Spriela0f472a2013-04-05 10:57:49 +0200716s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
717 struct brcmf_if *ifp, bool aborted,
718 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100719{
720 struct brcmf_scan_params_le params_le;
721 struct cfg80211_scan_request *scan_request;
722 s32 err = 0;
723
724 brcmf_dbg(SCAN, "Enter\n");
725
726 /* clear scan request, because the FW abort can cause a second call */
727 /* to this functon and might cause a double cfg80211_scan_done */
728 scan_request = cfg->scan_request;
729 cfg->scan_request = NULL;
730
731 if (timer_pending(&cfg->escan_timeout))
732 del_timer_sync(&cfg->escan_timeout);
733
734 if (fw_abort) {
735 /* Do a scan abort to stop the driver's scan engine */
736 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
737 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800738 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100739 params_le.bss_type = DOT11_BSSTYPE_ANY;
740 params_le.scan_type = 0;
741 params_le.channel_num = cpu_to_le32(1);
742 params_le.nprobes = cpu_to_le32(1);
743 params_le.active_time = cpu_to_le32(-1);
744 params_le.passive_time = cpu_to_le32(-1);
745 params_le.home_time = cpu_to_le32(-1);
746 /* Scan is aborted by setting channel_list[0] to -1 */
747 params_le.channel_list[0] = cpu_to_le16(-1);
748 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200749 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100750 &params_le, sizeof(params_le));
751 if (err)
752 brcmf_err("Scan abort failed\n");
753 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200754
Daniel Kim5e787f72014-06-21 12:11:18 +0200755 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200756
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100757 /*
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000758 * e-scan can be initiated internally
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100759 * which takes precedence.
760 */
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000761 if (cfg->internal_escan) {
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100762 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend Van Sprielfa85b302016-11-23 10:25:25 +0000763 cfg->internal_escan = false;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100764 if (!aborted)
765 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100766 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300767 struct cfg80211_scan_info info = {
768 .aborted = aborted,
769 };
770
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100771 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
772 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300773 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100774 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100775 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
776 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100777
778 return err;
779}
780
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200781static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
782 struct wireless_dev *wdev)
783{
784 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
785 struct net_device *ndev = wdev->netdev;
786 struct brcmf_if *ifp = netdev_priv(ndev);
787 int ret;
788 int err;
789
790 brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
791
792 err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
793 if (err) {
794 brcmf_err("interface_remove failed %d\n", err);
795 goto err_unarm;
796 }
797
798 /* wait for firmware event */
799 ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
800 BRCMF_VIF_EVENT_TIMEOUT);
801 if (!ret) {
802 brcmf_err("timeout occurred\n");
803 err = -EIO;
804 goto err_unarm;
805 }
806
807 brcmf_remove_interface(ifp, true);
808
809err_unarm:
810 brcmf_cfg80211_arm_vif_event(cfg, NULL);
811 return err;
812}
813
Arend van Spriel9f440b72013-02-08 15:53:36 +0100814static
815int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
816{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100817 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
818 struct net_device *ndev = wdev->netdev;
819
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200820 if (ndev && ndev == cfg_to_ndev(cfg))
821 return -ENOTSUPP;
822
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100823 /* vif event pending in firmware */
824 if (brcmf_cfg80211_vif_event_armed(cfg))
825 return -EBUSY;
826
827 if (ndev) {
828 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200829 cfg->escan_info.ifp == netdev_priv(ndev))
830 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
831 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100832
833 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
834 }
835
Arend van Spriel9f440b72013-02-08 15:53:36 +0100836 switch (wdev->iftype) {
837 case NL80211_IFTYPE_ADHOC:
838 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100839 case NL80211_IFTYPE_AP_VLAN:
840 case NL80211_IFTYPE_WDS:
841 case NL80211_IFTYPE_MONITOR:
842 case NL80211_IFTYPE_MESH_POINT:
843 return -EOPNOTSUPP;
Rafał Miłeckidba8fbc2016-06-29 21:54:27 +0200844 case NL80211_IFTYPE_AP:
845 return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100846 case NL80211_IFTYPE_P2P_CLIENT:
847 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200848 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100849 return brcmf_p2p_del_vif(wiphy, wdev);
850 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100851 default:
852 return -EINVAL;
853 }
854 return -EOPNOTSUPP;
855}
856
Arend van Spriel5b435de2011-10-05 13:19:03 +0200857static s32
858brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg818a9862017-04-12 11:23:28 +0200859 enum nl80211_iftype type,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860 struct vif_params *params)
861{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100862 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700863 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100864 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200865 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200866 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200867 s32 err = 0;
868
Hante Meuleman37a869e2015-10-29 20:33:17 +0100869 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
870 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200871
872 /* WAR: There are a number of p2p interface related problems which
873 * need to be handled initially (before doing the validate).
874 * wpa_supplicant tends to do iface changes on p2p device/client/go
875 * which are not always possible/allowed. However we need to return
876 * OK otherwise the wpa_supplicant wont start. The situation differs
877 * on configuration and setup (p2pon=1 module param). The first check
878 * is to see if the request is a change to station for p2p iface.
879 */
880 if ((type == NL80211_IFTYPE_STATION) &&
881 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
882 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
883 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
884 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
885 /* Now depending on whether module param p2pon=1 was used the
886 * response needs to be either 0 or EOPNOTSUPP. The reason is
887 * that if p2pon=1 is used, but a newer supplicant is used then
888 * we should return an error, as this combination wont work.
889 * In other situations 0 is returned and supplicant will start
890 * normally. It will give a trace in cfg80211, but it is the
891 * only way to get it working. Unfortunately this will result
892 * in situation where we wont support new supplicant in
893 * combination with module param p2pon=1, but that is the way
894 * it is. If the user tries this then unloading of driver might
895 * fail/lock.
896 */
897 if (cfg->p2p.p2pdev_dynamically)
898 return -EOPNOTSUPP;
899 else
900 return 0;
901 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200902 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
903 if (err) {
904 brcmf_err("iface validation failed: err=%d\n", err);
905 return err;
906 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200907 switch (type) {
908 case NL80211_IFTYPE_MONITOR:
909 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100910 brcmf_err("type (%d) : currently we do not support this type\n",
911 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200912 return -EOPNOTSUPP;
913 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200914 infra = 0;
915 break;
916 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200917 infra = 1;
918 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200919 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100920 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200921 ap = 1;
922 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200923 default:
924 err = -EINVAL;
925 goto done;
926 }
927
Hante Meuleman1a873342012-09-27 14:17:54 +0200928 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100929 if (type == NL80211_IFTYPE_P2P_GO) {
930 brcmf_dbg(INFO, "IF Type = P2P GO\n");
931 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
932 }
933 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100934 brcmf_dbg(INFO, "IF Type = AP\n");
935 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200936 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100937 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200938 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100939 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200940 err = -EAGAIN;
941 goto done;
942 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100943 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100944 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200945 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200946 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200947
Hante Meuleman8851cce2014-07-30 13:20:02 +0200948 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
949
Arend van Spriel5b435de2011-10-05 13:19:03 +0200950done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100951 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200952
953 return err;
954}
955
Franky Lin83cf17a2013-04-11 13:28:50 +0200956static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
957 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200958 struct cfg80211_scan_request *request)
959{
960 u32 n_ssids;
961 u32 n_channels;
962 s32 i;
963 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200964 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200965 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200966 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200967
Joe Perches93803b32015-03-02 19:54:49 -0800968 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200969 params_le->bss_type = DOT11_BSSTYPE_ANY;
970 params_le->scan_type = 0;
971 params_le->channel_num = 0;
972 params_le->nprobes = cpu_to_le32(-1);
973 params_le->active_time = cpu_to_le32(-1);
974 params_le->passive_time = cpu_to_le32(-1);
975 params_le->home_time = cpu_to_le32(-1);
976 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
977
978 /* if request is null exit so it will be all channel broadcast scan */
979 if (!request)
980 return;
981
982 n_ssids = request->n_ssids;
983 n_channels = request->n_channels;
984 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100985 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
986 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200987 if (n_channels > 0) {
988 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200989 chanspec = channel_to_chanspec(&cfg->d11inf,
990 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100991 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
992 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200993 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200994 }
995 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100996 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200997 }
998 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100999 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001000 if (n_ssids > 0) {
1001 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
1002 n_channels * sizeof(u16);
1003 offset = roundup(offset, sizeof(u32));
1004 ptr = (char *)params_le + offset;
1005 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +02001006 memset(&ssid_le, 0, sizeof(ssid_le));
1007 ssid_le.SSID_len =
1008 cpu_to_le32(request->ssids[i].ssid_len);
1009 memcpy(ssid_le.SSID, request->ssids[i].ssid,
1010 request->ssids[i].ssid_len);
1011 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001012 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +02001013 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001014 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
1015 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +02001016 memcpy(ptr, &ssid_le, sizeof(ssid_le));
1017 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +02001018 }
1019 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001020 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +02001021 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001022 brcmf_dbg(SCAN, "SSID %s len=%d\n",
1023 params_le->ssid_le.SSID,
1024 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001025 params_le->ssid_le.SSID_len =
1026 cpu_to_le32(request->ssids->ssid_len);
1027 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1028 request->ssids->ssid_len);
1029 }
1030 }
1031 /* Adding mask to channel numbers */
1032 params_le->channel_num =
1033 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1034 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1035}
1036
1037static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001038brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001039 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001040{
1041 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1042 offsetof(struct brcmf_escan_params_le, params_le);
1043 struct brcmf_escan_params_le *params;
1044 s32 err = 0;
1045
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001046 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001047
1048 if (request != NULL) {
1049 /* Allocate space for populating ssids in struct */
1050 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1051
1052 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001053 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001054 }
1055
1056 params = kzalloc(params_size, GFP_KERNEL);
1057 if (!params) {
1058 err = -ENOMEM;
1059 goto exit;
1060 }
1061 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001062 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001063 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001064 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001065 params->sync_id = cpu_to_le16(0x1234);
1066
Arend van Spriela0f472a2013-04-05 10:57:49 +02001067 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001068 if (err) {
1069 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001070 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001071 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001072 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001073 }
1074
1075 kfree(params);
1076exit:
1077 return err;
1078}
1079
1080static s32
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001081brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001082{
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001083 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02001084 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001085 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001086 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001087 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001088
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001089 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001090 escan->ifp = ifp;
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001091 escan->wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001092 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001093 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001094 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001095 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001096 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001097 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001098 return err;
1099 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001100 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001101 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001102 results->version = 0;
1103 results->count = 0;
1104 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1105
Hante Meulemanc4958102015-11-25 11:32:41 +01001106 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001107 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001108 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 return err;
1110}
1111
1112static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001113brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001114 struct cfg80211_scan_request *request,
1115 struct cfg80211_ssid *this_ssid)
1116{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001117 struct brcmf_if *ifp = vif->ifp;
1118 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001119 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001120 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001121 bool escan_req;
1122 bool spec_scan;
1123 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001124 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001125 u32 SSID_len;
1126
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001127 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001128
Arend van Sprielc1179032012-10-22 13:55:33 -07001129 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001130 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001131 return -EAGAIN;
1132 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001133 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001134 brcmf_err("Scanning being aborted: status (%lu)\n",
1135 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001136 return -EAGAIN;
1137 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001138 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1139 brcmf_err("Scanning suppressed: status (%lu)\n",
1140 cfg->scan_status);
1141 return -EAGAIN;
1142 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001143 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001144 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001145 return -EAGAIN;
1146 }
1147
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001148 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001149 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1150 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001151
Hante Meulemane756af52012-09-11 21:18:52 +02001152 escan_req = false;
1153 if (request) {
1154 /* scan bss */
1155 ssids = request->ssids;
1156 escan_req = true;
1157 } else {
1158 /* scan in ibss */
1159 /* we don't do escan in ibss */
1160 ssids = this_ssid;
1161 }
1162
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001163 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001164 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001165 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001166 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001167 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001168 if (err)
1169 goto scan_out;
1170
Arend Van Sprielab5981c2016-11-23 10:25:24 +00001171 err = brcmf_do_escan(vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001172 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001173 goto scan_out;
1174 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001175 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1176 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001177 memset(&ssid_le, 0, sizeof(ssid_le));
1178 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1179 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001180 spec_scan = false;
1181 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001182 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1183 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001184 spec_scan = true;
1185 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001186 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001187
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001188 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001189 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001190 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001191 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001192 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001193 goto scan_out;
1194 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001195 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001196 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1197 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001198 if (err) {
1199 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001200 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001201 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001202 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001203 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001204
Daniel Kim5e787f72014-06-21 12:11:18 +02001205 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001206 goto scan_out;
1207 }
1208 }
1209
Hante Meuleman661fa952015-02-06 18:36:47 +01001210 /* Arm scan timeout timer */
1211 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001212 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001213
Hante Meulemane756af52012-09-11 21:18:52 +02001214 return 0;
1215
1216scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001217 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001218 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001219 return err;
1220}
1221
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001223brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001224{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001225 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226 s32 err = 0;
1227
Arend van Sprield96b8012012-12-05 15:26:02 +01001228 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001229 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1230 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001231 return -EIO;
1232
Arend van Spriela0f472a2013-04-05 10:57:49 +02001233 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001234
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001236 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237
Arend van Sprield96b8012012-12-05 15:26:02 +01001238 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 return err;
1240}
1241
1242static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1243{
1244 s32 err = 0;
1245
Arend van Sprielac24be62012-10-22 10:36:23 -07001246 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1247 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001249 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250
1251 return err;
1252}
1253
1254static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1255{
1256 s32 err = 0;
1257
Arend van Sprielac24be62012-10-22 10:36:23 -07001258 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1259 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001260 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001261 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262
1263 return err;
1264}
1265
1266static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1267{
1268 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001269 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001270
Arend van Sprielac24be62012-10-22 10:36:23 -07001271 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001273 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001274 return err;
1275 }
1276 return err;
1277}
1278
1279static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1280{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001281 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1282 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001283 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001284 s32 err = 0;
1285
Arend van Sprield96b8012012-12-05 15:26:02 +01001286 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001287 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288 return -EIO;
1289
1290 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001291 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1292 cfg->conf->rts_threshold = wiphy->rts_threshold;
1293 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001294 if (!err)
1295 goto done;
1296 }
1297 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001298 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1299 cfg->conf->frag_threshold = wiphy->frag_threshold;
1300 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301 if (!err)
1302 goto done;
1303 }
1304 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001305 && (cfg->conf->retry_long != wiphy->retry_long)) {
1306 cfg->conf->retry_long = wiphy->retry_long;
1307 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001308 if (!err)
1309 goto done;
1310 }
1311 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001312 && (cfg->conf->retry_short != wiphy->retry_short)) {
1313 cfg->conf->retry_short = wiphy->retry_short;
1314 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001315 if (!err)
1316 goto done;
1317 }
1318
1319done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001320 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 return err;
1322}
1323
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1325{
1326 memset(prof, 0, sizeof(*prof));
1327}
1328
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001329static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1330{
1331 u16 reason;
1332
1333 switch (e->event_code) {
1334 case BRCMF_E_DEAUTH:
1335 case BRCMF_E_DEAUTH_IND:
1336 case BRCMF_E_DISASSOC_IND:
1337 reason = e->reason;
1338 break;
1339 case BRCMF_E_LINK:
1340 default:
1341 reason = 0;
1342 break;
1343 }
1344 return reason;
1345}
1346
1347static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001348{
Piotr Haber61730d42013-04-23 12:53:12 +02001349 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350 s32 err = 0;
1351
Arend van Sprield96b8012012-12-05 15:26:02 +01001352 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353
Hante Meulemanb0a79082015-12-10 13:43:07 +01001354 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001355 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001356 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001357 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001358 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001359 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001360 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001361 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1362 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1363 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1364 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001365 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001366 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001367 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1368 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001369 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001370}
1371
1372static s32
1373brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1374 struct cfg80211_ibss_params *params)
1375{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001376 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001377 struct brcmf_if *ifp = netdev_priv(ndev);
1378 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001379 struct brcmf_join_params join_params;
1380 size_t join_params_size = 0;
1381 s32 err = 0;
1382 s32 wsec = 0;
1383 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001384 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001385 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001386
Arend van Sprield96b8012012-12-05 15:26:02 +01001387 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001388 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001389 return -EIO;
1390
1391 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001392 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001393 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001394 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001395 return -EOPNOTSUPP;
1396 }
1397
Arend van Sprielc1179032012-10-22 13:55:33 -07001398 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399
1400 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001401 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 else
Arend van Spriel16886732012-12-05 15:26:04 +01001403 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404
Johannes Berg683b6d32012-11-08 21:25:48 +01001405 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001406 brcmf_dbg(CONN, "channel: %d\n",
1407 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 else
Arend van Spriel16886732012-12-05 15:26:04 +01001409 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410
1411 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001412 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001413 else
Arend van Spriel16886732012-12-05 15:26:04 +01001414 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415
1416 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001417 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418 else
Arend van Spriel16886732012-12-05 15:26:04 +01001419 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001420
1421 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001422 brcmf_dbg(CONN, "beacon interval: %d\n",
1423 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 else
Arend van Spriel16886732012-12-05 15:26:04 +01001425 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001426
1427 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001428 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 else
Arend van Spriel16886732012-12-05 15:26:04 +01001430 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431
1432 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001433 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001434 else
Arend van Spriel16886732012-12-05 15:26:04 +01001435 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436
1437 /* Configure Privacy for starter */
1438 if (params->privacy)
1439 wsec |= WEP_ENABLED;
1440
Arend van Sprielc1179032012-10-22 13:55:33 -07001441 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001443 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001444 goto done;
1445 }
1446
1447 /* Configure Beacon Interval for starter */
1448 if (params->beacon_interval)
1449 bcnprd = params->beacon_interval;
1450 else
1451 bcnprd = 100;
1452
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001453 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001454 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001455 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 goto done;
1457 }
1458
1459 /* Configure required join parameter */
1460 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1461
1462 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001463 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1464 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1465 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467
1468 /* BSSID */
1469 if (params->bssid) {
1470 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001471 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001472 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001474 eth_broadcast_addr(join_params.params_le.bssid);
1475 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001476 }
1477
Arend van Spriel5b435de2011-10-05 13:19:03 +02001478 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001479 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 u32 target_channel;
1481
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001482 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001483 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001484 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001485 if (params->channel_fixed) {
1486 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001487 chanspec = chandef_to_chanspec(&cfg->d11inf,
1488 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001489 join_params.params_le.chanspec_list[0] =
1490 cpu_to_le16(chanspec);
1491 join_params.params_le.chanspec_num = cpu_to_le32(1);
1492 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001493 }
1494
1495 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001496 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001497 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001498 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001499 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001500 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501 goto done;
1502 }
1503 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001504 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001506 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001507
1508
Arend van Sprielc1179032012-10-22 13:55:33 -07001509 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001510 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001512 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001513 goto done;
1514 }
1515
1516done:
1517 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001518 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001519 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001520 return err;
1521}
1522
1523static s32
1524brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1525{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001526 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001527
Arend van Sprield96b8012012-12-05 15:26:02 +01001528 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001529 if (!check_vif_up(ifp->vif)) {
1530 /* When driver is being unloaded, it can end up here. If an
1531 * error is returned then later on a debug trace in the wireless
1532 * core module will be printed. To avoid this 0 is returned.
1533 */
1534 return 0;
1535 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001536
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001537 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001538 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539
Arend van Sprield96b8012012-12-05 15:26:02 +01001540 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001541
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001542 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543}
1544
1545static s32 brcmf_set_wpa_version(struct net_device *ndev,
1546 struct cfg80211_connect_params *sme)
1547{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001548 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549 struct brcmf_cfg80211_security *sec;
1550 s32 val = 0;
1551 s32 err = 0;
1552
1553 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1554 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1555 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1556 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1557 else
1558 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001559 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001560 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001561 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001562 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001563 return err;
1564 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001565 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001566 sec->wpa_versions = sme->crypto.wpa_versions;
1567 return err;
1568}
1569
1570static s32 brcmf_set_auth_type(struct net_device *ndev,
1571 struct cfg80211_connect_params *sme)
1572{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001573 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 struct brcmf_cfg80211_security *sec;
1575 s32 val = 0;
1576 s32 err = 0;
1577
1578 switch (sme->auth_type) {
1579 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1580 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001581 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 break;
1583 case NL80211_AUTHTYPE_SHARED_KEY:
1584 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001585 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587 default:
1588 val = 2;
Hante Meuleman92c31362016-09-19 12:09:59 +01001589 brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001590 break;
1591 }
1592
Hante Meuleman89286dc2013-02-08 15:53:46 +01001593 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001594 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001595 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001596 return err;
1597 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001598 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 sec->auth_type = sme->auth_type;
1600 return err;
1601}
1602
1603static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001604brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001605 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001606{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001607 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001608 struct brcmf_cfg80211_security *sec;
1609 s32 pval = 0;
1610 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001611 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612 s32 err = 0;
1613
1614 if (sme->crypto.n_ciphers_pairwise) {
1615 switch (sme->crypto.ciphers_pairwise[0]) {
1616 case WLAN_CIPHER_SUITE_WEP40:
1617 case WLAN_CIPHER_SUITE_WEP104:
1618 pval = WEP_ENABLED;
1619 break;
1620 case WLAN_CIPHER_SUITE_TKIP:
1621 pval = TKIP_ENABLED;
1622 break;
1623 case WLAN_CIPHER_SUITE_CCMP:
1624 pval = AES_ENABLED;
1625 break;
1626 case WLAN_CIPHER_SUITE_AES_CMAC:
1627 pval = AES_ENABLED;
1628 break;
1629 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001630 brcmf_err("invalid cipher pairwise (%d)\n",
1631 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 return -EINVAL;
1633 }
1634 }
1635 if (sme->crypto.cipher_group) {
1636 switch (sme->crypto.cipher_group) {
1637 case WLAN_CIPHER_SUITE_WEP40:
1638 case WLAN_CIPHER_SUITE_WEP104:
1639 gval = WEP_ENABLED;
1640 break;
1641 case WLAN_CIPHER_SUITE_TKIP:
1642 gval = TKIP_ENABLED;
1643 break;
1644 case WLAN_CIPHER_SUITE_CCMP:
1645 gval = AES_ENABLED;
1646 break;
1647 case WLAN_CIPHER_SUITE_AES_CMAC:
1648 gval = AES_ENABLED;
1649 break;
1650 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001651 brcmf_err("invalid cipher group (%d)\n",
1652 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 return -EINVAL;
1654 }
1655 }
1656
Arend van Spriel16886732012-12-05 15:26:04 +01001657 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001658 /* In case of privacy, but no security and WPS then simulate */
1659 /* setting AES. WPS-2.0 allows no security */
1660 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1661 sme->privacy)
1662 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001663
Hante Meuleman240d61a2016-02-17 11:27:10 +01001664 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001665 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001666 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001667 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001668 return err;
1669 }
1670
Arend van Spriel06bb1232012-09-27 14:17:56 +02001671 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1673 sec->cipher_group = sme->crypto.cipher_group;
1674
1675 return err;
1676}
1677
1678static s32
1679brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1680{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001681 struct brcmf_if *ifp = netdev_priv(ndev);
1682 s32 val;
1683 s32 err;
1684 const struct brcmf_tlv *rsn_ie;
1685 const u8 *ie;
1686 u32 ie_len;
1687 u32 offset;
1688 u16 rsn_cap;
1689 u32 mfp;
1690 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001691
Hante Meuleman240d61a2016-02-17 11:27:10 +01001692 if (!sme->crypto.n_akm_suites)
1693 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001694
Hante Meuleman240d61a2016-02-17 11:27:10 +01001695 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1696 if (err) {
1697 brcmf_err("could not get wpa_auth (%d)\n", err);
1698 return err;
1699 }
1700 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1701 switch (sme->crypto.akm_suites[0]) {
1702 case WLAN_AKM_SUITE_8021X:
1703 val = WPA_AUTH_UNSPECIFIED;
1704 break;
1705 case WLAN_AKM_SUITE_PSK:
1706 val = WPA_AUTH_PSK;
1707 break;
1708 default:
1709 brcmf_err("invalid cipher group (%d)\n",
1710 sme->crypto.cipher_group);
1711 return -EINVAL;
1712 }
1713 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1714 switch (sme->crypto.akm_suites[0]) {
1715 case WLAN_AKM_SUITE_8021X:
1716 val = WPA2_AUTH_UNSPECIFIED;
1717 break;
1718 case WLAN_AKM_SUITE_8021X_SHA256:
1719 val = WPA2_AUTH_1X_SHA256;
1720 break;
1721 case WLAN_AKM_SUITE_PSK_SHA256:
1722 val = WPA2_AUTH_PSK_SHA256;
1723 break;
1724 case WLAN_AKM_SUITE_PSK:
1725 val = WPA2_AUTH_PSK;
1726 break;
1727 default:
1728 brcmf_err("invalid cipher group (%d)\n",
1729 sme->crypto.cipher_group);
1730 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001731 }
1732 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001733
1734 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1735 goto skip_mfp_config;
1736 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1737 * IE will not be verified, just a quick search for MFP config
1738 */
1739 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1740 WLAN_EID_RSN);
1741 if (!rsn_ie)
1742 goto skip_mfp_config;
1743 ie = (const u8 *)rsn_ie;
1744 ie_len = rsn_ie->len + TLV_HDR_LEN;
1745 /* Skip unicast suite */
1746 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1747 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1748 goto skip_mfp_config;
1749 /* Skip multicast suite */
1750 count = ie[offset] + (ie[offset + 1] << 8);
1751 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1752 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1753 goto skip_mfp_config;
1754 /* Skip auth key management suite(s) */
1755 count = ie[offset] + (ie[offset + 1] << 8);
1756 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1757 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1758 goto skip_mfp_config;
1759 /* Ready to read capabilities */
1760 mfp = BRCMF_MFP_NONE;
1761 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1762 if (rsn_cap & RSN_CAP_MFPR_MASK)
1763 mfp = BRCMF_MFP_REQUIRED;
1764 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1765 mfp = BRCMF_MFP_CAPABLE;
1766 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1767
1768skip_mfp_config:
1769 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1770 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1771 if (err) {
1772 brcmf_err("could not set wpa_auth (%d)\n", err);
1773 return err;
1774 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001775
1776 return err;
1777}
1778
1779static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001780brcmf_set_sharedkey(struct net_device *ndev,
1781 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001782{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001783 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001784 struct brcmf_cfg80211_security *sec;
1785 struct brcmf_wsec_key key;
1786 s32 val;
1787 s32 err = 0;
1788
Arend van Spriel16886732012-12-05 15:26:04 +01001789 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001790
Roland Vossena718e2f2011-10-12 20:51:24 +02001791 if (sme->key_len == 0)
1792 return 0;
1793
Arend van Spriel06bb1232012-09-27 14:17:56 +02001794 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001795 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1796 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001797
1798 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1799 return 0;
1800
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001801 if (!(sec->cipher_pairwise &
1802 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1803 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001804
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001805 memset(&key, 0, sizeof(key));
1806 key.len = (u32) sme->key_len;
1807 key.index = (u32) sme->key_idx;
1808 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001809 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001810 return -EINVAL;
1811 }
1812 memcpy(key.data, sme->key, key.len);
1813 key.flags = BRCMF_PRIMARY_KEY;
1814 switch (sec->cipher_pairwise) {
1815 case WLAN_CIPHER_SUITE_WEP40:
1816 key.algo = CRYPTO_ALGO_WEP1;
1817 break;
1818 case WLAN_CIPHER_SUITE_WEP104:
1819 key.algo = CRYPTO_ALGO_WEP128;
1820 break;
1821 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001822 brcmf_err("Invalid algorithm (%d)\n",
1823 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001824 return -EINVAL;
1825 }
1826 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001827 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1828 key.len, key.index, key.algo);
1829 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001830 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001831 if (err)
1832 return err;
1833
1834 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001835 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001836 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001837 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001838 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001839 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 }
1841 return err;
1842}
1843
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001844static
1845enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1846 enum nl80211_auth_type type)
1847{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001848 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1849 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1850 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1851 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001852 }
1853 return type;
1854}
1855
Arend van Spriel7705ba62016-04-17 16:44:58 +02001856static void brcmf_set_join_pref(struct brcmf_if *ifp,
1857 struct cfg80211_bss_selection *bss_select)
1858{
1859 struct brcmf_join_pref_params join_pref_params[2];
1860 enum nl80211_band band;
1861 int err, i = 0;
1862
1863 join_pref_params[i].len = 2;
1864 join_pref_params[i].rssi_gain = 0;
1865
1866 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1867 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1868
1869 switch (bss_select->behaviour) {
1870 case __NL80211_BSS_SELECT_ATTR_INVALID:
1871 brcmf_c_set_joinpref_default(ifp);
1872 return;
1873 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1874 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1875 band = bss_select->param.band_pref;
1876 join_pref_params[i].band = nl80211_band_to_fwil(band);
1877 i++;
1878 break;
1879 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1880 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1881 band = bss_select->param.adjust.band;
1882 join_pref_params[i].band = nl80211_band_to_fwil(band);
1883 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1884 i++;
1885 break;
1886 case NL80211_BSS_SELECT_ATTR_RSSI:
1887 default:
1888 break;
1889 }
1890 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1891 join_pref_params[i].len = 2;
1892 join_pref_params[i].rssi_gain = 0;
1893 join_pref_params[i].band = 0;
1894 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1895 sizeof(join_pref_params));
1896 if (err)
1897 brcmf_err("Set join_pref error (%d)\n", err);
1898}
1899
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900static s32
1901brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001902 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001904 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001905 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001906 struct ieee80211_channel *chan = sme->channel;
1907 struct brcmf_join_params join_params;
1908 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001909 const struct brcmf_tlv *rsn_ie;
1910 const struct brcmf_vs_tlv *wpa_ie;
1911 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001912 u32 ie_len;
1913 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001914 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001915 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001916 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917
Arend van Sprield96b8012012-12-05 15:26:02 +01001918 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001919 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001920 return -EIO;
1921
1922 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001923 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001924 return -EOPNOTSUPP;
1925 }
1926
Hante Meuleman89286dc2013-02-08 15:53:46 +01001927 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1928 /* A normal (non P2P) connection request setup. */
1929 ie = NULL;
1930 ie_len = 0;
1931 /* find the WPA_IE */
1932 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1933 if (wpa_ie) {
1934 ie = wpa_ie;
1935 ie_len = wpa_ie->len + TLV_HDR_LEN;
1936 } else {
1937 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001938 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1939 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001940 WLAN_EID_RSN);
1941 if (rsn_ie) {
1942 ie = rsn_ie;
1943 ie_len = rsn_ie->len + TLV_HDR_LEN;
1944 }
1945 }
1946 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1947 }
1948
1949 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1950 sme->ie, sme->ie_len);
1951 if (err)
1952 brcmf_err("Set Assoc REQ IE Failed\n");
1953 else
1954 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1955
Arend van Sprielc1179032012-10-22 13:55:33 -07001956 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957
1958 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001959 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001960 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001961 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001962 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1963 cfg->channel, chan->center_freq, chanspec);
1964 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001965 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001966 chanspec = 0;
1967 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001969 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001970
1971 err = brcmf_set_wpa_version(ndev, sme);
1972 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001973 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001974 goto done;
1975 }
1976
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001977 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001978 err = brcmf_set_auth_type(ndev, sme);
1979 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001980 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981 goto done;
1982 }
1983
Hante Meuleman240d61a2016-02-17 11:27:10 +01001984 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001986 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001987 goto done;
1988 }
1989
1990 err = brcmf_set_key_mgmt(ndev, sme);
1991 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001992 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001993 goto done;
1994 }
1995
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001996 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001997 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001998 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999 goto done;
2000 }
2001
Hante Meuleman89286dc2013-02-08 15:53:46 +01002002 /* Join with specific BSSID and cached SSID
2003 * If SSID is zero join based on BSSID only
2004 */
2005 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
2006 offsetof(struct brcmf_assoc_params_le, chanspec_list);
2007 if (cfg->channel)
2008 join_params_size += sizeof(u16);
2009 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
2010 if (ext_join_params == NULL) {
2011 err = -ENOMEM;
2012 goto done;
2013 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002014 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
2015 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
2016 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
2017 if (ssid_len < IEEE80211_MAX_SSID_LEN)
2018 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
2019 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002020
Hante Meuleman89286dc2013-02-08 15:53:46 +01002021 /* Set up join scan parameters */
2022 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002023 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2024
2025 if (sme->bssid)
2026 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2027 else
Joe Perches93803b32015-03-02 19:54:49 -08002028 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002029
2030 if (cfg->channel) {
2031 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2032
2033 ext_join_params->assoc_le.chanspec_list[0] =
2034 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002035 /* Increase dwell time to receive probe response or detect
2036 * beacon from target AP at a noisy air only during connect
2037 * command.
2038 */
2039 ext_join_params->scan_le.active_time =
2040 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2041 ext_join_params->scan_le.passive_time =
2042 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2043 /* To sync with presence period of VSDB GO send probe request
2044 * more frequently. Probe request will be stopped when it gets
2045 * probe response from target AP/GO.
2046 */
2047 ext_join_params->scan_le.nprobes =
2048 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2049 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2050 } else {
2051 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2052 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2053 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002054 }
2055
Arend van Spriel7705ba62016-04-17 16:44:58 +02002056 brcmf_set_join_pref(ifp, &sme->bss_select);
2057
Hante Meuleman89286dc2013-02-08 15:53:46 +01002058 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2059 join_params_size);
2060 kfree(ext_join_params);
2061 if (!err)
2062 /* This is it. join command worked, we are done */
2063 goto done;
2064
2065 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066 memset(&join_params, 0, sizeof(join_params));
2067 join_params_size = sizeof(join_params.ssid_le);
2068
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002069 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2070 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002071
Hante Meuleman89286dc2013-02-08 15:53:46 +01002072 if (sme->bssid)
2073 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2074 else
Joe Perches93803b32015-03-02 19:54:49 -08002075 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002076
Hante Meuleman17012612013-02-06 18:40:44 +01002077 if (cfg->channel) {
2078 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2079 join_params.params_le.chanspec_num = cpu_to_le32(1);
2080 join_params_size += sizeof(join_params.params_le);
2081 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002082 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002083 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002084 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002085 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002086
2087done:
2088 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002089 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002090 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002091 return err;
2092}
2093
2094static s32
2095brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2096 u16 reason_code)
2097{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002098 struct brcmf_if *ifp = netdev_priv(ndev);
2099 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 struct brcmf_scb_val_le scbval;
2101 s32 err = 0;
2102
Arend van Sprield96b8012012-12-05 15:26:02 +01002103 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002104 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105 return -EIO;
2106
Arend van Sprielc1179032012-10-22 13:55:33 -07002107 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002108 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002109 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002110
Arend van Spriel06bb1232012-09-27 14:17:56 +02002111 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002113 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002114 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002116 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117
Arend van Sprield96b8012012-12-05 15:26:02 +01002118 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119 return err;
2120}
2121
2122static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002123brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002124 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002125{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002126 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002127 struct net_device *ndev = cfg_to_ndev(cfg);
2128 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002129 s32 err;
2130 s32 disable;
2131 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002133 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002134 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 return -EIO;
2136
2137 switch (type) {
2138 case NL80211_TX_POWER_AUTOMATIC:
2139 break;
2140 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002142 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002143 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 err = -EINVAL;
2145 goto done;
2146 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002147 qdbm = MBM_TO_DBM(4 * mbm);
2148 if (qdbm > 127)
2149 qdbm = 127;
2150 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002152 default:
2153 brcmf_err("Unsupported type %d\n", type);
2154 err = -EINVAL;
2155 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002156 }
2157 /* Make sure radio is off or on as far as software is concerned */
2158 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002159 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002161 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002163 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002165 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166
2167done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002168 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 return err;
2170}
2171
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002172static s32
2173brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2174 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002175{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002176 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002177 struct net_device *ndev = cfg_to_ndev(cfg);
2178 struct brcmf_if *ifp = netdev_priv(ndev);
2179 s32 qdbm = 0;
2180 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181
Arend van Sprield96b8012012-12-05 15:26:02 +01002182 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002183 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002184 return -EIO;
2185
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002186 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002187 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002188 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 goto done;
2190 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002191 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002192
2193done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002194 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 return err;
2196}
2197
2198static s32
2199brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002200 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002202 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002203 u32 index;
2204 u32 wsec;
2205 s32 err = 0;
2206
Arend van Sprield96b8012012-12-05 15:26:02 +01002207 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002208 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002209 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002210 return -EIO;
2211
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002212 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002213 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002214 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002215 goto done;
2216 }
2217
2218 if (wsec & WEP_ENABLED) {
2219 /* Just select a new current key */
2220 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002221 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002222 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002224 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002225 }
2226done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002227 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002228 return err;
2229}
2230
2231static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002232brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2233 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002234{
Hante Meuleman992f6062013-04-02 21:06:17 +02002235 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002236 struct brcmf_wsec_key *key;
2237 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002238
2239 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002240 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2241
Hante Meuleman219e0f72016-02-17 11:27:09 +01002242 if (!check_vif_up(ifp->vif))
2243 return -EIO;
2244
2245 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2246 /* we ignore this key index in this case */
2247 return -EINVAL;
2248 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002249
Hante Meuleman240d61a2016-02-17 11:27:10 +01002250 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251
Hante Meuleman240d61a2016-02-17 11:27:10 +01002252 if (key->algo == CRYPTO_ALGO_OFF) {
2253 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2254 return -EINVAL;
2255 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002256
Hante Meuleman240d61a2016-02-17 11:27:10 +01002257 memset(key, 0, sizeof(*key));
2258 key->index = (u32)key_idx;
2259 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Hante Meuleman240d61a2016-02-17 11:27:10 +01002261 /* Clear the key/index */
2262 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263
Hante Meuleman219e0f72016-02-17 11:27:09 +01002264 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 return err;
2266}
2267
2268static s32
2269brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002270 u8 key_idx, bool pairwise, const u8 *mac_addr,
2271 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002272{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002273 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002274 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275 s32 val;
2276 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002277 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002278 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002279 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002280
Arend van Sprield96b8012012-12-05 15:26:02 +01002281 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002282 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002283 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284 return -EIO;
2285
Hante Meuleman118eb302014-12-21 12:43:49 +01002286 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2287 /* we ignore this key index in this case */
2288 brcmf_err("invalid key index (%d)\n", key_idx);
2289 return -EINVAL;
2290 }
2291
Hante Meuleman219e0f72016-02-17 11:27:09 +01002292 if (params->key_len == 0)
2293 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2294 mac_addr);
2295
2296 if (params->key_len > sizeof(key->data)) {
2297 brcmf_err("Too long key length (%u)\n", params->key_len);
2298 return -EINVAL;
2299 }
2300
2301 ext_key = false;
2302 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2303 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2304 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2305 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307
Hante Meuleman118eb302014-12-21 12:43:49 +01002308 key = &ifp->vif->profile.key[key_idx];
2309 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002310 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2311 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002312 key->len = params->key_len;
2313 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002314 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002315 if (!ext_key)
2316 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002317
Arend van Spriel5b435de2011-10-05 13:19:03 +02002318 switch (params->cipher) {
2319 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002320 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002321 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002322 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 break;
2324 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002325 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002326 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002327 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002328 break;
2329 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002330 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002331 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002332 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2333 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2334 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002335 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002336 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002337 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002338 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339 break;
2340 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002341 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002342 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002343 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344 break;
2345 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002346 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002347 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002348 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002349 break;
2350 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002351 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352 err = -EINVAL;
2353 goto done;
2354 }
2355
Hante Meuleman118eb302014-12-21 12:43:49 +01002356 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002357 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002358 goto done;
2359
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002360 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002361 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002362 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 goto done;
2364 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002366 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002367 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002368 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 goto done;
2370 }
2371
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002373 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002374 return err;
2375}
2376
2377static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002378brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2379 bool pairwise, const u8 *mac_addr, void *cookie,
2380 void (*callback)(void *cookie,
2381 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382{
2383 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002384 struct brcmf_if *ifp = netdev_priv(ndev);
2385 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 struct brcmf_cfg80211_security *sec;
2387 s32 wsec;
2388 s32 err = 0;
2389
Arend van Sprield96b8012012-12-05 15:26:02 +01002390 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002391 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002392 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002393 return -EIO;
2394
2395 memset(&params, 0, sizeof(params));
2396
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002397 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002398 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002399 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400 /* Ignore this error, may happen during DISASSOC */
2401 err = -EAGAIN;
2402 goto done;
2403 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002404 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002405 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002406 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2407 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002408 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002409 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2410 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002411 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002412 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002413 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002414 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002415 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002416 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002417 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002418 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002419 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002420 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002421 err = -EINVAL;
2422 goto done;
2423 }
2424 callback(cookie, &params);
2425
2426done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002427 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 return err;
2429}
2430
2431static s32
2432brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002433 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002435 struct brcmf_if *ifp = netdev_priv(ndev);
2436
2437 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2438
2439 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2440 return 0;
2441
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002442 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002443
2444 return -EOPNOTSUPP;
2445}
2446
Hante Meuleman118eb302014-12-21 12:43:49 +01002447static void
2448brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2449{
2450 s32 err;
2451 u8 key_idx;
2452 struct brcmf_wsec_key *key;
2453 s32 wsec;
2454
2455 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2456 key = &ifp->vif->profile.key[key_idx];
2457 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2458 (key->algo == CRYPTO_ALGO_WEP128))
2459 break;
2460 }
2461 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2462 return;
2463
2464 err = send_key_to_dongle(ifp, key);
2465 if (err) {
2466 brcmf_err("Setting WEP key failed (%d)\n", err);
2467 return;
2468 }
2469 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2470 if (err) {
2471 brcmf_err("get wsec error (%d)\n", err);
2472 return;
2473 }
2474 wsec |= WEP_ENABLED;
2475 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2476 if (err)
2477 brcmf_err("set wsec error (%d)\n", err);
2478}
2479
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002480static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2481{
2482 struct nl80211_sta_flag_update *sfu;
2483
2484 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2485 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2486 sfu = &si->sta_flags;
2487 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2488 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2489 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2490 BIT(NL80211_STA_FLAG_AUTHORIZED);
2491 if (fw_sta_flags & BRCMF_STA_WME)
2492 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2493 if (fw_sta_flags & BRCMF_STA_AUTHE)
2494 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2495 if (fw_sta_flags & BRCMF_STA_ASSOC)
2496 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2497 if (fw_sta_flags & BRCMF_STA_AUTHO)
2498 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2499}
2500
2501static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2502{
2503 struct {
2504 __le32 len;
2505 struct brcmf_bss_info_le bss_le;
2506 } *buf;
2507 u16 capability;
2508 int err;
2509
2510 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2511 if (!buf)
2512 return;
2513
2514 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2515 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2516 WL_BSS_INFO_MAX);
2517 if (err) {
2518 brcmf_err("Failed to get bss info (%d)\n", err);
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002519 goto out_kfree;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002520 }
2521 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2522 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2523 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2524 capability = le16_to_cpu(buf->bss_le.capability);
2525 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2526 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2527 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2528 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2529 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2530 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
Rafał Miłecki23e9c122016-09-21 08:23:24 +02002531
2532out_kfree:
2533 kfree(buf);
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002534}
2535
Arend van Spriel5b435de2011-10-05 13:19:03 +02002536static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002537brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2538 struct station_info *sinfo)
2539{
2540 struct brcmf_scb_val_le scbval;
2541 struct brcmf_pktcnt_le pktcnt;
2542 s32 err;
2543 u32 rate;
2544 u32 rssi;
2545
2546 /* Get the current tx rate */
2547 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2548 if (err < 0) {
2549 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2550 return err;
2551 }
2552 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2553 sinfo->txrate.legacy = rate * 5;
2554
2555 memset(&scbval, 0, sizeof(scbval));
2556 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2557 sizeof(scbval));
2558 if (err) {
2559 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2560 return err;
2561 }
2562 rssi = le32_to_cpu(scbval.val);
2563 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2564 sinfo->signal = rssi;
2565
2566 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2567 sizeof(pktcnt));
2568 if (err) {
2569 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2570 return err;
2571 }
2572 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2573 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2574 BIT(NL80211_STA_INFO_TX_PACKETS) |
2575 BIT(NL80211_STA_INFO_TX_FAILED);
2576 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2577 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2578 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2579 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2580
2581 return 0;
2582}
2583
2584static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002585brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002586 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002587{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002588 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002589 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002590 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002591 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002592 u32 sta_flags;
2593 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002594 s32 total_rssi;
2595 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002596 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002597 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002598
Arend van Sprield96b8012012-12-05 15:26:02 +01002599 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002600 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002601 return -EIO;
2602
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002603 if (brcmf_is_ibssmode(ifp->vif))
2604 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2605
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002606 memset(&sta_info_le, 0, sizeof(sta_info_le));
2607 memcpy(&sta_info_le, mac, ETH_ALEN);
2608 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2609 &sta_info_le,
2610 sizeof(sta_info_le));
2611 is_tdls_peer = !err;
2612 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002613 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002614 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002615 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002616 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002617 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002618 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002619 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002620 }
2621 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2622 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2623 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2624 sta_flags = le32_to_cpu(sta_info_le.flags);
2625 brcmf_convert_sta_flags(sta_flags, sinfo);
2626 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2627 if (is_tdls_peer)
2628 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2629 else
2630 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2631 if (sta_flags & BRCMF_STA_ASSOC) {
2632 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2633 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2634 brcmf_fill_bss_param(ifp, sinfo);
2635 }
2636 if (sta_flags & BRCMF_STA_SCBSTATS) {
2637 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2638 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2639 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2640 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2641 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2642 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2643 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2644 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2645 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002646 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002647 sinfo->txrate.legacy =
2648 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002649 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002650 if (sinfo->rx_packets) {
2651 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002652 sinfo->rxrate.legacy =
2653 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002654 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002655 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2656 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2657 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2658 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2659 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2660 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002661 total_rssi = 0;
2662 count_rssi = 0;
2663 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2664 if (sta_info_le.rssi[i]) {
2665 sinfo->chain_signal_avg[count_rssi] =
2666 sta_info_le.rssi[i];
2667 sinfo->chain_signal[count_rssi] =
2668 sta_info_le.rssi[i];
2669 total_rssi += sta_info_le.rssi[i];
2670 count_rssi++;
2671 }
2672 }
2673 if (count_rssi) {
2674 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2675 sinfo->chains = count_rssi;
2676
2677 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2678 total_rssi /= count_rssi;
2679 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002680 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2681 &ifp->vif->sme_state)) {
2682 memset(&scb_val, 0, sizeof(scb_val));
2683 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2684 &scb_val, sizeof(scb_val));
2685 if (err) {
2686 brcmf_err("Could not get rssi (%d)\n", err);
2687 goto done;
2688 } else {
2689 rssi = le32_to_cpu(scb_val.val);
2690 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2691 sinfo->signal = rssi;
2692 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2693 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002694 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002695 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002696done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002697 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002698 return err;
2699}
2700
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002701static int
2702brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2703 int idx, u8 *mac, struct station_info *sinfo)
2704{
2705 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2706 struct brcmf_if *ifp = netdev_priv(ndev);
2707 s32 err;
2708
2709 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2710
2711 if (idx == 0) {
2712 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2713 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2714 &cfg->assoclist,
2715 sizeof(cfg->assoclist));
2716 if (err) {
2717 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2718 err);
2719 cfg->assoclist.count = 0;
2720 return -EOPNOTSUPP;
2721 }
2722 }
2723 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2724 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2725 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2726 }
2727 return -ENOENT;
2728}
2729
Arend van Spriel5b435de2011-10-05 13:19:03 +02002730static s32
2731brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2732 bool enabled, s32 timeout)
2733{
2734 s32 pm;
2735 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002736 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002737 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002738
Arend van Sprield96b8012012-12-05 15:26:02 +01002739 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002740
2741 /*
2742 * Powersave enable/disable request is coming from the
2743 * cfg80211 even before the interface is up. In that
2744 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002745 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002746 * FW later while initializing the dongle
2747 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002748 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002749 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002750
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002751 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002752 goto done;
2753 }
2754
2755 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002756 /* Do not enable the power save after assoc if it is a p2p interface */
2757 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2758 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2759 pm = PM_OFF;
2760 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002761 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002762
Arend van Sprielc1179032012-10-22 13:55:33 -07002763 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002764 if (err) {
2765 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002766 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002767 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002768 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002769 }
2770done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002771 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772 return err;
2773}
2774
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002775static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002776 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002777{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002778 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002779 struct ieee80211_channel *notify_channel;
2780 struct cfg80211_bss *bss;
2781 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002782 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002783 u16 channel;
2784 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002785 u16 notify_capability;
2786 u16 notify_interval;
2787 u8 *notify_ie;
2788 size_t notify_ielen;
2789 s32 notify_signal;
2790
2791 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002792 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002793 return 0;
2794 }
2795
Franky Lin83cf17a2013-04-11 13:28:50 +02002796 if (!bi->ctl_ch) {
2797 ch.chspec = le16_to_cpu(bi->chanspec);
2798 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002799 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002800 }
2801 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002802
2803 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002804 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002805 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002806 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807
2808 freq = ieee80211_channel_to_frequency(channel, band->band);
2809 notify_channel = ieee80211_get_channel(wiphy, freq);
2810
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811 notify_capability = le16_to_cpu(bi->capability);
2812 notify_interval = le16_to_cpu(bi->beacon_period);
2813 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2814 notify_ielen = le32_to_cpu(bi->ie_length);
2815 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2816
Arend van Spriel16886732012-12-05 15:26:04 +01002817 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2818 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2819 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2820 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2821 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002823 bss = cfg80211_inform_bss(wiphy, notify_channel,
2824 CFG80211_BSS_FTYPE_UNKNOWN,
2825 (const u8 *)bi->BSSID,
2826 0, notify_capability,
2827 notify_interval, notify_ie,
2828 notify_ielen, notify_signal,
2829 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830
Franky Line78946e2011-11-10 20:30:34 +01002831 if (!bss)
2832 return -ENOMEM;
2833
Johannes Berg5b112d32013-02-01 01:49:58 +01002834 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002835
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002836 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837}
2838
Roland Vossen6f09be02011-10-18 14:03:02 +02002839static struct brcmf_bss_info_le *
2840next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2841{
2842 if (bss == NULL)
2843 return list->bss_info_le;
2844 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2845 le32_to_cpu(bss->length));
2846}
2847
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002848static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002849{
2850 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002851 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002852 s32 err = 0;
2853 int i;
2854
Hante Meulemanef8596e2014-09-30 10:23:13 +02002855 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002856 if (bss_list->count != 0 &&
2857 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002858 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2859 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 return -EOPNOTSUPP;
2861 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002862 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002863 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002864 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002865 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002866 if (err)
2867 break;
2868 }
2869 return err;
2870}
2871
Hante Meulemanb0a79082015-12-10 13:43:07 +01002872static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2873 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002874{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002875 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002876 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002877 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002878 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002879 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002880 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 u8 *buf = NULL;
2882 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002883 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002884 u16 notify_capability;
2885 u16 notify_interval;
2886 u8 *notify_ie;
2887 size_t notify_ielen;
2888 s32 notify_signal;
2889
Arend van Sprield96b8012012-12-05 15:26:02 +01002890 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891
2892 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2893 if (buf == NULL) {
2894 err = -ENOMEM;
2895 goto CleanUp;
2896 }
2897
2898 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2899
Arend van Sprielac24be62012-10-22 10:36:23 -07002900 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2901 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002902 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002903 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002904 goto CleanUp;
2905 }
2906
Roland Vossend34bf642011-10-18 14:03:01 +02002907 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002908
Franky Lin83cf17a2013-04-11 13:28:50 +02002909 ch.chspec = le16_to_cpu(bi->chanspec);
2910 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002911
Franky Lin83cf17a2013-04-11 13:28:50 +02002912 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002913 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002914 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002915 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002916
Rafał Miłecki4712d882016-05-20 13:38:57 +02002917 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002918 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002919 notify_channel = ieee80211_get_channel(wiphy, freq);
2920
Arend van Spriel5b435de2011-10-05 13:19:03 +02002921 notify_capability = le16_to_cpu(bi->capability);
2922 notify_interval = le16_to_cpu(bi->beacon_period);
2923 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2924 notify_ielen = le32_to_cpu(bi->ie_length);
2925 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2926
Rafał Miłecki4712d882016-05-20 13:38:57 +02002927 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002928 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2929 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2930 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002931
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002932 bss = cfg80211_inform_bss(wiphy, notify_channel,
2933 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2934 notify_capability, notify_interval,
2935 notify_ie, notify_ielen, notify_signal,
2936 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002937
Franky Line78946e2011-11-10 20:30:34 +01002938 if (!bss) {
2939 err = -ENOMEM;
2940 goto CleanUp;
2941 }
2942
Johannes Berg5b112d32013-02-01 01:49:58 +01002943 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002944
Arend van Spriel5b435de2011-10-05 13:19:03 +02002945CleanUp:
2946
2947 kfree(buf);
2948
Arend van Sprield96b8012012-12-05 15:26:02 +01002949 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002950
2951 return err;
2952}
2953
Hante Meuleman89286dc2013-02-08 15:53:46 +01002954static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2955 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002956{
Roland Vossend34bf642011-10-18 14:03:01 +02002957 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002958 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002959 u16 beacon_interval;
2960 u8 dtim_period;
2961 size_t ie_len;
2962 u8 *ie;
2963 s32 err = 0;
2964
Arend van Sprield96b8012012-12-05 15:26:02 +01002965 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002966 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002967 return err;
2968
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002969 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002970 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002971 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002972 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002973 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974 goto update_bss_info_out;
2975 }
2976
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002977 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2978 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002979 if (err)
2980 goto update_bss_info_out;
2981
2982 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2983 ie_len = le32_to_cpu(bi->ie_length);
2984 beacon_interval = le16_to_cpu(bi->beacon_period);
2985
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002986 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002987 if (tim)
2988 dtim_period = tim->data[1];
2989 else {
2990 /*
2991 * active scan was done so we could not get dtim
2992 * information out of probe response.
2993 * so we speficially query dtim information to dongle.
2994 */
2995 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002996 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002998 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002999 goto update_bss_info_out;
3000 }
3001 dtim_period = (u8)var;
3002 }
3003
Arend van Spriel5b435de2011-10-05 13:19:03 +02003004update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01003005 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003006 return err;
3007}
3008
Hante Meuleman18e2f612013-02-08 15:53:49 +01003009void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003010{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003011 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003012
Arend van Sprielc1179032012-10-22 13:55:33 -07003013 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003014 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02003015 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02003016 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02003017 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003018 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3019 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003020}
3021
Hante Meulemane756af52012-09-11 21:18:52 +02003022static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3023{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003024 struct brcmf_cfg80211_info *cfg =
3025 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003026 escan_timeout_work);
3027
Hante Meulemanef8596e2014-09-30 10:23:13 +02003028 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003029 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003030}
3031
3032static void brcmf_escan_timeout(unsigned long data)
3033{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003034 struct brcmf_cfg80211_info *cfg =
3035 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003036
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003037 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003038 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003039 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003040 }
3041}
3042
3043static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003044brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3045 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003046 struct brcmf_bss_info_le *bss_info_le)
3047{
Franky Lin83cf17a2013-04-11 13:28:50 +02003048 struct brcmu_chan ch_bss, ch_bss_info_le;
3049
3050 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3051 cfg->d11inf.decchspec(&ch_bss);
3052 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3053 cfg->d11inf.decchspec(&ch_bss_info_le);
3054
Hante Meulemane756af52012-09-11 21:18:52 +02003055 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003056 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003057 bss_info_le->SSID_len == bss->SSID_len &&
3058 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003059 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3060 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003061 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3062 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3063
Hante Meulemane756af52012-09-11 21:18:52 +02003064 /* preserve max RSSI if the measurements are
3065 * both on-channel or both off-channel
3066 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003067 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003068 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003069 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3070 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003071 /* preserve the on-channel rssi measurement
3072 * if the new measurement is off channel
3073 */
3074 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003075 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003076 }
3077 return 1;
3078 }
3079 return 0;
3080}
3081
3082static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003083brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003084 const struct brcmf_event_msg *e, void *data)
3085{
Arend van Spriel19937322012-11-05 16:22:32 -08003086 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003087 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003088 struct brcmf_escan_result_le *escan_result_le;
3089 struct brcmf_bss_info_le *bss_info_le;
3090 struct brcmf_bss_info_le *bss = NULL;
3091 u32 bi_length;
3092 struct brcmf_scan_results *list;
3093 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003094 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003095
Arend van Spriel5c36b992012-11-14 18:46:05 -08003096 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003097
Arend van Spriela0f472a2013-04-05 10:57:49 +02003098 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003099 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003100 return -EPERM;
3101 }
3102
3103 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003104 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003105 escan_result_le = (struct brcmf_escan_result_le *) data;
3106 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003107 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003108 goto exit;
3109 }
Hante Meulemane756af52012-09-11 21:18:52 +02003110 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003111 brcmf_err("Invalid bss_count %d: ignoring\n",
3112 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003113 goto exit;
3114 }
3115 bss_info_le = &escan_result_le->bss_info_le;
3116
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003117 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3118 goto exit;
3119
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003120 if (!cfg->internal_escan && !cfg->scan_request) {
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003121 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3122 goto exit;
3123 }
3124
Hante Meulemane756af52012-09-11 21:18:52 +02003125 bi_length = le32_to_cpu(bss_info_le->length);
3126 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3127 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003128 brcmf_err("Invalid bss_info length %d: ignoring\n",
3129 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003130 goto exit;
3131 }
3132
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003133 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003134 BIT(NL80211_IFTYPE_ADHOC))) {
3135 if (le16_to_cpu(bss_info_le->capability) &
3136 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003137 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003138 goto exit;
3139 }
3140 }
3141
3142 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003143 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003144 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003145 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003146 goto exit;
3147 }
3148
3149 for (i = 0; i < list->count; i++) {
3150 bss = bss ? (struct brcmf_bss_info_le *)
3151 ((unsigned char *)bss +
3152 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003153 if (brcmf_compare_update_same_bss(cfg, bss,
3154 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003155 goto exit;
3156 }
Hante Meulemand5367332016-02-17 11:26:51 +01003157 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3158 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003159 list->version = le32_to_cpu(bss_info_le->version);
3160 list->buflen += bi_length;
3161 list->count++;
3162 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003163 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003164 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3165 goto exit;
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003166 if (cfg->internal_escan || cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003167 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003168 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003169 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003170 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003171 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3172 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003173 }
3174exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003175 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003176}
3177
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003178static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003179{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003180 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3181 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003182 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3183 /* Init scan_timeout timer */
3184 init_timer(&cfg->escan_timeout);
3185 cfg->escan_timeout.data = (unsigned long) cfg;
3186 cfg->escan_timeout.function = brcmf_escan_timeout;
3187 INIT_WORK(&cfg->escan_timeout_work,
3188 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003189}
3190
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003191static struct cfg80211_scan_request *
3192brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
3193 struct cfg80211_scan_request *req;
3194 size_t req_size;
3195
3196 req_size = sizeof(*req) +
3197 n_netinfo * sizeof(req->channels[0]) +
3198 n_netinfo * sizeof(*req->ssids);
3199
3200 req = kzalloc(req_size, GFP_KERNEL);
3201 if (req) {
3202 req->wiphy = wiphy;
3203 req->ssids = (void *)(&req->channels[0]) +
3204 n_netinfo * sizeof(req->channels[0]);
3205 }
3206 return req;
3207}
3208
3209static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3210 u8 *ssid, u8 ssid_len, u8 channel)
3211{
3212 struct ieee80211_channel *chan;
3213 enum nl80211_band band;
3214 int freq;
3215
3216 if (channel <= CH_MAX_2G_CHANNEL)
3217 band = NL80211_BAND_2GHZ;
3218 else
3219 band = NL80211_BAND_5GHZ;
3220
3221 freq = ieee80211_channel_to_frequency(channel, band);
3222 if (!freq)
3223 return -EINVAL;
3224
3225 chan = ieee80211_get_channel(req->wiphy, freq);
3226 if (!chan)
3227 return -EINVAL;
3228
3229 req->channels[req->n_channels++] = chan;
3230 memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
3231 req->ssids[req->n_ssids++].ssid_len = ssid_len;
3232
3233 return 0;
3234}
3235
3236static int brcmf_start_internal_escan(struct brcmf_if *ifp,
3237 struct cfg80211_scan_request *request)
3238{
3239 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3240 int err;
3241
3242 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3243 /* Abort any on-going scan */
3244 brcmf_abort_scanning(cfg);
3245 }
3246
3247 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3248 cfg->escan_info.run = brcmf_run_escan;
3249 err = brcmf_do_escan(ifp, request);
3250 if (err) {
3251 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3252 return err;
3253 }
3254 cfg->internal_escan = true;
3255 return 0;
3256}
3257
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003258static struct brcmf_pno_net_info_le *
3259brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
3260{
3261 struct brcmf_pno_scanresults_v2_le *pfn_v2;
3262 struct brcmf_pno_net_info_le *netinfo;
3263
3264 switch (pfn_v1->version) {
3265 default:
3266 WARN_ON(1);
3267 /* fall-thru */
3268 case cpu_to_le32(1):
3269 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
3270 break;
3271 case cpu_to_le32(2):
3272 pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
3273 netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
3274 break;
3275 }
3276
3277 return netinfo;
3278}
3279
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003280/* PFN result doesn't have all the info which are required by the supplicant
3281 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3282 * via wl_inform_single_bss in the required format. Escan does require the
3283 * scan request in the form of cfg80211_scan_request. For timebeing, create
3284 * cfg80211_scan_request one out of the received PNO event.
3285 */
3286static s32
3287brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3288 const struct brcmf_event_msg *e, void *data)
3289{
3290 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3291 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3292 struct cfg80211_scan_request *request = NULL;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003293 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003294 int i, err = 0;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003295 struct brcmf_pno_scanresults_le *pfn_result;
3296 u32 result_count;
3297 u32 status;
3298
3299 brcmf_dbg(SCAN, "Enter\n");
3300
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003301 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3302 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3303 return 0;
3304 }
3305
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003306 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3307 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3308 return 0;
3309 }
3310
3311 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3312 result_count = le32_to_cpu(pfn_result->count);
3313 status = le32_to_cpu(pfn_result->status);
3314
3315 /* PFN event is limited to fit 512 bytes so we may get
3316 * multiple NET_FOUND events. For now place a warning here.
3317 */
3318 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3319 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003320 if (!result_count) {
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003321 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3322 goto out_err;
3323 }
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003324 request = brcmf_alloc_internal_escan_request(wiphy,
3325 result_count);
3326 if (!request) {
3327 err = -ENOMEM;
3328 goto out_err;
3329 }
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003330
Arend Van Spriel53e3a802016-11-23 10:25:31 +00003331 netinfo_start = brcmf_get_netinfo_array(pfn_result);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003332
3333 for (i = 0; i < result_count; i++) {
3334 netinfo = &netinfo_start[i];
3335 if (!netinfo) {
3336 brcmf_err("Invalid netinfo ptr. index: %d\n",
3337 i);
3338 err = -EINVAL;
3339 goto out_err;
3340 }
3341
3342 brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
3343 netinfo->SSID, netinfo->channel);
3344 err = brcmf_internal_escan_add_info(request,
3345 netinfo->SSID,
3346 netinfo->SSID_len,
3347 netinfo->channel);
3348 if (err)
3349 goto out_err;
3350 }
3351
3352 err = brcmf_start_internal_escan(ifp, request);
3353 if (!err)
3354 goto free_req;
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003355
3356out_err:
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003357 cfg80211_sched_scan_stopped(wiphy);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003358free_req:
3359 kfree(request);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003360 return err;
3361}
3362
3363static int
3364brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3365 struct net_device *ndev,
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003366 struct cfg80211_sched_scan_request *req)
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003367{
3368 struct brcmf_if *ifp = netdev_priv(ndev);
3369 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003370
3371 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003372 req->n_match_sets, req->n_ssids);
Arend Van Sprieldfe5b0d2016-11-23 10:25:29 +00003373
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003374 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3375 brcmf_err("Scanning suppressed: status (%lu)\n",
3376 cfg->scan_status);
3377 return -EAGAIN;
3378 }
3379
Arend Van Spriel3e2e86a2016-11-23 10:25:23 +00003380 if (req->n_match_sets <= 0) {
3381 brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
3382 req->n_match_sets);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003383 return -EINVAL;
3384 }
3385
Arend Van Spriel3e486112016-11-23 10:25:27 +00003386 return brcmf_pno_start_sched_scan(ifp, req);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003387}
3388
3389static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3390 struct net_device *ndev)
3391{
3392 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Sprielac551362016-11-23 10:25:22 +00003393 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003394
3395 brcmf_dbg(SCAN, "enter\n");
Arend Van Sprielac551362016-11-23 10:25:22 +00003396 brcmf_pno_clean(ifp);
Arend Van Sprielfa85b302016-11-23 10:25:25 +00003397 if (cfg->internal_escan)
Arend Van Sprielac551362016-11-23 10:25:22 +00003398 brcmf_notify_escan_complete(cfg, ifp, true, true);
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003399 return 0;
3400}
3401
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003402static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003403{
3404 if (ms < 1000 / HZ) {
3405 cond_resched();
3406 mdelay(ms);
3407 } else {
3408 msleep(ms);
3409 }
3410}
3411
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003412static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3413 u8 *pattern, u32 patternsize, u8 *mask,
3414 u32 packet_offset)
3415{
3416 struct brcmf_fil_wowl_pattern_le *filter;
3417 u32 masksize;
3418 u32 patternoffset;
3419 u8 *buf;
3420 u32 bufsize;
3421 s32 ret;
3422
3423 masksize = (patternsize + 7) / 8;
3424 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3425
3426 bufsize = sizeof(*filter) + patternsize + masksize;
3427 buf = kzalloc(bufsize, GFP_KERNEL);
3428 if (!buf)
3429 return -ENOMEM;
3430 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3431
3432 memcpy(filter->cmd, cmd, 4);
3433 filter->masksize = cpu_to_le32(masksize);
3434 filter->offset = cpu_to_le32(packet_offset);
3435 filter->patternoffset = cpu_to_le32(patternoffset);
3436 filter->patternsize = cpu_to_le32(patternsize);
3437 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3438
3439 if ((mask) && (masksize))
3440 memcpy(buf + sizeof(*filter), mask, masksize);
3441 if ((pattern) && (patternsize))
3442 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3443
3444 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3445
3446 kfree(buf);
3447 return ret;
3448}
3449
Hante Meuleman3021ad92016-01-05 11:05:45 +01003450static s32
3451brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3452 void *data)
3453{
3454 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3455 struct brcmf_pno_scanresults_le *pfn_result;
3456 struct brcmf_pno_net_info_le *netinfo;
3457
3458 brcmf_dbg(SCAN, "Enter\n");
3459
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003460 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3461 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3462 return 0;
3463 }
3464
Hante Meuleman3021ad92016-01-05 11:05:45 +01003465 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3466
3467 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3468 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3469 return 0;
3470 }
3471
3472 if (le32_to_cpu(pfn_result->count) < 1) {
3473 brcmf_err("Invalid result count, expected 1 (%d)\n",
3474 le32_to_cpu(pfn_result->count));
3475 return -EINVAL;
3476 }
3477
Arend Van Sprield29afe92017-01-27 12:27:46 +00003478 netinfo = brcmf_get_netinfo_array(pfn_result);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003479 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3480 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3481 cfg->wowl.nd->n_channels = 1;
3482 cfg->wowl.nd->channels[0] =
3483 ieee80211_channel_to_frequency(netinfo->channel,
3484 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3485 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3486 cfg->wowl.nd_info->n_matches = 1;
3487 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3488
3489 /* Inform (the resume task) that the net detect information was recvd */
3490 cfg->wowl.nd_data_completed = true;
3491 wake_up(&cfg->wowl.nd_data_wait);
3492
3493 return 0;
3494}
3495
Hante Meulemanaeb64222015-10-29 20:33:19 +01003496#ifdef CONFIG_PM
3497
3498static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3499{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003500 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003501 struct brcmf_wowl_wakeind_le wake_ind_le;
3502 struct cfg80211_wowlan_wakeup wakeup_data;
3503 struct cfg80211_wowlan_wakeup *wakeup;
3504 u32 wakeind;
3505 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003506 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003507
3508 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3509 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003510 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003511 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3512 return;
3513 }
3514
3515 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3516 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003517 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3518 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003519 wakeup = &wakeup_data;
3520 memset(&wakeup_data, 0, sizeof(wakeup_data));
3521 wakeup_data.pattern_idx = -1;
3522
3523 if (wakeind & BRCMF_WOWL_MAGIC) {
3524 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3525 wakeup_data.magic_pkt = true;
3526 }
3527 if (wakeind & BRCMF_WOWL_DIS) {
3528 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3529 wakeup_data.disconnect = true;
3530 }
3531 if (wakeind & BRCMF_WOWL_BCN) {
3532 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3533 wakeup_data.disconnect = true;
3534 }
3535 if (wakeind & BRCMF_WOWL_RETR) {
3536 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3537 wakeup_data.disconnect = true;
3538 }
3539 if (wakeind & BRCMF_WOWL_NET) {
3540 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3541 /* For now always map to pattern 0, no API to get
3542 * correct information available at the moment.
3543 */
3544 wakeup_data.pattern_idx = 0;
3545 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003546 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3547 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3548 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3549 cfg->wowl.nd_data_completed,
3550 BRCMF_ND_INFO_TIMEOUT);
3551 if (!timeout)
3552 brcmf_err("No result for wowl net detect\n");
3553 else
3554 wakeup_data.net_detect = cfg->wowl.nd_info;
3555 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003556 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3557 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3558 wakeup_data.gtk_rekey_failure = true;
3559 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003560 } else {
3561 wakeup = NULL;
3562 }
3563 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3564}
3565
3566#else
3567
3568static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3569{
3570}
3571
3572#endif /* CONFIG_PM */
3573
Arend van Spriel5b435de2011-10-05 13:19:03 +02003574static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3575{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003576 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3577 struct net_device *ndev = cfg_to_ndev(cfg);
3578 struct brcmf_if *ifp = netdev_priv(ndev);
3579
Arend van Sprield96b8012012-12-05 15:26:02 +01003580 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003581
Hante Meuleman3021ad92016-01-05 11:05:45 +01003582 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003583 brcmf_report_wowl_wakeind(wiphy, ifp);
3584 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3585 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003586 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3587 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003588 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003589 cfg->wowl.pre_pmmode);
3590 cfg->wowl.active = false;
3591 if (cfg->wowl.nd_enabled) {
3592 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3593 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3594 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3595 brcmf_notify_sched_scan_results);
3596 cfg->wowl.nd_enabled = false;
3597 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003598 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003599 return 0;
3600}
3601
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003602static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3603 struct brcmf_if *ifp,
3604 struct cfg80211_wowlan *wowl)
3605{
3606 u32 wowl_config;
Hante Meulemana7ed7822016-09-19 12:09:58 +01003607 struct brcmf_wowl_wakeind_le wowl_wakeind;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003608 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003609
3610 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3611
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003612 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3613 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003614 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003615 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3616
3617 wowl_config = 0;
3618 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003619 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003620 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003621 wowl_config |= BRCMF_WOWL_MAGIC;
3622 if ((wowl->patterns) && (wowl->n_patterns)) {
3623 wowl_config |= BRCMF_WOWL_NET;
3624 for (i = 0; i < wowl->n_patterns; i++) {
3625 brcmf_config_wowl_pattern(ifp, "add",
3626 (u8 *)wowl->patterns[i].pattern,
3627 wowl->patterns[i].pattern_len,
3628 (u8 *)wowl->patterns[i].mask,
3629 wowl->patterns[i].pkt_offset);
3630 }
3631 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003632 if (wowl->nd_config) {
3633 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3634 wowl->nd_config);
3635 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3636
3637 cfg->wowl.nd_data_completed = false;
3638 cfg->wowl.nd_enabled = true;
3639 /* Now reroute the event for PFN to the wowl function. */
3640 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3641 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3642 brcmf_wowl_nd_results);
3643 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003644 if (wowl->gtk_rekey_failure)
3645 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003646 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3647 wowl_config |= BRCMF_WOWL_UNASSOC;
3648
Hante Meulemana7ed7822016-09-19 12:09:58 +01003649 memcpy(&wowl_wakeind, "clear", 6);
3650 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
3651 sizeof(wowl_wakeind));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003652 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3653 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3654 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003655 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003656}
3657
Arend van Spriel5b435de2011-10-05 13:19:03 +02003658static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003659 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003660{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003661 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3662 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003663 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003664 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003665
Arend van Sprield96b8012012-12-05 15:26:02 +01003666 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003667
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003668 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003669 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003670 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003671 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003672 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003673
Hante Meuleman3021ad92016-01-05 11:05:45 +01003674 /* Stop scheduled scan */
3675 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3676 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3677
Arend van Spriel7d641072012-10-22 13:55:39 -07003678 /* end any scanning */
3679 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003680 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003681
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003682 if (wowl == NULL) {
3683 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3684 list_for_each_entry(vif, &cfg->vif_list, list) {
3685 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3686 continue;
3687 /* While going to suspend if associated with AP
3688 * disassociate from AP to save power while system is
3689 * in suspended state
3690 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003691 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003692 /* Make sure WPA_Supplicant receives all the event
3693 * generated due to DISASSOC call to the fw to keep
3694 * the state fw and WPA_Supplicant state consistent
3695 */
3696 brcmf_delay(500);
3697 }
3698 /* Configure MPC */
3699 brcmf_set_mpc(ifp, 1);
3700
3701 } else {
3702 /* Configure WOWL paramaters */
3703 brcmf_configure_wowl(cfg, ifp, wowl);
3704 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003705
Arend van Spriel7d641072012-10-22 13:55:39 -07003706exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003707 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003708 /* clear any scanning activity */
3709 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003710 return 0;
3711}
3712
3713static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003714brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003715{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003716 struct brcmf_pmk_list_le *pmk_list;
3717 int i;
3718 u32 npmk;
3719 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003720
Hante Meuleman6c404f32015-12-10 13:43:03 +01003721 pmk_list = &cfg->pmk_list;
3722 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003723
Hante Meuleman6c404f32015-12-10 13:43:03 +01003724 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3725 for (i = 0; i < npmk; i++)
3726 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003727
Hante Meuleman6c404f32015-12-10 13:43:03 +01003728 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3729 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003730
3731 return err;
3732}
3733
3734static s32
3735brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3736 struct cfg80211_pmksa *pmksa)
3737{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003738 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003739 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003740 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3741 s32 err;
3742 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003743
Arend van Sprield96b8012012-12-05 15:26:02 +01003744 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003745 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003746 return -EIO;
3747
Hante Meuleman6c404f32015-12-10 13:43:03 +01003748 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3749 for (i = 0; i < npmk; i++)
3750 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003751 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003752 if (i < BRCMF_MAXPMKID) {
3753 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3754 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3755 if (i == npmk) {
3756 npmk++;
3757 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003758 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003759 } else {
3760 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3761 return -EINVAL;
3762 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003763
Hante Meuleman6c404f32015-12-10 13:43:03 +01003764 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3765 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3766 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3767 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3768 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769
Hante Meuleman6c404f32015-12-10 13:43:03 +01003770 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003771
Arend van Sprield96b8012012-12-05 15:26:02 +01003772 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003773 return err;
3774}
3775
3776static s32
3777brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003778 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003779{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003780 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003781 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003782 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3783 s32 err;
3784 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003785
Arend van Sprield96b8012012-12-05 15:26:02 +01003786 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003787 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003788 return -EIO;
3789
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003790 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003791
Hante Meuleman6c404f32015-12-10 13:43:03 +01003792 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3793 for (i = 0; i < npmk; i++)
Nicolas Iooss7703773ef2016-08-23 11:37:17 +02003794 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003795 break;
3796
Hante Meuleman6c404f32015-12-10 13:43:03 +01003797 if ((npmk > 0) && (i < npmk)) {
3798 for (; i < (npmk - 1); i++) {
3799 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3800 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003801 WLAN_PMKID_LEN);
3802 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003803 memset(&pmk[i], 0, sizeof(*pmk));
3804 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3805 } else {
3806 brcmf_err("Cache entry not found\n");
3807 return -EINVAL;
3808 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003809
Hante Meuleman6c404f32015-12-10 13:43:03 +01003810 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003811
Arend van Sprield96b8012012-12-05 15:26:02 +01003812 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003813 return err;
3814
3815}
3816
3817static s32
3818brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3819{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003820 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003821 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003822 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003823
Arend van Sprield96b8012012-12-05 15:26:02 +01003824 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003825 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003826 return -EIO;
3827
Hante Meuleman6c404f32015-12-10 13:43:03 +01003828 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3829 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003830
Arend van Sprield96b8012012-12-05 15:26:02 +01003831 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003832 return err;
3833
3834}
3835
Hante Meuleman1f170112013-02-06 18:40:38 +01003836static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003837{
3838 s32 err;
3839
3840 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003841 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003842 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003843 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003844 return err;
3845 }
3846 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003847 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003848 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003849 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003850 return err;
3851 }
3852 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003853 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003854 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003855 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003856 return err;
3857 }
3858
3859 return 0;
3860}
3861
3862static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3863{
3864 if (is_rsn_ie)
3865 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3866
3867 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3868}
3869
3870static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003871brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003872 const struct brcmf_vs_tlv *wpa_ie,
3873 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003874{
3875 u32 auth = 0; /* d11 open authentication */
3876 u16 count;
3877 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003878 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003879 u32 i;
3880 u32 wsec;
3881 u32 pval = 0;
3882 u32 gval = 0;
3883 u32 wpa_auth = 0;
3884 u32 offset;
3885 u8 *data;
3886 u16 rsn_cap;
3887 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003888 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003889
Arend van Sprield96b8012012-12-05 15:26:02 +01003890 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003891 if (wpa_ie == NULL)
3892 goto exit;
3893
3894 len = wpa_ie->len + TLV_HDR_LEN;
3895 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003896 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003897 if (!is_rsn_ie)
3898 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003899 else
3900 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003901
3902 /* check for multicast cipher suite */
3903 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3904 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003905 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003906 goto exit;
3907 }
3908
3909 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3910 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003911 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003912 goto exit;
3913 }
3914 offset += TLV_OUI_LEN;
3915
3916 /* pick up multicast cipher */
3917 switch (data[offset]) {
3918 case WPA_CIPHER_NONE:
3919 gval = 0;
3920 break;
3921 case WPA_CIPHER_WEP_40:
3922 case WPA_CIPHER_WEP_104:
3923 gval = WEP_ENABLED;
3924 break;
3925 case WPA_CIPHER_TKIP:
3926 gval = TKIP_ENABLED;
3927 break;
3928 case WPA_CIPHER_AES_CCM:
3929 gval = AES_ENABLED;
3930 break;
3931 default:
3932 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003933 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003934 goto exit;
3935 }
3936
3937 offset++;
3938 /* walk thru unicast cipher list and pick up what we recognize */
3939 count = data[offset] + (data[offset + 1] << 8);
3940 offset += WPA_IE_SUITE_COUNT_LEN;
3941 /* Check for unicast suite(s) */
3942 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3943 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003944 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003945 goto exit;
3946 }
3947 for (i = 0; i < count; i++) {
3948 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3949 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003950 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003951 goto exit;
3952 }
3953 offset += TLV_OUI_LEN;
3954 switch (data[offset]) {
3955 case WPA_CIPHER_NONE:
3956 break;
3957 case WPA_CIPHER_WEP_40:
3958 case WPA_CIPHER_WEP_104:
3959 pval |= WEP_ENABLED;
3960 break;
3961 case WPA_CIPHER_TKIP:
3962 pval |= TKIP_ENABLED;
3963 break;
3964 case WPA_CIPHER_AES_CCM:
3965 pval |= AES_ENABLED;
3966 break;
3967 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00003968 brcmf_err("Invalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003969 }
3970 offset++;
3971 }
3972 /* walk thru auth management suite list and pick up what we recognize */
3973 count = data[offset] + (data[offset + 1] << 8);
3974 offset += WPA_IE_SUITE_COUNT_LEN;
3975 /* Check for auth key management suite(s) */
3976 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3977 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003978 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003979 goto exit;
3980 }
3981 for (i = 0; i < count; i++) {
3982 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3983 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003984 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003985 goto exit;
3986 }
3987 offset += TLV_OUI_LEN;
3988 switch (data[offset]) {
3989 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003990 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003991 wpa_auth |= WPA_AUTH_NONE;
3992 break;
3993 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003994 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003995 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3996 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3997 break;
3998 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003999 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004000 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4001 (wpa_auth |= WPA_AUTH_PSK);
4002 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004003 case RSN_AKM_SHA256_PSK:
4004 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4005 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4006 break;
4007 case RSN_AKM_SHA256_1X:
4008 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4009 wpa_auth |= WPA2_AUTH_1X_SHA256;
4010 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004011 default:
Colin Ian Kingad334bb2016-12-23 00:43:22 +00004012 brcmf_err("Invalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004013 }
4014 offset++;
4015 }
4016
Hante Meuleman240d61a2016-02-17 11:27:10 +01004017 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004018 if (is_rsn_ie) {
4019 wme_bss_disable = 1;
4020 if ((offset + RSN_CAP_LEN) <= len) {
4021 rsn_cap = data[offset] + (data[offset + 1] << 8);
4022 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4023 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004024 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4025 brcmf_dbg(TRACE, "MFP Required\n");
4026 mfp = BRCMF_MFP_REQUIRED;
4027 /* Firmware only supports mfp required in
4028 * combination with WPA2_AUTH_PSK_SHA256 or
4029 * WPA2_AUTH_1X_SHA256.
4030 */
4031 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4032 WPA2_AUTH_1X_SHA256))) {
4033 err = -EINVAL;
4034 goto exit;
4035 }
4036 /* Firmware has requirement that WPA2_AUTH_PSK/
4037 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4038 * is to be included in the rsn ie.
4039 */
4040 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4041 wpa_auth |= WPA2_AUTH_PSK;
4042 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4043 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4044 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4045 brcmf_dbg(TRACE, "MFP Capable\n");
4046 mfp = BRCMF_MFP_CAPABLE;
4047 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004048 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004049 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004050 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004051 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004052 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004053 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004054 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004055 goto exit;
4056 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004057
4058 /* Skip PMKID cnt as it is know to be 0 for AP. */
4059 offset += RSN_PMKID_COUNT_LEN;
4060
4061 /* See if there is BIP wpa suite left for MFP */
4062 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4063 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4064 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4065 &data[offset],
4066 WPA_IE_MIN_OUI_LEN);
4067 if (err < 0) {
4068 brcmf_err("bip error %d\n", err);
4069 goto exit;
4070 }
4071 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004072 }
4073 /* FOR WPS , set SES_OW_ENABLED */
4074 wsec = (pval | gval | SES_OW_ENABLED);
4075
4076 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004077 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004078 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004079 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004080 goto exit;
4081 }
4082 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004083 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004084 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004085 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004086 goto exit;
4087 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004088 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4089 * will overwrite the values set by MFP
4090 */
4091 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4092 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4093 if (err < 0) {
4094 brcmf_err("mfp error %d\n", err);
4095 goto exit;
4096 }
4097 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004098 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004099 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004100 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004101 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004102 goto exit;
4103 }
4104
4105exit:
4106 return err;
4107}
4108
4109static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004110brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004111 struct parsed_vndr_ies *vndr_ies)
4112{
Hante Meuleman1a873342012-09-27 14:17:54 +02004113 struct brcmf_vs_tlv *vndrie;
4114 struct brcmf_tlv *ie;
4115 struct parsed_vndr_ie_info *parsed_info;
4116 s32 remaining_len;
4117
4118 remaining_len = (s32)vndr_ie_len;
4119 memset(vndr_ies, 0, sizeof(*vndr_ies));
4120
4121 ie = (struct brcmf_tlv *)vndr_ie_buf;
4122 while (ie) {
4123 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4124 goto next;
4125 vndrie = (struct brcmf_vs_tlv *)ie;
4126 /* len should be bigger than OUI length + one */
4127 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004128 brcmf_err("invalid vndr ie. length is too small %d\n",
4129 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004130 goto next;
4131 }
4132 /* if wpa or wme ie, do not add ie */
4133 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4134 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4135 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004136 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004137 goto next;
4138 }
4139
4140 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4141
4142 /* save vndr ie information */
4143 parsed_info->ie_ptr = (char *)vndrie;
4144 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4145 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4146
4147 vndr_ies->count++;
4148
Arend van Sprield96b8012012-12-05 15:26:02 +01004149 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4150 parsed_info->vndrie.oui[0],
4151 parsed_info->vndrie.oui[1],
4152 parsed_info->vndrie.oui[2],
4153 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004154
Arend van Spriel9f440b72013-02-08 15:53:36 +01004155 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004156 break;
4157next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004158 remaining_len -= (ie->len + TLV_HDR_LEN);
4159 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004160 ie = NULL;
4161 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004162 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4163 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004164 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004165 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004166}
4167
4168static u32
4169brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4170{
4171
Hante Meuleman1a873342012-09-27 14:17:54 +02004172 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4173 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4174
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304175 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004176
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304177 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004178
4179 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4180
4181 return ie_len + VNDR_IE_HDR_SIZE;
4182}
4183
Arend van Spriel1332e262012-11-05 16:22:18 -08004184s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4185 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004186{
Arend van Spriel1332e262012-11-05 16:22:18 -08004187 struct brcmf_if *ifp;
4188 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004189 s32 err = 0;
4190 u8 *iovar_ie_buf;
4191 u8 *curr_ie_buf;
4192 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004193 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004194 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004195 u32 del_add_ie_buf_len = 0;
4196 u32 total_ie_buf_len = 0;
4197 u32 parsed_ie_buf_len = 0;
4198 struct parsed_vndr_ies old_vndr_ies;
4199 struct parsed_vndr_ies new_vndr_ies;
4200 struct parsed_vndr_ie_info *vndrie_info;
4201 s32 i;
4202 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004203 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004204
Arend van Spriel1332e262012-11-05 16:22:18 -08004205 if (!vif)
4206 return -ENODEV;
4207 ifp = vif->ifp;
4208 saved_ie = &vif->saved_ie;
4209
Hante Meuleman37a869e2015-10-29 20:33:17 +01004210 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4211 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004212 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4213 if (!iovar_ie_buf)
4214 return -ENOMEM;
4215 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004216 switch (pktflag) {
4217 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4218 mgmt_ie_buf = saved_ie->probe_req_ie;
4219 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4220 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4221 break;
4222 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4223 mgmt_ie_buf = saved_ie->probe_res_ie;
4224 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4225 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4226 break;
4227 case BRCMF_VNDR_IE_BEACON_FLAG:
4228 mgmt_ie_buf = saved_ie->beacon_ie;
4229 mgmt_ie_len = &saved_ie->beacon_ie_len;
4230 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4231 break;
4232 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4233 mgmt_ie_buf = saved_ie->assoc_req_ie;
4234 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4235 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4236 break;
4237 default:
4238 err = -EPERM;
4239 brcmf_err("not suitable type\n");
4240 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004241 }
4242
4243 if (vndr_ie_len > mgmt_ie_buf_len) {
4244 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004245 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004246 goto exit;
4247 }
4248
4249 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4250 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4251 ptr = curr_ie_buf;
4252 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4253 for (i = 0; i < new_vndr_ies.count; i++) {
4254 vndrie_info = &new_vndr_ies.ie_info[i];
4255 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4256 vndrie_info->ie_len);
4257 parsed_ie_buf_len += vndrie_info->ie_len;
4258 }
4259 }
4260
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004261 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004262 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4263 (memcmp(mgmt_ie_buf, curr_ie_buf,
4264 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004265 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004266 goto exit;
4267 }
4268
4269 /* parse old vndr_ie */
4270 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4271
4272 /* make a command to delete old ie */
4273 for (i = 0; i < old_vndr_ies.count; i++) {
4274 vndrie_info = &old_vndr_ies.ie_info[i];
4275
Arend van Sprield96b8012012-12-05 15:26:02 +01004276 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4277 vndrie_info->vndrie.id,
4278 vndrie_info->vndrie.len,
4279 vndrie_info->vndrie.oui[0],
4280 vndrie_info->vndrie.oui[1],
4281 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004282
4283 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4284 vndrie_info->ie_ptr,
4285 vndrie_info->ie_len,
4286 "del");
4287 curr_ie_buf += del_add_ie_buf_len;
4288 total_ie_buf_len += del_add_ie_buf_len;
4289 }
4290 }
4291
4292 *mgmt_ie_len = 0;
4293 /* Add if there is any extra IE */
4294 if (mgmt_ie_buf && parsed_ie_buf_len) {
4295 ptr = mgmt_ie_buf;
4296
4297 remained_buf_len = mgmt_ie_buf_len;
4298
4299 /* make a command to add new ie */
4300 for (i = 0; i < new_vndr_ies.count; i++) {
4301 vndrie_info = &new_vndr_ies.ie_info[i];
4302
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004303 /* verify remained buf size before copy data */
4304 if (remained_buf_len < (vndrie_info->vndrie.len +
4305 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004306 brcmf_err("no space in mgmt_ie_buf: len left %d",
4307 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004308 break;
4309 }
4310 remained_buf_len -= (vndrie_info->ie_len +
4311 VNDR_IE_VSIE_OFFSET);
4312
Arend van Sprield96b8012012-12-05 15:26:02 +01004313 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4314 vndrie_info->vndrie.id,
4315 vndrie_info->vndrie.len,
4316 vndrie_info->vndrie.oui[0],
4317 vndrie_info->vndrie.oui[1],
4318 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004319
4320 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4321 vndrie_info->ie_ptr,
4322 vndrie_info->ie_len,
4323 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004324
4325 /* save the parsed IE in wl struct */
4326 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4327 vndrie_info->ie_len);
4328 *mgmt_ie_len += vndrie_info->ie_len;
4329
4330 curr_ie_buf += del_add_ie_buf_len;
4331 total_ie_buf_len += del_add_ie_buf_len;
4332 }
4333 }
4334 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004335 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004336 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004337 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004338 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004339 }
4340
4341exit:
4342 kfree(iovar_ie_buf);
4343 return err;
4344}
4345
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004346s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4347{
4348 s32 pktflags[] = {
4349 BRCMF_VNDR_IE_PRBREQ_FLAG,
4350 BRCMF_VNDR_IE_PRBRSP_FLAG,
4351 BRCMF_VNDR_IE_BEACON_FLAG
4352 };
4353 int i;
4354
4355 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4356 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4357
4358 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4359 return 0;
4360}
4361
Hante Meuleman1a873342012-09-27 14:17:54 +02004362static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004363brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4364 struct cfg80211_beacon_data *beacon)
4365{
4366 s32 err;
4367
4368 /* Set Beacon IEs to FW */
4369 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4370 beacon->tail, beacon->tail_len);
4371 if (err) {
4372 brcmf_err("Set Beacon IE Failed\n");
4373 return err;
4374 }
4375 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4376
4377 /* Set Probe Response IEs to FW */
4378 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4379 beacon->proberesp_ies,
4380 beacon->proberesp_ies_len);
4381 if (err)
4382 brcmf_err("Set Probe Resp IE Failed\n");
4383 else
4384 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4385
4386 return err;
4387}
4388
4389static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004390brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4391 struct cfg80211_ap_settings *settings)
4392{
4393 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004394 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004395 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004396 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004397 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004398 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004399 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004400 const struct brcmf_tlv *rsn_ie;
4401 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004402 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004403 enum nl80211_iftype dev_role;
4404 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004405 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004406 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004407 int is_11d;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004408 bool supports_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004409
Arend van Spriel06c01582014-05-12 10:47:37 +02004410 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4411 settings->chandef.chan->hw_value,
4412 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004413 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004414 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4415 settings->ssid, settings->ssid_len, settings->auth_type,
4416 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004417 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004418 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004419
Arend van Spriel98027762014-12-21 12:43:53 +01004420 /* store current 11d setting */
Hante Meulemanb3589df2016-09-19 12:09:51 +01004421 if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
4422 &ifp->vif->is_11d)) {
Arnd Bergmannd3532ea2016-10-18 00:13:40 +02004423 is_11d = supports_11d = false;
Hante Meulemanb3589df2016-09-19 12:09:51 +01004424 } else {
4425 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4426 settings->beacon.tail_len,
4427 WLAN_EID_COUNTRY);
4428 is_11d = country_ie ? 1 : 0;
4429 supports_11d = true;
4430 }
Arend van Spriel98027762014-12-21 12:43:53 +01004431
Hante Meuleman1a873342012-09-27 14:17:54 +02004432 memset(&ssid_le, 0, sizeof(ssid_le));
4433 if (settings->ssid == NULL || settings->ssid_len == 0) {
4434 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4435 ssid_ie = brcmf_parse_tlvs(
4436 (u8 *)&settings->beacon.head[ie_offset],
4437 settings->beacon.head_len - ie_offset,
4438 WLAN_EID_SSID);
Arend Van Sprielded89912016-09-05 10:45:47 +01004439 if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004440 return -EINVAL;
4441
4442 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4443 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004444 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004445 } else {
4446 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4447 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4448 }
4449
Hante Meulemana44aa402014-12-03 21:05:33 +01004450 if (!mbss) {
4451 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004452 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004453 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004454
4455 /* find the RSN_IE */
4456 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4457 settings->beacon.tail_len, WLAN_EID_RSN);
4458
4459 /* find the WPA_IE */
4460 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4461 settings->beacon.tail_len);
4462
Hante Meuleman1a873342012-09-27 14:17:54 +02004463 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004464 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004465 if (wpa_ie != NULL) {
4466 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004467 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004468 if (err < 0)
4469 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004470 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004471 struct brcmf_vs_tlv *tmp_ie;
4472
4473 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4474
Hante Meuleman1a873342012-09-27 14:17:54 +02004475 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004476 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004477 if (err < 0)
4478 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004479 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004480 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004481 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004482 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004483 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004484
Rafał Miłecki8707e082016-05-27 21:07:19 +02004485 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004486 if (!mbss) {
Hante Meulemanb3589df2016-09-19 12:09:51 +01004487 if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
Arend van Spriel98027762014-12-21 12:43:53 +01004488 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4489 is_11d);
4490 if (err < 0) {
4491 brcmf_err("Regulatory Set Error, %d\n", err);
4492 goto exit;
4493 }
4494 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004495 if (settings->beacon_interval) {
4496 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4497 settings->beacon_interval);
4498 if (err < 0) {
4499 brcmf_err("Beacon Interval Set Error, %d\n",
4500 err);
4501 goto exit;
4502 }
4503 }
4504 if (settings->dtim_period) {
4505 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4506 settings->dtim_period);
4507 if (err < 0) {
4508 brcmf_err("DTIM Interval Set Error, %d\n", err);
4509 goto exit;
4510 }
4511 }
4512
Hante Meuleman8abffd82015-10-29 20:33:16 +01004513 if ((dev_role == NL80211_IFTYPE_AP) &&
4514 ((ifp->ifidx == 0) ||
4515 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004516 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4517 if (err < 0) {
4518 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4519 goto exit;
4520 }
4521 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4522 }
4523
4524 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004525 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004526 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004527 goto exit;
4528 }
Hante Meulemanb3589df2016-09-19 12:09:51 +01004529 } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
Arend van Spriel98027762014-12-21 12:43:53 +01004530 /* Multiple-BSS should use same 11d configuration */
4531 err = -EINVAL;
4532 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004533 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004534
4535 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004536 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004537 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4538 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4539
Hante Meulemana0f07952013-02-08 15:53:47 +01004540 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4541 if (err < 0) {
4542 brcmf_err("setting AP mode failed %d\n", err);
4543 goto exit;
4544 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004545 if (!mbss) {
4546 /* Firmware 10.x requires setting channel after enabling
4547 * AP and before bringing interface up.
4548 */
4549 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4550 if (err < 0) {
4551 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4552 chanspec, err);
4553 goto exit;
4554 }
4555 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004556 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4557 if (err < 0) {
4558 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4559 goto exit;
4560 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004561 /* On DOWN the firmware removes the WEP keys, reconfigure
4562 * them if they were set.
4563 */
4564 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004565
4566 memset(&join_params, 0, sizeof(join_params));
4567 /* join parameters starts with ssid */
4568 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4569 /* create softap */
4570 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4571 &join_params, sizeof(join_params));
4572 if (err < 0) {
4573 brcmf_err("SET SSID error (%d)\n", err);
4574 goto exit;
4575 }
Rafał Miłeckic940de12016-07-06 12:22:54 +02004576
4577 if (settings->hidden_ssid) {
4578 err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
4579 if (err) {
4580 brcmf_err("closednet error (%d)\n", err);
4581 goto exit;
4582 }
4583 }
4584
Hante Meulemana0f07952013-02-08 15:53:47 +01004585 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004586 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4587 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4588 if (err < 0) {
4589 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4590 chanspec, err);
4591 goto exit;
4592 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004593 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4594 sizeof(ssid_le));
4595 if (err < 0) {
4596 brcmf_err("setting ssid failed %d\n", err);
4597 goto exit;
4598 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004599 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004600 bss_enable.enable = cpu_to_le32(1);
4601 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4602 sizeof(bss_enable));
4603 if (err < 0) {
4604 brcmf_err("bss_enable config failed %d\n", err);
4605 goto exit;
4606 }
4607
4608 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004609 } else {
4610 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004611 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004612
Wright Fengf25ba692016-11-18 09:59:52 +08004613 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Arend van Sprielc1179032012-10-22 13:55:33 -07004614 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004615 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004616
4617exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004618 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004619 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004620 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004621 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004622 return err;
4623}
4624
4625static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4626{
Arend van Sprielc1179032012-10-22 13:55:33 -07004627 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004628 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004629 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004630 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004631
Arend van Sprield96b8012012-12-05 15:26:02 +01004632 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004633
Hante Meuleman426d0a52013-02-08 15:53:53 +01004634 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004635 /* Due to most likely deauths outstanding we sleep */
4636 /* first to make sure they get processed by fw. */
4637 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004638
Hante Meulemana44aa402014-12-03 21:05:33 +01004639 if (ifp->vif->mbss) {
4640 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4641 return err;
4642 }
4643
Rafał Miłeckic940de12016-07-06 12:22:54 +02004644 /* First BSS doesn't get a full reset */
4645 if (ifp->bsscfgidx == 0)
4646 brcmf_fil_iovar_int_set(ifp, "closednet", 0);
4647
Hante Meuleman5c33a942013-04-02 21:06:18 +02004648 memset(&join_params, 0, sizeof(join_params));
4649 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4650 &join_params, sizeof(join_params));
4651 if (err < 0)
4652 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004653 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004654 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004655 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004656 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4657 if (err < 0)
4658 brcmf_err("setting AP mode failed %d\n", err);
4659 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4660 if (err < 0)
4661 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004662 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4663 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Hante Meulemanb3589df2016-09-19 12:09:51 +01004664 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4665 ifp->vif->is_11d);
Hante Meulemana44aa402014-12-03 21:05:33 +01004666 /* Bring device back up so it can be used again */
4667 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4668 if (err < 0)
4669 brcmf_err("BRCMF_C_UP error %d\n", err);
Wright Fengf25ba692016-11-18 09:59:52 +08004670
4671 brcmf_vif_clear_mgmt_ies(ifp->vif);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004672 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004673 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004674 bss_enable.enable = cpu_to_le32(0);
4675 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4676 sizeof(bss_enable));
4677 if (err < 0)
4678 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004679 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004680 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004681 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004682 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004683 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004684
Hante Meuleman1a873342012-09-27 14:17:54 +02004685 return err;
4686}
4687
Hante Meulemana0f07952013-02-08 15:53:47 +01004688static s32
4689brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4690 struct cfg80211_beacon_data *info)
4691{
Hante Meulemana0f07952013-02-08 15:53:47 +01004692 struct brcmf_if *ifp = netdev_priv(ndev);
4693 s32 err;
4694
4695 brcmf_dbg(TRACE, "Enter\n");
4696
Hante Meulemana0f07952013-02-08 15:53:47 +01004697 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4698
4699 return err;
4700}
4701
Hante Meuleman1a873342012-09-27 14:17:54 +02004702static int
4703brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004704 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004705{
Hante Meulemana0f07952013-02-08 15:53:47 +01004706 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004707 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004708 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004709 s32 err;
4710
Jouni Malinen89c771e2014-10-10 20:52:40 +03004711 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004712 return -EFAULT;
4713
Jouni Malinen89c771e2014-10-10 20:52:40 +03004714 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004715
Hante Meulemana0f07952013-02-08 15:53:47 +01004716 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4717 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004718 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004719 return -EIO;
4720
Jouni Malinen89c771e2014-10-10 20:52:40 +03004721 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004722 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004723 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004724 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004725 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004726 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004727
Arend van Sprield96b8012012-12-05 15:26:02 +01004728 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004729 return err;
4730}
4731
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004732static int
4733brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4734 const u8 *mac, struct station_parameters *params)
4735{
4736 struct brcmf_if *ifp = netdev_priv(ndev);
4737 s32 err;
4738
4739 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4740 params->sta_flags_mask, params->sta_flags_set);
4741
4742 /* Ignore all 00 MAC */
4743 if (is_zero_ether_addr(mac))
4744 return 0;
4745
4746 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4747 return 0;
4748
4749 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4750 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4751 (void *)mac, ETH_ALEN);
4752 else
4753 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4754 (void *)mac, ETH_ALEN);
4755 if (err < 0)
4756 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4757
4758 return err;
4759}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004760
4761static void
4762brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4763 struct wireless_dev *wdev,
4764 u16 frame_type, bool reg)
4765{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004766 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004767 u16 mgmt_type;
4768
4769 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4770
4771 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004772 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004773 if (reg)
4774 vif->mgmt_rx_reg |= BIT(mgmt_type);
4775 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004776 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004777}
4778
4779
4780static int
4781brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004782 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004783{
4784 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004785 struct ieee80211_channel *chan = params->chan;
4786 const u8 *buf = params->buf;
4787 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004788 const struct ieee80211_mgmt *mgmt;
4789 struct brcmf_cfg80211_vif *vif;
4790 s32 err = 0;
4791 s32 ie_offset;
4792 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004793 struct brcmf_fil_action_frame_le *action_frame;
4794 struct brcmf_fil_af_params_le *af_params;
4795 bool ack;
4796 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004797 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004798
4799 brcmf_dbg(TRACE, "Enter\n");
4800
4801 *cookie = 0;
4802
4803 mgmt = (const struct ieee80211_mgmt *)buf;
4804
Hante Meulemana0f07952013-02-08 15:53:47 +01004805 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4806 brcmf_err("Driver only allows MGMT packet type\n");
4807 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004808 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004809
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004810 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4811
Hante Meulemana0f07952013-02-08 15:53:47 +01004812 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4813 /* Right now the only reason to get a probe response */
4814 /* is for p2p listen response or for p2p GO from */
4815 /* wpa_supplicant. Unfortunately the probe is send */
4816 /* on primary ndev, while dongle wants it on the p2p */
4817 /* vif. Since this is only reason for a probe */
4818 /* response to be sent, the vif is taken from cfg. */
4819 /* If ever desired to send proberesp for non p2p */
4820 /* response then data should be checked for */
4821 /* "DIRECT-". Note in future supplicant will take */
4822 /* dedicated p2p wdev to do this and then this 'hack'*/
4823 /* is not needed anymore. */
4824 ie_offset = DOT11_MGMT_HDR_LEN +
4825 DOT11_BCN_PRB_FIXED_LEN;
4826 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004827 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4828 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4829 err = brcmf_vif_set_mgmt_ie(vif,
4830 BRCMF_VNDR_IE_PRBRSP_FLAG,
4831 &buf[ie_offset],
4832 ie_len);
4833 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4834 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004835 } else if (ieee80211_is_action(mgmt->frame_control)) {
4836 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4837 if (af_params == NULL) {
4838 brcmf_err("unable to allocate frame\n");
4839 err = -ENOMEM;
4840 goto exit;
4841 }
4842 action_frame = &af_params->action_frame;
4843 /* Add the packet Id */
4844 action_frame->packet_id = cpu_to_le32(*cookie);
4845 /* Add BSSID */
4846 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4847 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4848 /* Add the length exepted for 802.11 header */
4849 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004850 /* Add the channel. Use the one specified as parameter if any or
4851 * the current one (got from the firmware) otherwise
4852 */
4853 if (chan)
4854 freq = chan->center_freq;
4855 else
4856 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4857 &freq);
4858 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004859 af_params->channel = cpu_to_le32(chan_nr);
4860
4861 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4862 le16_to_cpu(action_frame->len));
4863
4864 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004865 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004866
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004867 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004868 af_params);
4869
4870 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4871 GFP_KERNEL);
4872 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004873 } else {
4874 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -08004875 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
Hante Meulemana0f07952013-02-08 15:53:47 +01004876 }
4877
Hante Meuleman18e2f612013-02-08 15:53:49 +01004878exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004879 return err;
4880}
4881
4882
4883static int
4884brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4885 struct wireless_dev *wdev,
4886 u64 cookie)
4887{
4888 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4889 struct brcmf_cfg80211_vif *vif;
4890 int err = 0;
4891
4892 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4893
4894 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4895 if (vif == NULL) {
4896 brcmf_err("No p2p device available for probe response\n");
4897 err = -ENODEV;
4898 goto exit;
4899 }
4900 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4901exit:
4902 return err;
4903}
4904
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004905static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4906 struct wireless_dev *wdev,
4907 struct cfg80211_chan_def *chandef)
4908{
4909 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4910 struct net_device *ndev = wdev->netdev;
4911 struct brcmf_if *ifp;
4912 struct brcmu_chan ch;
4913 enum nl80211_band band = 0;
4914 enum nl80211_chan_width width = 0;
4915 u32 chanspec;
4916 int freq, err;
4917
4918 if (!ndev)
4919 return -ENODEV;
4920 ifp = netdev_priv(ndev);
4921
4922 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4923 if (err) {
4924 brcmf_err("chanspec failed (%d)\n", err);
4925 return err;
4926 }
4927
4928 ch.chspec = chanspec;
4929 cfg->d11inf.decchspec(&ch);
4930
4931 switch (ch.band) {
4932 case BRCMU_CHAN_BAND_2G:
4933 band = NL80211_BAND_2GHZ;
4934 break;
4935 case BRCMU_CHAN_BAND_5G:
4936 band = NL80211_BAND_5GHZ;
4937 break;
4938 }
4939
4940 switch (ch.bw) {
4941 case BRCMU_CHAN_BW_80:
4942 width = NL80211_CHAN_WIDTH_80;
4943 break;
4944 case BRCMU_CHAN_BW_40:
4945 width = NL80211_CHAN_WIDTH_40;
4946 break;
4947 case BRCMU_CHAN_BW_20:
4948 width = NL80211_CHAN_WIDTH_20;
4949 break;
4950 case BRCMU_CHAN_BW_80P80:
4951 width = NL80211_CHAN_WIDTH_80P80;
4952 break;
4953 case BRCMU_CHAN_BW_160:
4954 width = NL80211_CHAN_WIDTH_160;
4955 break;
4956 }
4957
4958 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
4959 chandef->chan = ieee80211_get_channel(wiphy, freq);
4960 chandef->width = width;
4961 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
4962 chandef->center_freq2 = 0;
4963
4964 return 0;
4965}
4966
Piotr Haber61730d42013-04-23 12:53:12 +02004967static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4968 struct wireless_dev *wdev,
4969 enum nl80211_crit_proto_id proto,
4970 u16 duration)
4971{
4972 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4973 struct brcmf_cfg80211_vif *vif;
4974
4975 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4976
4977 /* only DHCP support for now */
4978 if (proto != NL80211_CRIT_PROTO_DHCP)
4979 return -EINVAL;
4980
4981 /* suppress and abort scanning */
4982 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4983 brcmf_abort_scanning(cfg);
4984
4985 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4986}
4987
4988static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4989 struct wireless_dev *wdev)
4990{
4991 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4992 struct brcmf_cfg80211_vif *vif;
4993
4994 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4995
4996 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4997 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4998}
4999
Hante Meuleman70b7d942014-07-30 13:20:07 +02005000static s32
5001brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5002 const struct brcmf_event_msg *e, void *data)
5003{
5004 switch (e->reason) {
5005 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5006 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5007 break;
5008 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5009 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5010 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5011 break;
5012 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5013 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5014 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5015 break;
5016 }
5017
5018 return 0;
5019}
5020
Arend van Spriel89c2f382013-08-10 12:27:25 +02005021static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5022{
5023 int ret;
5024
5025 switch (oper) {
5026 case NL80211_TDLS_DISCOVERY_REQ:
5027 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5028 break;
5029 case NL80211_TDLS_SETUP:
5030 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5031 break;
5032 case NL80211_TDLS_TEARDOWN:
5033 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5034 break;
5035 default:
5036 brcmf_err("unsupported operation: %d\n", oper);
5037 ret = -EOPNOTSUPP;
5038 }
5039 return ret;
5040}
5041
5042static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005043 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005044 enum nl80211_tdls_operation oper)
5045{
5046 struct brcmf_if *ifp;
5047 struct brcmf_tdls_iovar_le info;
5048 int ret = 0;
5049
5050 ret = brcmf_convert_nl80211_tdls_oper(oper);
5051 if (ret < 0)
5052 return ret;
5053
5054 ifp = netdev_priv(ndev);
5055 memset(&info, 0, sizeof(info));
5056 info.mode = (u8)ret;
5057 if (peer)
5058 memcpy(info.ea, peer, ETH_ALEN);
5059
5060 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5061 &info, sizeof(info));
5062 if (ret < 0)
5063 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5064
5065 return ret;
5066}
5067
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005068static int
5069brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
5070 struct net_device *ndev,
5071 struct cfg80211_connect_params *sme,
5072 u32 changed)
5073{
5074 struct brcmf_if *ifp;
5075 int err;
5076
5077 if (!(changed & UPDATE_ASSOC_IES))
5078 return 0;
5079
5080 ifp = netdev_priv(ndev);
5081 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
5082 sme->ie, sme->ie_len);
5083 if (err)
5084 brcmf_err("Set Assoc REQ IE Failed\n");
5085 else
5086 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
5087
5088 return err;
5089}
5090
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005091#ifdef CONFIG_PM
5092static int
5093brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5094 struct cfg80211_gtk_rekey_data *gtk)
5095{
5096 struct brcmf_if *ifp = netdev_priv(ndev);
5097 struct brcmf_gtk_keyinfo_le gtk_le;
5098 int ret;
5099
5100 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5101
5102 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5103 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5104 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5105 sizeof(gtk_le.replay_counter));
5106
5107 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5108 sizeof(gtk_le));
5109 if (ret < 0)
5110 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5111
5112 return ret;
5113}
5114#endif
5115
5116static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005117 .add_virtual_intf = brcmf_cfg80211_add_iface,
5118 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005119 .change_virtual_intf = brcmf_cfg80211_change_iface,
5120 .scan = brcmf_cfg80211_scan,
5121 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5122 .join_ibss = brcmf_cfg80211_join_ibss,
5123 .leave_ibss = brcmf_cfg80211_leave_ibss,
5124 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005125 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005126 .set_tx_power = brcmf_cfg80211_set_tx_power,
5127 .get_tx_power = brcmf_cfg80211_get_tx_power,
5128 .add_key = brcmf_cfg80211_add_key,
5129 .del_key = brcmf_cfg80211_del_key,
5130 .get_key = brcmf_cfg80211_get_key,
5131 .set_default_key = brcmf_cfg80211_config_default_key,
5132 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5133 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005134 .connect = brcmf_cfg80211_connect,
5135 .disconnect = brcmf_cfg80211_disconnect,
5136 .suspend = brcmf_cfg80211_suspend,
5137 .resume = brcmf_cfg80211_resume,
5138 .set_pmksa = brcmf_cfg80211_set_pmksa,
5139 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005140 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005141 .start_ap = brcmf_cfg80211_start_ap,
5142 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005143 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005144 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005145 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005146 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5147 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005148 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5149 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5150 .remain_on_channel = brcmf_p2p_remain_on_channel,
5151 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005152 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005153 .start_p2p_device = brcmf_p2p_start_device,
5154 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005155 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5156 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005157 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend Van Spriel2a2a5d12017-01-27 12:27:48 +00005158 .update_connect_params = brcmf_cfg80211_update_conn_params,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005159};
5160
Arend van Spriel3eacf862012-10-22 13:55:30 -07005161struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005162 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005163{
Hante Meulemana44aa402014-12-03 21:05:33 +01005164 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005165 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005166 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005167
Arend van Spriel33a6b152013-02-08 15:53:39 +01005168 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005169 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005170 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5171 if (!vif)
5172 return ERR_PTR(-ENOMEM);
5173
5174 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005175 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005176
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005177 brcmf_init_prof(&vif->profile);
5178
Hante Meulemana44aa402014-12-03 21:05:33 +01005179 if (type == NL80211_IFTYPE_AP) {
5180 mbss = false;
5181 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5182 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5183 mbss = true;
5184 break;
5185 }
5186 }
5187 vif->mbss = mbss;
5188 }
5189
Arend van Spriel3eacf862012-10-22 13:55:30 -07005190 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005191 return vif;
5192}
5193
Arend van Spriel427dec52014-01-06 12:40:47 +01005194void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005195{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005196 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005197 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005198}
5199
Arend van Spriel9df4d542014-01-06 12:40:49 +01005200void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5201{
5202 struct brcmf_cfg80211_vif *vif;
5203 struct brcmf_if *ifp;
5204
5205 ifp = netdev_priv(ndev);
5206 vif = ifp->vif;
5207
Arend van Spriel95ef1232015-08-26 22:15:04 +02005208 if (vif)
5209 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005210 free_netdev(ndev);
5211}
5212
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005213static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005214{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005215 u32 event = e->event_code;
5216 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005217
5218 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005219 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005220 return true;
5221 }
5222
5223 return false;
5224}
5225
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005226static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005227{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005228 u32 event = e->event_code;
5229 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005230
Hante Meuleman68ca3952014-02-25 20:30:26 +01005231 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5232 (event == BRCMF_E_DISASSOC_IND) ||
5233 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005234 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005235 return true;
5236 }
5237 return false;
5238}
5239
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005240static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005241 const struct brcmf_event_msg *e)
5242{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005243 u32 event = e->event_code;
5244 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005245
5246 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005247 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5248 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005249 return true;
5250 }
5251
5252 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005253 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005254 return true;
5255 }
5256
5257 return false;
5258}
5259
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005260static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005261{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005262 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263
5264 kfree(conn_info->req_ie);
5265 conn_info->req_ie = NULL;
5266 conn_info->req_ie_len = 0;
5267 kfree(conn_info->resp_ie);
5268 conn_info->resp_ie = NULL;
5269 conn_info->resp_ie_len = 0;
5270}
5271
Hante Meuleman89286dc2013-02-08 15:53:46 +01005272static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5273 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005274{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005275 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005276 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005277 u32 req_len;
5278 u32 resp_len;
5279 s32 err = 0;
5280
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005281 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005282
Arend van Sprielac24be62012-10-22 10:36:23 -07005283 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5284 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005285 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005286 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005287 return err;
5288 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005289 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005290 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005291 req_len = le32_to_cpu(assoc_info->req_len);
5292 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005294 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005295 cfg->extra_buf,
5296 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005297 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005298 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005299 return err;
5300 }
5301 conn_info->req_ie_len = req_len;
5302 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005303 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005304 GFP_KERNEL);
5305 } else {
5306 conn_info->req_ie_len = 0;
5307 conn_info->req_ie = NULL;
5308 }
5309 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005310 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005311 cfg->extra_buf,
5312 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005313 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005314 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005315 return err;
5316 }
5317 conn_info->resp_ie_len = resp_len;
5318 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005319 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005320 GFP_KERNEL);
5321 } else {
5322 conn_info->resp_ie_len = 0;
5323 conn_info->resp_ie = NULL;
5324 }
Arend van Spriel16886732012-12-05 15:26:04 +01005325 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5326 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005327
5328 return err;
5329}
5330
5331static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005332brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005333 struct net_device *ndev,
5334 const struct brcmf_event_msg *e)
5335{
Arend van Sprielc1179032012-10-22 13:55:33 -07005336 struct brcmf_if *ifp = netdev_priv(ndev);
5337 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005338 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5339 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005340 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005341 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005342 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005343 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005344 u32 freq;
5345 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005346 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005347
Arend van Sprield96b8012012-12-05 15:26:02 +01005348 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005349
Hante Meuleman89286dc2013-02-08 15:53:46 +01005350 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005351 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005352 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005353
Franky Lina180b832012-10-10 11:13:09 -07005354 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5355 if (buf == NULL) {
5356 err = -ENOMEM;
5357 goto done;
5358 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005359
Franky Lina180b832012-10-10 11:13:09 -07005360 /* data sent to dongle has to be little endian */
5361 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005362 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005363 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005364
5365 if (err)
5366 goto done;
5367
5368 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005369 ch.chspec = le16_to_cpu(bi->chanspec);
5370 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005371
Franky Lin83cf17a2013-04-11 13:28:50 +02005372 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005373 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005374 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005375 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005376
Rafał Miłecki4712d882016-05-20 13:38:57 +02005377 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378 notify_channel = ieee80211_get_channel(wiphy, freq);
5379
Franky Lina180b832012-10-10 11:13:09 -07005380done:
5381 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005382 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005383 conn_info->req_ie, conn_info->req_ie_len,
5384 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005385 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005386
Arend van Sprielc1179032012-10-22 13:55:33 -07005387 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005388 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005389 return err;
5390}
5391
5392static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005393brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005394 struct net_device *ndev, const struct brcmf_event_msg *e,
5395 bool completed)
5396{
Arend van Sprielc1179032012-10-22 13:55:33 -07005397 struct brcmf_if *ifp = netdev_priv(ndev);
5398 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005399 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005400
Arend van Sprield96b8012012-12-05 15:26:02 +01005401 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005402
Arend van Sprielc1179032012-10-22 13:55:33 -07005403 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5404 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005405 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005406 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005407 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005408 brcmf_update_bss_info(cfg, ifp);
5409 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5410 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005411 }
5412 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005413 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005414 conn_info->req_ie,
5415 conn_info->req_ie_len,
5416 conn_info->resp_ie,
5417 conn_info->resp_ie_len,
5418 completed ? WLAN_STATUS_SUCCESS :
5419 WLAN_STATUS_AUTH_TIMEOUT,
5420 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005421 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5422 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005423 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005424 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005425 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005426}
5427
5428static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005429brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005430 struct net_device *ndev,
5431 const struct brcmf_event_msg *e, void *data)
5432{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005433 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005434 u32 event = e->event_code;
5435 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005436 struct station_info sinfo;
5437
Rafał Miłeckie1c122d2016-10-14 09:45:59 +02005438 brcmf_dbg(CONN, "event %s (%u), reason %d\n",
5439 brcmf_fweh_event_name(event), event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005440 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5441 ndev != cfg_to_ndev(cfg)) {
5442 brcmf_dbg(CONN, "AP mode link down\n");
5443 complete(&cfg->vif_disabled);
5444 return 0;
5445 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005446
Hante Meuleman1a873342012-09-27 14:17:54 +02005447 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005448 (reason == BRCMF_E_STATUS_SUCCESS)) {
5449 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005450 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005451 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005452 return -EINVAL;
5453 }
5454 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005455 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005456 generation++;
5457 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005458 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005459 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5460 (event == BRCMF_E_DEAUTH_IND) ||
5461 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005462 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005463 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005464 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005465}
5466
5467static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005468brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005469 const struct brcmf_event_msg *e, void *data)
5470{
Arend van Spriel19937322012-11-05 16:22:32 -08005471 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5472 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005473 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005474 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005475 s32 err = 0;
5476
Hante Meuleman8851cce2014-07-30 13:20:02 +02005477 if ((e->event_code == BRCMF_E_DEAUTH) ||
5478 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5479 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5480 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5481 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5482 }
5483
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005484 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005485 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005486 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005487 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005488 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005489 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005490 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005491 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005492 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005493 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5494 &ifp->vif->sme_state);
5495 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5496 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005497 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005498 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005499 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005500 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005501 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005502 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005503 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005504 brcmf_link_down(ifp->vif,
5505 brcmf_map_fw_linkdown_reason(e));
5506 brcmf_init_prof(ndev_to_prof(ndev));
5507 if (ndev != cfg_to_ndev(cfg))
5508 complete(&cfg->vif_disabled);
5509 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005510 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005511 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005512 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005513 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5514 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005515 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005516 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005517 }
5518
5519 return err;
5520}
5521
5522static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005523brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005524 const struct brcmf_event_msg *e, void *data)
5525{
Arend van Spriel19937322012-11-05 16:22:32 -08005526 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005527 u32 event = e->event_code;
5528 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005529
5530 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005531 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005532 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005533 else
Arend van Spriel19937322012-11-05 16:22:32 -08005534 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005535 }
5536
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005537 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005538}
5539
5540static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005541brcmf_notify_mic_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 Spriel5c36b992012-11-14 18:46:05 -08005544 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005545 enum nl80211_key_type key_type;
5546
5547 if (flags & BRCMF_EVENT_MSG_GROUP)
5548 key_type = NL80211_KEYTYPE_GROUP;
5549 else
5550 key_type = NL80211_KEYTYPE_PAIRWISE;
5551
Arend van Spriel19937322012-11-05 16:22:32 -08005552 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005553 NULL, GFP_KERNEL);
5554
5555 return 0;
5556}
5557
Arend van Sprield3c0b632013-02-08 15:53:37 +01005558static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5559 const struct brcmf_event_msg *e, void *data)
5560{
5561 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5562 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5563 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5564 struct brcmf_cfg80211_vif *vif;
5565
Hante Meuleman37a869e2015-10-29 20:33:17 +01005566 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005567 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005568 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005569
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005570 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005571 event->action = ifevent->action;
5572 vif = event->vif;
5573
5574 switch (ifevent->action) {
5575 case BRCMF_E_IF_ADD:
5576 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005577 if (!cfg->vif_event.vif) {
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005578 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005579 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005580 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005581
5582 ifp->vif = vif;
5583 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005584 if (ifp->ndev) {
5585 vif->wdev.netdev = ifp->ndev;
5586 ifp->ndev->ieee80211_ptr = &vif->wdev;
5587 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5588 }
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005589 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005590 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005591 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005592
5593 case BRCMF_E_IF_DEL:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005594 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005595 /* event may not be upon user request */
5596 if (brcmf_cfg80211_vif_event_armed(cfg))
5597 wake_up(&event->vif_wq);
5598 return 0;
5599
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005600 case BRCMF_E_IF_CHANGE:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005601 spin_unlock(&event->vif_event_lock);
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005602 wake_up(&event->vif_wq);
5603 return 0;
5604
Arend van Sprield3c0b632013-02-08 15:53:37 +01005605 default:
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005606 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005607 break;
5608 }
5609 return -EINVAL;
5610}
5611
Arend van Spriel5b435de2011-10-05 13:19:03 +02005612static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5613{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005614 conf->frag_threshold = (u32)-1;
5615 conf->rts_threshold = (u32)-1;
5616 conf->retry_short = (u32)-1;
5617 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005618}
5619
Arend van Spriel5c36b992012-11-14 18:46:05 -08005620static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005621{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005622 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5623 brcmf_notify_connect_status);
5624 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5625 brcmf_notify_connect_status);
5626 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5627 brcmf_notify_connect_status);
5628 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5629 brcmf_notify_connect_status);
5630 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5631 brcmf_notify_connect_status);
5632 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5633 brcmf_notify_connect_status);
5634 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5635 brcmf_notify_roaming_status);
5636 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5637 brcmf_notify_mic_status);
5638 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5639 brcmf_notify_connect_status);
5640 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5641 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005642 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5643 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005644 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005645 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005646 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5647 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005648 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5649 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005650 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5651 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005652 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5653 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005654}
5655
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005656static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005657{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005658 kfree(cfg->conf);
5659 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005660 kfree(cfg->extra_buf);
5661 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005662 kfree(cfg->wowl.nd);
5663 cfg->wowl.nd = NULL;
5664 kfree(cfg->wowl.nd_info);
5665 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005666 kfree(cfg->escan_info.escan_buf);
5667 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005668}
5669
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005670static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005671{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005672 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5673 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005674 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005675 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5676 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005677 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005678 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5679 if (!cfg->wowl.nd)
5680 goto init_priv_mem_out;
5681 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5682 sizeof(struct cfg80211_wowlan_nd_match *),
5683 GFP_KERNEL);
5684 if (!cfg->wowl.nd_info)
5685 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005686 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5687 if (!cfg->escan_info.escan_buf)
5688 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005689
5690 return 0;
5691
5692init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005693 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005694
5695 return -ENOMEM;
5696}
5697
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005698static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005699{
5700 s32 err = 0;
5701
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005702 cfg->scan_request = NULL;
5703 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005704 cfg->active_scan = true; /* we do active scan per default */
5705 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005706 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005707 if (err)
5708 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005709 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005710 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005711 brcmf_init_escan(cfg);
5712 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005713 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005714 return err;
5715}
5716
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005717static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005718{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005719 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005720 brcmf_abort_scanning(cfg);
5721 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005722}
5723
Arend van Sprield3c0b632013-02-08 15:53:37 +01005724static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5725{
5726 init_waitqueue_head(&event->vif_wq);
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09005727 spin_lock_init(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005728}
5729
Hante Meuleman1119e232015-11-25 11:32:42 +01005730static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005731{
Hante Meuleman1119e232015-11-25 11:32:42 +01005732 s32 err;
5733 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005734 __le32 roamtrigger[2];
5735 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005736
Hante Meuleman1119e232015-11-25 11:32:42 +01005737 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005738 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005739 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5740 else
5741 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5742 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5743 if (err) {
5744 brcmf_err("bcn_timeout error (%d)\n", err);
5745 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005746 }
5747
Hante Meuleman1119e232015-11-25 11:32:42 +01005748 /* Enable/Disable built-in roaming to allow supplicant to take care of
5749 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005750 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005751 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005752 ifp->drvr->settings->roamoff ? "Off" : "On");
5753 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5754 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005755 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005756 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005757 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005758 }
5759
Arend van Sprielf588bc02011-10-12 20:51:22 +02005760 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5761 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005762 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005763 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005764 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005765 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005766 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005767 }
5768
Arend van Sprielf588bc02011-10-12 20:51:22 +02005769 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5770 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005771 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005772 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005773 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005774 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005775 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005776 }
5777
Hante Meuleman1119e232015-11-25 11:32:42 +01005778roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005779 return err;
5780}
5781
5782static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005783brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005784{
5785 s32 err = 0;
5786
Arend van Sprielac24be62012-10-22 10:36:23 -07005787 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005788 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005789 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005790 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005791 goto dongle_scantime_out;
5792 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005793 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005794 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005795 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005796 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005797 goto dongle_scantime_out;
5798 }
5799
Arend van Sprielac24be62012-10-22 10:36:23 -07005800 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005801 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005802 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005803 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005804 goto dongle_scantime_out;
5805 }
5806
5807dongle_scantime_out:
5808 return err;
5809}
5810
Arend van Sprielb48d8912014-07-12 08:49:41 +02005811static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5812 struct brcmu_chan *ch)
5813{
5814 u32 ht40_flag;
5815
5816 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5817 if (ch->sb == BRCMU_CHAN_SB_U) {
5818 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5819 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5820 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5821 } else {
5822 /* It should be one of
5823 * IEEE80211_CHAN_NO_HT40 or
5824 * IEEE80211_CHAN_NO_HT40PLUS
5825 */
5826 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5827 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5828 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5829 }
5830}
5831
5832static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5833 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005834{
5835 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005836 struct ieee80211_supported_band *band;
5837 struct ieee80211_channel *channel;
5838 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005839 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005840 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005841 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005842 u8 *pbuf;
5843 u32 i, j;
5844 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005845 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005846
5847 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5848
5849 if (pbuf == NULL)
5850 return -ENOMEM;
5851
5852 list = (struct brcmf_chanspec_list *)pbuf;
5853
5854 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5855 BRCMF_DCMD_MEDLEN);
5856 if (err) {
5857 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005858 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005859 }
5860
Arend van Sprielb48d8912014-07-12 08:49:41 +02005861 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005862 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005863 if (band)
5864 for (i = 0; i < band->n_channels; i++)
5865 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005866 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005867 if (band)
5868 for (i = 0; i < band->n_channels; i++)
5869 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005870
5871 total = le32_to_cpu(list->count);
5872 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005873 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5874 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005875
Franky Lin83cf17a2013-04-11 13:28:50 +02005876 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005877 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005878 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005879 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005880 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005881 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005882 continue;
5883 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005884 if (!band)
5885 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005886 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005887 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005888 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005889 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005890 ch.bw == BRCMU_CHAN_BW_80)
5891 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005892
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005893 channel = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005894 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005895 if (band->channels[j].hw_value == ch.control_ch_num) {
5896 channel = &band->channels[j];
Hante Meulemand48200b2013-04-03 12:40:29 +02005897 break;
5898 }
5899 }
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005900 if (!channel) {
5901 /* It seems firmware supports some channel we never
5902 * considered. Something new in IEEE standard?
5903 */
5904 brcmf_err("Ignoring unexpected firmware channel %d\n",
5905 ch.control_ch_num);
5906 continue;
5907 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005908
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01005909 if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
5910 continue;
5911
Arend van Sprielb48d8912014-07-12 08:49:41 +02005912 /* assuming the chanspecs order is HT20,
5913 * HT40 upper, HT40 lower, and VHT80.
5914 */
5915 if (ch.bw == BRCMU_CHAN_BW_80) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005916 channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005917 } else if (ch.bw == BRCMU_CHAN_BW_40) {
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005918 brcmf_update_bw40_channel_flag(channel, &ch);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005919 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005920 /* enable the channel and disable other bandwidths
5921 * for now as mentioned order assure they are enabled
5922 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005923 */
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005924 channel->flags = IEEE80211_CHAN_NO_HT40 |
5925 IEEE80211_CHAN_NO_80MHZ;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005926 ch.bw = BRCMU_CHAN_BW_20;
5927 cfg->d11inf.encchspec(&ch);
5928 chaninfo = ch.chspec;
5929 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5930 &chaninfo);
5931 if (!err) {
5932 if (chaninfo & WL_CHAN_RADAR)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005933 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02005934 (IEEE80211_CHAN_RADAR |
5935 IEEE80211_CHAN_NO_IR);
5936 if (chaninfo & WL_CHAN_PASSIVE)
Rafał Miłecki77c0d0c2017-01-04 12:09:41 +01005937 channel->flags |=
Arend van Sprielb48d8912014-07-12 08:49:41 +02005938 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005939 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005940 }
5941 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005942
Arend van Sprielb48d8912014-07-12 08:49:41 +02005943fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005944 kfree(pbuf);
5945 return err;
5946}
5947
Arend van Sprielb48d8912014-07-12 08:49:41 +02005948static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005949{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005950 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5951 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005952 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005953 struct brcmf_chanspec_list *list;
5954 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005955 u32 val;
5956 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005957 struct brcmu_chan ch;
5958 u32 num_chan;
5959 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005960
5961 /* verify support for bw_cap command */
5962 val = WLC_BAND_5G;
5963 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5964
5965 if (!err) {
5966 /* only set 2G bandwidth using bw_cap command */
5967 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5968 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5969 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5970 sizeof(band_bwcap));
5971 } else {
5972 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5973 val = WLC_N_BW_40ALL;
5974 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5975 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005976
5977 if (!err) {
5978 /* update channel info in 2G band */
5979 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5980
5981 if (pbuf == NULL)
5982 return -ENOMEM;
5983
5984 ch.band = BRCMU_CHAN_BAND_2G;
5985 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005986 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005987 ch.chnum = 0;
5988 cfg->d11inf.encchspec(&ch);
5989
5990 /* pass encoded chanspec in query */
5991 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5992
5993 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5994 BRCMF_DCMD_MEDLEN);
5995 if (err) {
5996 brcmf_err("get chanspecs error (%d)\n", err);
5997 kfree(pbuf);
5998 return err;
5999 }
6000
Johannes Berg57fbcce2016-04-12 15:56:15 +02006001 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006002 list = (struct brcmf_chanspec_list *)pbuf;
6003 num_chan = le32_to_cpu(list->count);
6004 for (i = 0; i < num_chan; i++) {
6005 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6006 cfg->d11inf.decchspec(&ch);
6007 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6008 continue;
6009 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6010 continue;
6011 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006012 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006013 break;
6014 }
6015 if (WARN_ON(j == band->n_channels))
6016 continue;
6017
6018 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6019 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006020 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006021 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006022 return err;
6023}
6024
Arend van Spriel2375d972014-01-06 12:40:41 +01006025static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6026{
6027 u32 band, mimo_bwcap;
6028 int err;
6029
6030 band = WLC_BAND_2G;
6031 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6032 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006033 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006034 band = WLC_BAND_5G;
6035 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6036 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006037 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006038 return;
6039 }
6040 WARN_ON(1);
6041 return;
6042 }
6043 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6044 mimo_bwcap = 0;
6045 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6046 if (err)
6047 /* assume 20MHz if firmware does not give a clue */
6048 mimo_bwcap = WLC_N_BW_20ALL;
6049
6050 switch (mimo_bwcap) {
6051 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006052 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006053 /* fall-thru */
6054 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006055 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006056 /* fall-thru */
6057 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006058 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6059 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006060 break;
6061 default:
6062 brcmf_err("invalid mimo_bw_cap value\n");
6063 }
6064}
Hante Meulemand48200b2013-04-03 12:40:29 +02006065
Arend van Spriel18d6c532014-05-12 10:47:35 +02006066static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6067 u32 bw_cap[2], u32 nchain)
6068{
6069 band->ht_cap.ht_supported = true;
6070 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6071 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6072 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6073 }
6074 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6075 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6076 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6077 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6078 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6079 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6080}
6081
6082static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6083{
6084 u16 mcs_map;
6085 int i;
6086
6087 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6088 mcs_map = (mcs_map << 2) | supp;
6089
6090 return cpu_to_le16(mcs_map);
6091}
6092
6093static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006094 u32 bw_cap[2], u32 nchain, u32 txstreams,
6095 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006096{
6097 __le16 mcs_map;
6098
6099 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006100 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006101 return;
6102
6103 band->vht_cap.vht_supported = true;
6104 /* 80MHz is mandatory */
6105 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6106 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6107 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6108 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6109 }
6110 /* all support 256-QAM */
6111 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6112 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6113 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006114
6115 /* Beamforming support information */
6116 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6117 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6118 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6119 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6120 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6121 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6122 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6123 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6124
6125 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6126 band->vht_cap.cap |=
6127 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6128 band->vht_cap.cap |= ((txstreams - 1) <<
6129 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6130 band->vht_cap.cap |=
6131 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6132 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006133}
6134
Arend van Sprielb48d8912014-07-12 08:49:41 +02006135static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006136{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006137 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006138 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006139 u32 nmode = 0;
6140 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006141 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006142 u32 rxchain;
6143 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006144 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006145 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006146 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006147 u32 txstreams = 0;
6148 u32 txbf_bfe_cap = 0;
6149 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006150
Arend van Spriel18d6c532014-05-12 10:47:35 +02006151 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006152 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6153 if (err) {
6154 brcmf_err("nmode error (%d)\n", err);
6155 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006156 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006157 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006158 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006159 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6160 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006161
Daniel Kim4aca7a12014-02-25 20:30:36 +01006162 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6163 if (err) {
6164 brcmf_err("rxchain error (%d)\n", err);
6165 nchain = 1;
6166 } else {
6167 for (nchain = 0; rxchain; nchain++)
6168 rxchain = rxchain & (rxchain - 1);
6169 }
6170 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6171
Arend van Sprielb48d8912014-07-12 08:49:41 +02006172 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006173 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006174 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006175 return err;
6176 }
6177
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006178 if (vhtmode) {
6179 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6180 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6181 &txbf_bfe_cap);
6182 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6183 &txbf_bfr_cap);
6184 }
6185
Arend van Sprielb48d8912014-07-12 08:49:41 +02006186 wiphy = cfg_to_wiphy(cfg);
6187 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6188 band = wiphy->bands[i];
6189 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006190 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006191
Arend van Spriel18d6c532014-05-12 10:47:35 +02006192 if (nmode)
6193 brcmf_update_ht_cap(band, bw_cap, nchain);
6194 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006195 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6196 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006197 }
6198
Arend van Sprielb48d8912014-07-12 08:49:41 +02006199 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006200}
6201
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006202static const struct ieee80211_txrx_stypes
6203brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6204 [NL80211_IFTYPE_STATION] = {
6205 .tx = 0xffff,
6206 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6207 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6208 },
6209 [NL80211_IFTYPE_P2P_CLIENT] = {
6210 .tx = 0xffff,
6211 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6212 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6213 },
6214 [NL80211_IFTYPE_P2P_GO] = {
6215 .tx = 0xffff,
6216 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6217 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6218 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6219 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6220 BIT(IEEE80211_STYPE_AUTH >> 4) |
6221 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6222 BIT(IEEE80211_STYPE_ACTION >> 4)
6223 },
6224 [NL80211_IFTYPE_P2P_DEVICE] = {
6225 .tx = 0xffff,
6226 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6227 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6228 }
6229};
6230
Arend van Spriel0882dda2015-08-20 22:06:03 +02006231/**
6232 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6233 *
6234 * @wiphy: wiphy object.
6235 * @ifp: interface object needed for feat module api.
6236 *
6237 * The interface modes and combinations are determined dynamically here
6238 * based on firmware functionality.
6239 *
6240 * no p2p and no mbss:
6241 *
6242 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6243 *
6244 * no p2p and mbss:
6245 *
6246 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6247 * #AP <= 4, matching BI, channels = 1, 4 total
6248 *
6249 * p2p, no mchan, and mbss:
6250 *
6251 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6252 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6253 * #AP <= 4, matching BI, channels = 1, 4 total
6254 *
6255 * p2p, mchan, and mbss:
6256 *
6257 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6258 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6259 * #AP <= 4, matching BI, channels = 1, 4 total
6260 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006261static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6262{
6263 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006264 struct ieee80211_iface_limit *c0_limits = NULL;
6265 struct ieee80211_iface_limit *p2p_limits = NULL;
6266 struct ieee80211_iface_limit *mbss_limits = NULL;
6267 bool mbss, p2p;
6268 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006269
Arend van Spriel0882dda2015-08-20 22:06:03 +02006270 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6271 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6272
6273 n_combos = 1 + !!p2p + !!mbss;
6274 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006275 if (!combo)
6276 goto err;
6277
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006278 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6279 BIT(NL80211_IFTYPE_ADHOC) |
6280 BIT(NL80211_IFTYPE_AP);
6281
Arend van Spriel0882dda2015-08-20 22:06:03 +02006282 c = 0;
6283 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006284 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6285 if (!c0_limits)
6286 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006287 c0_limits[i].max = 1;
6288 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6289 if (p2p) {
6290 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6291 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006292 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6293 BIT(NL80211_IFTYPE_P2P_GO) |
6294 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006295 c0_limits[i].max = 1;
6296 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6297 c0_limits[i].max = 1;
6298 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6299 BIT(NL80211_IFTYPE_P2P_GO);
6300 } else {
6301 c0_limits[i].max = 1;
6302 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006303 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006304 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006305 combo[c].max_interfaces = i;
6306 combo[c].n_limits = i;
6307 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006308
Arend van Spriel0882dda2015-08-20 22:06:03 +02006309 if (p2p) {
6310 c++;
6311 i = 0;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006312 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6313 if (!p2p_limits)
6314 goto err;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006315 p2p_limits[i].max = 1;
6316 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6317 p2p_limits[i].max = 1;
6318 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6319 p2p_limits[i].max = 1;
6320 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6321 p2p_limits[i].max = 1;
6322 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006323 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006324 combo[c].max_interfaces = i;
6325 combo[c].n_limits = i;
6326 combo[c].limits = p2p_limits;
6327 }
6328
6329 if (mbss) {
6330 c++;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006331 i = 0;
6332 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6333 if (!mbss_limits)
6334 goto err;
6335 mbss_limits[i].max = 4;
6336 mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006337 combo[c].beacon_int_infra_match = true;
6338 combo[c].num_different_channels = 1;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006339 combo[c].max_interfaces = 4;
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006340 combo[c].n_limits = i;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006341 combo[c].limits = mbss_limits;
6342 }
Rafał Miłeckif568ada2016-06-07 21:10:18 +02006343
Arend van Spriel0882dda2015-08-20 22:06:03 +02006344 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006345 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006346 return 0;
6347
6348err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006349 kfree(c0_limits);
6350 kfree(p2p_limits);
6351 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006352 kfree(combo);
6353 return -ENOMEM;
6354}
6355
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006356static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6357{
6358 /* scheduled scan settings */
6359 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6360 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6361 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend Van Sprielc6989fd2016-11-23 10:25:30 +00006362 wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006363 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6364}
6365
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006366#ifdef CONFIG_PM
Arend Van Spriel0b570102017-01-27 12:27:47 +00006367static const struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006368 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006369 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6370 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6371 .pattern_min_len = 1,
6372 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006373};
6374#endif
6375
Hante Meuleman3021ad92016-01-05 11:05:45 +01006376static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006377{
6378#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006379 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend Van Spriel0b570102017-01-27 12:27:47 +00006380 struct wiphy_wowlan_support *wowl;
6381
6382 wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
6383 GFP_KERNEL);
6384 if (!wowl) {
6385 brcmf_err("only support basic wowlan features\n");
6386 wiphy->wowlan = &brcmf_wowlan_support;
6387 return;
6388 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01006389
6390 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006391 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006392 wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
6393 wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006394 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006395 }
6396 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006397 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
Arend Van Spriel0b570102017-01-27 12:27:47 +00006398 wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6399 wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006400 }
6401
Arend Van Spriel0b570102017-01-27 12:27:47 +00006402 wiphy->wowlan = wowl;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006403#endif
6404}
6405
Arend van Sprielb48d8912014-07-12 08:49:41 +02006406static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006407{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006408 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006409 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006410 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006411 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006412 __le32 bandlist[3];
6413 u32 n_bands;
6414 int err, i;
6415
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006416 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6417 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006418 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006419
6420 err = brcmf_setup_ifmodes(wiphy, ifp);
6421 if (err)
6422 return err;
6423
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006424 for (i = 0, combo = wiphy->iface_combinations;
6425 i < wiphy->n_iface_combinations; i++, combo++) {
6426 max_interfaces = max(max_interfaces, combo->max_interfaces);
6427 }
6428
6429 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6430 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006431 u8 *addr = drvr->addresses[i].addr;
6432
6433 memcpy(addr, drvr->mac, ETH_ALEN);
6434 if (i) {
6435 addr[0] |= BIT(1);
6436 addr[ETH_ALEN - 1] ^= i;
6437 }
6438 }
6439 wiphy->addresses = drvr->addresses;
6440 wiphy->n_addresses = i;
6441
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006442 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006443 wiphy->cipher_suites = brcmf_cipher_suites;
6444 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6445 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6446 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006447 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6448 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6449 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6450
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006451 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6452 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006453 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6454 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6455 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006456 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006457 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6458 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6459 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006460 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6461 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006462
6463 /* vendor commands/events support */
6464 wiphy->vendor_commands = brcmf_vendor_cmds;
6465 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6466
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006467 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006468 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006469 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6470 sizeof(bandlist));
6471 if (err) {
6472 brcmf_err("could not obtain band info: err=%d\n", err);
6473 return err;
6474 }
6475 /* first entry in bandlist is number of bands */
6476 n_bands = le32_to_cpu(bandlist[0]);
6477 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6478 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6479 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6480 GFP_KERNEL);
6481 if (!band)
6482 return -ENOMEM;
6483
6484 band->channels = kmemdup(&__wl_2ghz_channels,
6485 sizeof(__wl_2ghz_channels),
6486 GFP_KERNEL);
6487 if (!band->channels) {
6488 kfree(band);
6489 return -ENOMEM;
6490 }
6491
6492 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006493 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006494 }
6495 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6496 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6497 GFP_KERNEL);
6498 if (!band)
6499 return -ENOMEM;
6500
6501 band->channels = kmemdup(&__wl_5ghz_channels,
6502 sizeof(__wl_5ghz_channels),
6503 GFP_KERNEL);
6504 if (!band->channels) {
6505 kfree(band);
6506 return -ENOMEM;
6507 }
6508
6509 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006510 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006511 }
6512 }
Rafał Miłecki0f83ff62017-01-17 23:35:50 +01006513
6514 wiphy_read_of_freq_limits(wiphy);
6515
Rafał Miłeckiab990632017-01-07 21:36:05 +01006516 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006517}
6518
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006519static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006520{
6521 struct net_device *ndev;
6522 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006523 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006524 s32 power_mode;
6525 s32 err = 0;
6526
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006527 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006528 return err;
6529
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006530 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006531 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006532 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006533
Hante Meuleman40a23292013-01-02 15:22:51 +01006534 /* make sure RF is ready for work */
6535 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6536
Hante Meuleman1678ba82015-12-10 13:43:00 +01006537 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006538
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006539 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006540 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006541 if (err)
6542 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006543 brcmf_dbg(INFO, "power save set to %s\n",
6544 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006545
Hante Meuleman1119e232015-11-25 11:32:42 +01006546 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006547 if (err)
6548 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006549 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
Johannes Berg818a9862017-04-12 11:23:28 +02006550 NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006551 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006552 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006553
Franky Lin52f22fb2016-02-17 11:26:55 +01006554 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006555
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006556 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006557default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006558
6559 return err;
6560
6561}
6562
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006563static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006564{
Arend van Sprielc1179032012-10-22 13:55:33 -07006565 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006566
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006567 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006568}
6569
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006570static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006571{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006572 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006573
Arend van Spriel5b435de2011-10-05 13:19:03 +02006574 /*
6575 * While going down, if associated with AP disassociate
6576 * from AP to save power
6577 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006578 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006579 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006580
6581 /* Make sure WPA_Supplicant receives all the event
6582 generated due to DISASSOC call to the fw to keep
6583 the state fw and WPA_Supplicant state consistent
6584 */
6585 brcmf_delay(500);
6586 }
6587
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006588 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006589 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006590
Arend van Spriel5b435de2011-10-05 13:19:03 +02006591 return 0;
6592}
6593
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006594s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006595{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006596 struct brcmf_if *ifp = netdev_priv(ndev);
6597 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006598 s32 err = 0;
6599
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006600 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006601 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006602 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006603
6604 return err;
6605}
6606
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006607s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006608{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006609 struct brcmf_if *ifp = netdev_priv(ndev);
6610 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006611 s32 err = 0;
6612
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006613 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006614 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006615 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006616
6617 return err;
6618}
6619
Arend van Spriela7965fb2013-04-11 17:08:37 +02006620enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6621{
6622 struct wireless_dev *wdev = &ifp->vif->wdev;
6623
6624 return wdev->iftype;
6625}
6626
Hante Meulemanbfe81972014-10-28 14:56:16 +01006627bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6628 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006629{
6630 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006631
6632 list_for_each_entry(vif, &cfg->vif_list, list) {
6633 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006634 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006635 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006636 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006637}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006638
6639static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6640 u8 action)
6641{
6642 u8 evt_action;
6643
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006644 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006645 evt_action = event->action;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006646 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006647 return evt_action == action;
6648}
6649
6650void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6651 struct brcmf_cfg80211_vif *vif)
6652{
6653 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6654
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006655 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006656 event->vif = vif;
6657 event->action = 0;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006658 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006659}
6660
6661bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6662{
6663 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6664 bool armed;
6665
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006666 spin_lock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006667 armed = event->vif != NULL;
mhiramat@kernel.orgb64abcb2016-08-15 18:41:12 +09006668 spin_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01006669
6670 return armed;
6671}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006672
6673int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6674 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006675{
6676 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6677
6678 return wait_event_timeout(event->vif_wq,
6679 vif_event_equals(event, action), timeout);
6680}
6681
Hante Meuleman73345fd2016-02-17 11:26:53 +01006682static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6683 struct brcmf_fil_country_le *ccreq)
6684{
Hante Meuleman4d792892016-02-17 11:27:07 +01006685 struct brcmfmac_pd_cc *country_codes;
6686 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006687 s32 found_index;
6688 int i;
6689
6690 country_codes = drvr->settings->country_codes;
6691 if (!country_codes) {
6692 brcmf_dbg(TRACE, "No country codes configured for device\n");
6693 return -EINVAL;
6694 }
6695
6696 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6697 (alpha2[1] == ccreq->country_abbrev[1])) {
6698 brcmf_dbg(TRACE, "Country code already set\n");
6699 return -EAGAIN;
6700 }
6701
6702 found_index = -1;
6703 for (i = 0; i < country_codes->table_size; i++) {
6704 cc = &country_codes->table[i];
6705 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6706 found_index = i;
6707 if ((cc->iso3166[0] == alpha2[0]) &&
6708 (cc->iso3166[1] == alpha2[1])) {
6709 found_index = i;
6710 break;
6711 }
6712 }
6713 if (found_index == -1) {
6714 brcmf_dbg(TRACE, "No country code match found\n");
6715 return -EINVAL;
6716 }
6717 memset(ccreq, 0, sizeof(*ccreq));
6718 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6719 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6720 BRCMF_COUNTRY_BUF_SZ);
6721 ccreq->country_abbrev[0] = alpha2[0];
6722 ccreq->country_abbrev[1] = alpha2[1];
6723 ccreq->country_abbrev[2] = 0;
6724
6725 return 0;
6726}
6727
Arend van Spriel63db1a42014-12-21 12:43:51 +01006728static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6729 struct regulatory_request *req)
6730{
6731 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6732 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6733 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006734 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006735 int i;
6736
Arend van Spriel63db1a42014-12-21 12:43:51 +01006737 /* ignore non-ISO3166 country codes */
6738 for (i = 0; i < sizeof(req->alpha2); i++)
6739 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006740 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6741 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006742 return;
6743 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006744
6745 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6746 req->alpha2[0], req->alpha2[1]);
6747
6748 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6749 if (err) {
6750 brcmf_err("Country code iovar returned err = %d\n", err);
6751 return;
6752 }
6753
6754 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6755 if (err)
6756 return;
6757
6758 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6759 if (err) {
6760 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006761 return;
6762 }
6763 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006764}
6765
Arend van Sprielb48d8912014-07-12 08:49:41 +02006766static void brcmf_free_wiphy(struct wiphy *wiphy)
6767{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006768 int i;
6769
Arend van Spriel58de92d2015-04-14 20:10:24 +02006770 if (!wiphy)
6771 return;
6772
Arend van Spriel0882dda2015-08-20 22:06:03 +02006773 if (wiphy->iface_combinations) {
6774 for (i = 0; i < wiphy->n_iface_combinations; i++)
6775 kfree(wiphy->iface_combinations[i].limits);
6776 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006777 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006778 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6779 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6780 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006781 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006782 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6783 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6784 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006785 }
Arend Van Spriel0b570102017-01-27 12:27:47 +00006786#if IS_ENABLED(CONFIG_PM)
6787 if (wiphy->wowlan != &brcmf_wowlan_support)
6788 kfree(wiphy->wowlan);
6789#endif
Arend van Sprielb48d8912014-07-12 08:49:41 +02006790 wiphy_free(wiphy);
6791}
6792
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006793struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006794 struct device *busdev,
6795 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006796{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006797 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006798 struct brcmf_cfg80211_info *cfg;
6799 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006800 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006801 struct brcmf_cfg80211_vif *vif;
6802 struct brcmf_if *ifp;
6803 s32 err = 0;
6804 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006805 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006806
6807 if (!ndev) {
6808 brcmf_err("ndev is invalid\n");
6809 return NULL;
6810 }
6811
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306812 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006813 if (!ops)
6814 return NULL;
6815
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006816 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006817#ifdef CONFIG_PM
6818 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6819 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6820#endif
6821 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006822 if (!wiphy) {
6823 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006824 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006825 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006826 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006827 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006828
6829 cfg = wiphy_priv(wiphy);
6830 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006831 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006832 cfg->pub = drvr;
6833 init_vif_event(&cfg->vif_event);
6834 INIT_LIST_HEAD(&cfg->vif_list);
6835
Rafał Miłecki26072332016-06-06 23:03:55 +02006836 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006837 if (IS_ERR(vif))
6838 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006839
6840 vif->ifp = ifp;
6841 vif->wdev.netdev = ndev;
6842 ndev->ieee80211_ptr = &vif->wdev;
6843 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6844
6845 err = wl_init_priv(cfg);
6846 if (err) {
6847 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006848 brcmf_free_vif(vif);
6849 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006850 }
6851 ifp->vif = vif;
6852
Arend van Sprielb48d8912014-07-12 08:49:41 +02006853 /* determine d11 io type before wiphy setup */
6854 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006855 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006856 brcmf_err("Failed to get D11 version (%d)\n", err);
6857 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006858 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006859 cfg->d11inf.io_type = (u8)io_type;
6860 brcmu_d11_attach(&cfg->d11inf);
6861
6862 err = brcmf_setup_wiphy(wiphy, ifp);
6863 if (err < 0)
6864 goto priv_out;
6865
6866 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006867 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006868 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6869 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6870
6871 /* firmware defaults to 40MHz disabled in 2G band. We signal
6872 * cfg80211 here that we do and have it decide we can enable
6873 * it. But first check if device does support 2G operation.
6874 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006875 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6876 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006877 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6878 }
6879 err = wiphy_register(wiphy);
6880 if (err < 0) {
6881 brcmf_err("Could not register wiphy device (%d)\n", err);
6882 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006883 }
6884
Rafał Miłeckiab990632017-01-07 21:36:05 +01006885 err = brcmf_setup_wiphybands(wiphy);
6886 if (err) {
6887 brcmf_err("Setting wiphy bands failed (%d)\n", err);
6888 goto wiphy_unreg_out;
6889 }
6890
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006891 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6892 * setup 40MHz in 2GHz band and enable OBSS scanning.
6893 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006894 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6895 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006896 if (!err)
6897 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6898 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006899 else
6900 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006901 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006902 /* p2p might require that "if-events" get processed by fweh. So
6903 * activate the already registered event handlers now and activate
6904 * the rest when initialization has completed. drvr->config needs to
6905 * be assigned before activating events.
6906 */
6907 drvr->config = cfg;
6908 err = brcmf_fweh_activate_events(ifp);
6909 if (err) {
6910 brcmf_err("FWEH activation failed (%d)\n", err);
6911 goto wiphy_unreg_out;
6912 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006913
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006914 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006915 if (err) {
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006916 brcmf_err("P2P initialisation failed (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006917 goto wiphy_unreg_out;
6918 }
6919 err = brcmf_btcoex_attach(cfg);
6920 if (err) {
6921 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6922 brcmf_p2p_detach(&cfg->p2p);
6923 goto wiphy_unreg_out;
6924 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006925
Hante Meulemana7b82d42015-12-10 13:43:04 +01006926 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6927 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6928 if (err) {
6929 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6930 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6931 } else {
6932 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6933 brcmf_notify_tdls_peer_event);
6934 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006935 }
6936
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006937 /* (re-) activate FWEH event handling */
6938 err = brcmf_fweh_activate_events(ifp);
6939 if (err) {
6940 brcmf_err("FWEH activation failed (%d)\n", err);
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006941 goto detach;
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006942 }
6943
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006944 /* Fill in some of the advertised nl80211 supported features */
6945 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6946 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6947#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006948 if (wiphy->wowlan &&
6949 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006950 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6951#endif
6952 }
6953
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006954 return cfg;
6955
Arend Van Sprielcb853da2016-12-09 11:34:13 +00006956detach:
6957 brcmf_btcoex_detach(cfg);
6958 brcmf_p2p_detach(&cfg->p2p);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006959wiphy_unreg_out:
6960 wiphy_unregister(cfg->wiphy);
6961priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006962 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006963 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006964 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006965wiphy_out:
6966 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006967 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006968 return NULL;
6969}
6970
6971void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6972{
6973 if (!cfg)
6974 return;
6975
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006976 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006977 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006978 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006979 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006980 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006981}