blob: 62f475e31077ca1fa1df15863f02ee0911c46997 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Franky Lin1bacb042014-06-21 12:11:16 +020022#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020024#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
Hante Meuleman122d3d02014-10-28 14:56:18 +010029#include "core.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010030#include "debug.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020031#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010032#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010033#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020034#include "btcoex.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010035#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020036#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070037#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020038#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020039#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010040#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010041#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
Arend van Spriele5806072012-09-19 22:21:08 +020043#define BRCMF_SCAN_IE_LEN_MAX 2048
44#define BRCMF_PNO_VERSION 2
45#define BRCMF_PNO_TIME 30
46#define BRCMF_PNO_REPEAT 4
47#define BRCMF_PNO_FREQ_EXPO_MAX 3
48#define BRCMF_PNO_MAX_PFN_COUNT 16
49#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
50#define BRCMF_PNO_HIDDEN_BIT 2
51#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
52#define BRCMF_PNO_SCAN_COMPLETE 1
53#define BRCMF_PNO_SCAN_INCOMPLETE 0
54
Hante Meuleman1a873342012-09-27 14:17:54 +020055#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
56#define WPA_OUI_TYPE 1
57#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
58#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010059#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020060
61#define VS_IE_FIXED_HDR_LEN 6
62#define WPA_IE_VERSION_LEN 2
63#define WPA_IE_MIN_OUI_LEN 4
64#define WPA_IE_SUITE_COUNT_LEN 2
65
66#define WPA_CIPHER_NONE 0 /* None */
67#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
68#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
69#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
70#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
71
72#define RSN_AKM_NONE 0 /* None (IBSS) */
73#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
74#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010075#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
76#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020077#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010078#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
79#define RSN_CAP_MFPR_MASK BIT(6)
80#define RSN_CAP_MFPC_MASK BIT(7)
81#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define VNDR_IE_CMD_LEN 4 /* length of the set command
84 * string :"add", "del" (+ NUL)
85 */
86#define VNDR_IE_COUNT_OFFSET 4
87#define VNDR_IE_PKTFLAG_OFFSET 8
88#define VNDR_IE_VSIE_OFFSET 12
89#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010090#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020091
92#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
93#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020094
Hante Meuleman89286dc2013-02-08 15:53:46 +010095#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
96#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
97#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
98
Hante Meuleman1678ba82015-12-10 13:43:00 +010099#define BRCMF_SCAN_CHANNEL_TIME 40
100#define BRCMF_SCAN_UNASSOC_TIME 40
101#define BRCMF_SCAN_PASSIVE_TIME 120
102
Hante Meuleman3021ad92016-01-05 11:05:45 +0100103#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
104
Arend van Spriel5b435de2011-10-05 13:19:03 +0200105#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
106 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
107
Arend van Sprielce81e312012-10-22 13:55:37 -0700108static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109{
Arend van Sprielc1179032012-10-22 13:55:33 -0700110 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100111 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
112 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200113 return false;
114 }
115 return true;
116}
117
Arend van Spriel5b435de2011-10-05 13:19:03 +0200118#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
119#define RATETAB_ENT(_rateid, _flags) \
120 { \
121 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
122 .hw_value = (_rateid), \
123 .flags = (_flags), \
124 }
125
126static struct ieee80211_rate __wl_rates[] = {
127 RATETAB_ENT(BRCM_RATE_1M, 0),
128 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
129 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
130 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_6M, 0),
132 RATETAB_ENT(BRCM_RATE_9M, 0),
133 RATETAB_ENT(BRCM_RATE_12M, 0),
134 RATETAB_ENT(BRCM_RATE_18M, 0),
135 RATETAB_ENT(BRCM_RATE_24M, 0),
136 RATETAB_ENT(BRCM_RATE_36M, 0),
137 RATETAB_ENT(BRCM_RATE_48M, 0),
138 RATETAB_ENT(BRCM_RATE_54M, 0),
139};
140
Arend van Spriel5b435de2011-10-05 13:19:03 +0200141#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200142#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
143#define wl_a_rates (__wl_rates + 4)
144#define wl_a_rates_size (wl_g_rates_size - 4)
145
146#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200147 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200148 .center_freq = (_freq), \
149 .hw_value = (_channel), \
150 .flags = IEEE80211_CHAN_DISABLED, \
151 .max_antenna_gain = 0, \
152 .max_power = 30, \
153}
154
155#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200156 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200157 .center_freq = 5000 + (5 * (_channel)), \
158 .hw_value = (_channel), \
159 .flags = IEEE80211_CHAN_DISABLED, \
160 .max_antenna_gain = 0, \
161 .max_power = 30, \
162}
163
164static struct ieee80211_channel __wl_2ghz_channels[] = {
165 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
166 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
167 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
168 CHAN2G(13, 2472), CHAN2G(14, 2484)
169};
170
171static struct ieee80211_channel __wl_5ghz_channels[] = {
172 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
173 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
174 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
175 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
176 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
177 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
178};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200179
Arend van Sprielb48d8912014-07-12 08:49:41 +0200180/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200181 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200182 */
183static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200184 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200185 .bitrates = wl_g_rates,
186 .n_bitrates = wl_g_rates_size,
187};
188
Arend van Spriel58de92d2015-04-14 20:10:24 +0200189static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200190 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200191 .bitrates = wl_a_rates,
192 .n_bitrates = wl_a_rates_size,
193};
194
Hante Meulemand48200b2013-04-03 12:40:29 +0200195/* This is to override regulatory domains defined in cfg80211 module (reg.c)
196 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200197 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
198 * With respect to these flags, wpa_supplicant doesn't * start p2p
199 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200200 * domain are to be done here.
201 */
202static const struct ieee80211_regdomain brcmf_regdom = {
203 .n_reg_rules = 4,
204 .alpha2 = "99",
205 .reg_rules = {
206 /* IEEE 802.11b/g, channels 1..11 */
207 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
208 /* If any */
209 /* IEEE 802.11 channel 14 - Only JP enables
210 * this and for 802.11b only
211 */
212 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
213 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200214 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200215 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200216 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200217};
218
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
220 * are supported. A pointer to this array and the number of entries is passed
221 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
222 * So the cipher suite AES_CMAC has to be the last one in the array, and when
223 * device does not support MFP then the number of suites will be decreased by 1
224 */
225static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200226 WLAN_CIPHER_SUITE_WEP40,
227 WLAN_CIPHER_SUITE_WEP104,
228 WLAN_CIPHER_SUITE_TKIP,
229 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100230 /* Keep as last entry: */
231 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200232};
233
Hante Meuleman1a873342012-09-27 14:17:54 +0200234/* Vendor specific ie. id = 221, oui and type defines exact ie */
235struct brcmf_vs_tlv {
236 u8 id;
237 u8 len;
238 u8 oui[3];
239 u8 oui_type;
240};
241
242struct parsed_vndr_ie_info {
243 u8 *ie_ptr;
244 u32 ie_len; /* total length including id & length field */
245 struct brcmf_vs_tlv vndrie;
246};
247
248struct parsed_vndr_ies {
249 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100250 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200251};
252
Arend van Spriel7705ba62016-04-17 16:44:58 +0200253static u8 nl80211_band_to_fwil(enum nl80211_band band)
254{
255 switch (band) {
256 case NL80211_BAND_2GHZ:
257 return WLC_BAND_2G;
258 case NL80211_BAND_5GHZ:
259 return WLC_BAND_5G;
260 default:
261 WARN_ON(1);
262 break;
263 }
264 return 0;
265}
266
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200267static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
268 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200269{
270 struct brcmu_chan ch_inf;
271 s32 primary_offset;
272
273 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
274 ch->chan->center_freq, ch->center_freq1, ch->width);
275 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100276 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200277 switch (ch->width) {
278 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100279 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200280 ch_inf.bw = BRCMU_CHAN_BW_20;
281 WARN_ON(primary_offset != 0);
282 break;
283 case NL80211_CHAN_WIDTH_40:
284 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100285 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200286 ch_inf.sb = BRCMU_CHAN_SB_U;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_L;
289 break;
290 case NL80211_CHAN_WIDTH_80:
291 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100292 if (primary_offset == -30)
293 ch_inf.sb = BRCMU_CHAN_SB_LL;
294 else if (primary_offset == -10)
295 ch_inf.sb = BRCMU_CHAN_SB_LU;
296 else if (primary_offset == 10)
297 ch_inf.sb = BRCMU_CHAN_SB_UL;
298 else
299 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200300 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100301 case NL80211_CHAN_WIDTH_80P80:
302 case NL80211_CHAN_WIDTH_160:
303 case NL80211_CHAN_WIDTH_5:
304 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200309 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200310 ch_inf.band = BRCMU_CHAN_BAND_2G;
311 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200312 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200313 ch_inf.band = BRCMU_CHAN_BAND_5G;
314 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200315 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200316 default:
317 WARN_ON_ONCE(1);
318 }
319 d11inf->encchspec(&ch_inf);
320
321 return ch_inf.chspec;
322}
323
Franky Lin83cf17a2013-04-11 13:28:50 +0200324u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
325 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700326{
Franky Lin83cf17a2013-04-11 13:28:50 +0200327 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700328
Franky Lin83cf17a2013-04-11 13:28:50 +0200329 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
330 ch_inf.bw = BRCMU_CHAN_BW_20;
331 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700332
Franky Lin83cf17a2013-04-11 13:28:50 +0200333 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700334}
335
Hante Meuleman89286dc2013-02-08 15:53:46 +0100336/* Traverse a string of 1-byte tag/1-byte length/variable-length value
337 * triples, returning a pointer to the substring whose first element
338 * matches tag
339 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100340const struct brcmf_tlv *
341brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100342{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100343 const struct brcmf_tlv *elt = buf;
344 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100345
346 /* find tagged parameter */
347 while (totlen >= TLV_HDR_LEN) {
348 int len = elt->len;
349
350 /* validate remaining totlen */
351 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
352 return elt;
353
354 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
355 totlen -= (len + TLV_HDR_LEN);
356 }
357
358 return NULL;
359}
360
361/* Is any of the tlvs the expected entry? If
362 * not update the tlvs buffer pointer/length.
363 */
364static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100365brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
366 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100367{
368 /* If the contents match the OUI and the type */
369 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
370 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
371 type == ie[TLV_BODY_OFF + oui_len]) {
372 return true;
373 }
374
375 if (tlvs == NULL)
376 return false;
377 /* point to the next ie */
378 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
379 /* calculate the length of the rest of the buffer */
380 *tlvs_len -= (int)(ie - *tlvs);
381 /* update the pointer to the start of the buffer */
382 *tlvs = ie;
383
384 return false;
385}
386
387static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100388brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100389{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391
392 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100393 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100394 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
395 return (struct brcmf_vs_tlv *)ie;
396 }
397 return NULL;
398}
399
400static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100401brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100402{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100403 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100404
405 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
406 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
407 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
408 return (struct brcmf_vs_tlv *)ie;
409 }
410 return NULL;
411}
412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
414 struct brcmf_cfg80211_vif *vif,
415 enum nl80211_iftype new_type)
416{
417 int iftype_num[NUM_NL80211_IFTYPES];
418 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100419 bool check_combos = false;
420 int ret = 0;
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
422 memset(&iftype_num[0], 0, sizeof(iftype_num));
423 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424 if (pos == vif) {
Arend van Spriel39504a22015-08-20 22:06:05 +0200425 iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100426 } else {
427 /* concurrent interfaces so need check combinations */
428 check_combos = true;
Arend van Spriel39504a22015-08-20 22:06:05 +0200429 iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100430 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200431
Arend van Spriel353c46a2015-12-10 13:43:06 +0100432 if (check_combos)
433 ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
434
435 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200436}
437
438static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
439 enum nl80211_iftype new_type)
440{
441 int iftype_num[NUM_NL80211_IFTYPES];
442 struct brcmf_cfg80211_vif *pos;
443
444 memset(&iftype_num[0], 0, sizeof(iftype_num));
445 list_for_each_entry(pos, &cfg->vif_list, list)
446 iftype_num[pos->wdev.iftype]++;
447
448 iftype_num[new_type]++;
449 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
450}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100451
Arend van Spriel5b435de2011-10-05 13:19:03 +0200452static void convert_key_from_CPU(struct brcmf_wsec_key *key,
453 struct brcmf_wsec_key_le *key_le)
454{
455 key_le->index = cpu_to_le32(key->index);
456 key_le->len = cpu_to_le32(key->len);
457 key_le->algo = cpu_to_le32(key->algo);
458 key_le->flags = cpu_to_le32(key->flags);
459 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
460 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
461 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
462 memcpy(key_le->data, key->data, sizeof(key->data));
463 memcpy(key_le->ea, key->ea, sizeof(key->ea));
464}
465
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200466static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100467send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200468{
469 int err;
470 struct brcmf_wsec_key_le key_le;
471
472 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200473
Hante Meuleman118eb302014-12-21 12:43:49 +0100474 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700475
Hante Meuleman118eb302014-12-21 12:43:49 +0100476 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700477 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200478
Arend van Spriel5b435de2011-10-05 13:19:03 +0200479 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100480 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200481 return err;
482}
483
Hante Meulemanb3657452013-05-27 21:09:53 +0200484static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100485brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200486{
487 s32 err;
488 u32 mode;
489
490 if (enable)
491 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
492 else
493 mode = 0;
494
495 /* Try to set and enable ARP offload feature, this may fail, then it */
496 /* is simply not supported and err 0 will be returned */
497 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
498 if (err) {
499 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
500 mode, err);
501 err = 0;
502 } else {
503 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
504 if (err) {
505 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
506 enable, err);
507 err = 0;
508 } else
509 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
510 enable, mode);
511 }
512
Franky Lin52f22fb2016-02-17 11:26:55 +0100513 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
514 if (err) {
515 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
516 enable, err);
517 err = 0;
518 } else
519 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
520 enable, mode);
521
Hante Meulemanb3657452013-05-27 21:09:53 +0200522 return err;
523}
524
Hante Meuleman8851cce2014-07-30 13:20:02 +0200525static void
526brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
527{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200528 struct brcmf_cfg80211_vif *vif;
529 struct brcmf_if *ifp;
530
531 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
532 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200533
534 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
535 (wdev->iftype == NL80211_IFTYPE_AP) ||
536 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
537 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
538 ADDR_DIRECT);
539 else
540 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
541 ADDR_INDIRECT);
542}
543
Hante Meulemana44aa402014-12-03 21:05:33 +0100544static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
545{
546 struct brcmf_mbss_ssid_le mbss_ssid_le;
547 int bsscfgidx;
548 int err;
549
550 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
551 bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr);
552 if (bsscfgidx < 0)
553 return bsscfgidx;
554
555 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
556 mbss_ssid_le.SSID_len = cpu_to_le32(5);
557 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
558
559 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
560 sizeof(mbss_ssid_le));
561 if (err < 0)
562 brcmf_err("setting ssid failed %d\n", err);
563
564 return err;
565}
566
567/**
568 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
569 *
570 * @wiphy: wiphy device of new interface.
571 * @name: name of the new interface.
572 * @flags: not used.
573 * @params: contains mac address for AP device.
574 */
575static
576struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
577 u32 *flags, struct vif_params *params)
578{
579 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
580 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
581 struct brcmf_cfg80211_vif *vif;
582 int err;
583
584 if (brcmf_cfg80211_vif_event_armed(cfg))
585 return ERR_PTR(-EBUSY);
586
587 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
588
589 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false);
590 if (IS_ERR(vif))
591 return (struct wireless_dev *)vif;
592
593 brcmf_cfg80211_arm_vif_event(cfg, vif);
594
595 err = brcmf_cfg80211_request_ap_if(ifp);
596 if (err) {
597 brcmf_cfg80211_arm_vif_event(cfg, NULL);
598 goto fail;
599 }
600
601 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100602 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
603 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100604 brcmf_cfg80211_arm_vif_event(cfg, NULL);
605 if (!err) {
606 brcmf_err("timeout occurred\n");
607 err = -EIO;
608 goto fail;
609 }
610
611 /* interface created in firmware */
612 ifp = vif->ifp;
613 if (!ifp) {
614 brcmf_err("no if pointer provided\n");
615 err = -ENOENT;
616 goto fail;
617 }
618
619 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
620 err = brcmf_net_attach(ifp, true);
621 if (err) {
622 brcmf_err("Registering netdevice failed\n");
623 goto fail;
624 }
625
626 return &ifp->vif->wdev;
627
628fail:
629 brcmf_free_vif(vif);
630 return ERR_PTR(err);
631}
632
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100633static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
634{
635 enum nl80211_iftype iftype;
636
637 iftype = vif->wdev.iftype;
638 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
639}
640
641static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
642{
643 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
644}
645
Arend van Spriel9f440b72013-02-08 15:53:36 +0100646static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
647 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100648 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100649 enum nl80211_iftype type,
650 u32 *flags,
651 struct vif_params *params)
652{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200653 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200654 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200655
Arend van Spriel9f440b72013-02-08 15:53:36 +0100656 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200657 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
658 if (err) {
659 brcmf_err("iface validation failed: err=%d\n", err);
660 return ERR_PTR(err);
661 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100662 switch (type) {
663 case NL80211_IFTYPE_ADHOC:
664 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100665 case NL80211_IFTYPE_AP_VLAN:
666 case NL80211_IFTYPE_WDS:
667 case NL80211_IFTYPE_MONITOR:
668 case NL80211_IFTYPE_MESH_POINT:
669 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100670 case NL80211_IFTYPE_AP:
671 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
672 if (!IS_ERR(wdev))
673 brcmf_cfg80211_update_proto_addr_mode(wdev);
674 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100675 case NL80211_IFTYPE_P2P_CLIENT:
676 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200677 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100678 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Hante Meuleman8851cce2014-07-30 13:20:02 +0200679 if (!IS_ERR(wdev))
680 brcmf_cfg80211_update_proto_addr_mode(wdev);
681 return wdev;
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 }
686}
687
Daniel Kim5e787f72014-06-21 12:11:18 +0200688static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
689{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200690 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200691 brcmf_set_mpc(ifp, mpc);
692}
693
Arend van Sprielf96aa072013-04-05 10:57:48 +0200694void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100695{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100696 s32 err = 0;
697
698 if (check_vif_up(ifp->vif)) {
699 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
700 if (err) {
701 brcmf_err("fail to set mpc\n");
702 return;
703 }
704 brcmf_dbg(INFO, "MPC : %d\n", mpc);
705 }
706}
707
Arend van Spriela0f472a2013-04-05 10:57:49 +0200708s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
709 struct brcmf_if *ifp, bool aborted,
710 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100711{
712 struct brcmf_scan_params_le params_le;
713 struct cfg80211_scan_request *scan_request;
714 s32 err = 0;
715
716 brcmf_dbg(SCAN, "Enter\n");
717
718 /* clear scan request, because the FW abort can cause a second call */
719 /* to this functon and might cause a double cfg80211_scan_done */
720 scan_request = cfg->scan_request;
721 cfg->scan_request = NULL;
722
723 if (timer_pending(&cfg->escan_timeout))
724 del_timer_sync(&cfg->escan_timeout);
725
726 if (fw_abort) {
727 /* Do a scan abort to stop the driver's scan engine */
728 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
729 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800730 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100731 params_le.bss_type = DOT11_BSSTYPE_ANY;
732 params_le.scan_type = 0;
733 params_le.channel_num = cpu_to_le32(1);
734 params_le.nprobes = cpu_to_le32(1);
735 params_le.active_time = cpu_to_le32(-1);
736 params_le.passive_time = cpu_to_le32(-1);
737 params_le.home_time = cpu_to_le32(-1);
738 /* Scan is aborted by setting channel_list[0] to -1 */
739 params_le.channel_list[0] = cpu_to_le16(-1);
740 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200741 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100742 &params_le, sizeof(params_le));
743 if (err)
744 brcmf_err("Scan abort failed\n");
745 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200746
Daniel Kim5e787f72014-06-21 12:11:18 +0200747 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200748
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100749 /*
750 * e-scan can be initiated by scheduled scan
751 * which takes precedence.
752 */
753 if (cfg->sched_escan) {
754 brcmf_dbg(SCAN, "scheduled scan completed\n");
755 cfg->sched_escan = false;
756 if (!aborted)
757 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100758 } else if (scan_request) {
759 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
760 aborted ? "Aborted" : "Done");
761 cfg80211_scan_done(scan_request, aborted);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100762 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100763 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
764 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100765
766 return err;
767}
768
Arend van Spriel9f440b72013-02-08 15:53:36 +0100769static
770int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
771{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100772 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
773 struct net_device *ndev = wdev->netdev;
774
775 /* vif event pending in firmware */
776 if (brcmf_cfg80211_vif_event_armed(cfg))
777 return -EBUSY;
778
779 if (ndev) {
780 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200781 cfg->escan_info.ifp == netdev_priv(ndev))
782 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
783 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100784
785 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
786 }
787
Arend van Spriel9f440b72013-02-08 15:53:36 +0100788 switch (wdev->iftype) {
789 case NL80211_IFTYPE_ADHOC:
790 case NL80211_IFTYPE_STATION:
791 case NL80211_IFTYPE_AP:
792 case NL80211_IFTYPE_AP_VLAN:
793 case NL80211_IFTYPE_WDS:
794 case NL80211_IFTYPE_MONITOR:
795 case NL80211_IFTYPE_MESH_POINT:
796 return -EOPNOTSUPP;
797 case NL80211_IFTYPE_P2P_CLIENT:
798 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200799 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100800 return brcmf_p2p_del_vif(wiphy, wdev);
801 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100802 default:
803 return -EINVAL;
804 }
805 return -EOPNOTSUPP;
806}
807
Arend van Spriel5b435de2011-10-05 13:19:03 +0200808static s32
809brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
810 enum nl80211_iftype type, u32 *flags,
811 struct vif_params *params)
812{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100813 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700814 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100815 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200816 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200817 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200818 s32 err = 0;
819
Hante Meuleman37a869e2015-10-29 20:33:17 +0100820 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
821 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200822
823 /* WAR: There are a number of p2p interface related problems which
824 * need to be handled initially (before doing the validate).
825 * wpa_supplicant tends to do iface changes on p2p device/client/go
826 * which are not always possible/allowed. However we need to return
827 * OK otherwise the wpa_supplicant wont start. The situation differs
828 * on configuration and setup (p2pon=1 module param). The first check
829 * is to see if the request is a change to station for p2p iface.
830 */
831 if ((type == NL80211_IFTYPE_STATION) &&
832 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
833 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
834 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
835 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
836 /* Now depending on whether module param p2pon=1 was used the
837 * response needs to be either 0 or EOPNOTSUPP. The reason is
838 * that if p2pon=1 is used, but a newer supplicant is used then
839 * we should return an error, as this combination wont work.
840 * In other situations 0 is returned and supplicant will start
841 * normally. It will give a trace in cfg80211, but it is the
842 * only way to get it working. Unfortunately this will result
843 * in situation where we wont support new supplicant in
844 * combination with module param p2pon=1, but that is the way
845 * it is. If the user tries this then unloading of driver might
846 * fail/lock.
847 */
848 if (cfg->p2p.p2pdev_dynamically)
849 return -EOPNOTSUPP;
850 else
851 return 0;
852 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200853 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
854 if (err) {
855 brcmf_err("iface validation failed: err=%d\n", err);
856 return err;
857 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200858 switch (type) {
859 case NL80211_IFTYPE_MONITOR:
860 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100861 brcmf_err("type (%d) : currently we do not support this type\n",
862 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200863 return -EOPNOTSUPP;
864 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200865 infra = 0;
866 break;
867 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200868 infra = 1;
869 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200870 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100871 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200872 ap = 1;
873 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200874 default:
875 err = -EINVAL;
876 goto done;
877 }
878
Hante Meuleman1a873342012-09-27 14:17:54 +0200879 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100880 if (type == NL80211_IFTYPE_P2P_GO) {
881 brcmf_dbg(INFO, "IF Type = P2P GO\n");
882 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
883 }
884 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100885 brcmf_dbg(INFO, "IF Type = AP\n");
886 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200887 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100888 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200889 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100890 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200891 err = -EAGAIN;
892 goto done;
893 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100894 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100895 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200896 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200897 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200898
Hante Meuleman8851cce2014-07-30 13:20:02 +0200899 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
900
Arend van Spriel5b435de2011-10-05 13:19:03 +0200901done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100902 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200903
904 return err;
905}
906
Franky Lin83cf17a2013-04-11 13:28:50 +0200907static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
908 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200909 struct cfg80211_scan_request *request)
910{
911 u32 n_ssids;
912 u32 n_channels;
913 s32 i;
914 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200915 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200916 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200917 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200918
Joe Perches93803b32015-03-02 19:54:49 -0800919 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200920 params_le->bss_type = DOT11_BSSTYPE_ANY;
921 params_le->scan_type = 0;
922 params_le->channel_num = 0;
923 params_le->nprobes = cpu_to_le32(-1);
924 params_le->active_time = cpu_to_le32(-1);
925 params_le->passive_time = cpu_to_le32(-1);
926 params_le->home_time = cpu_to_le32(-1);
927 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
928
929 /* if request is null exit so it will be all channel broadcast scan */
930 if (!request)
931 return;
932
933 n_ssids = request->n_ssids;
934 n_channels = request->n_channels;
935 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100936 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
937 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200938 if (n_channels > 0) {
939 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200940 chanspec = channel_to_chanspec(&cfg->d11inf,
941 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100942 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
943 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200944 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200945 }
946 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100947 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200948 }
949 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100950 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200951 if (n_ssids > 0) {
952 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
953 n_channels * sizeof(u16);
954 offset = roundup(offset, sizeof(u32));
955 ptr = (char *)params_le + offset;
956 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200957 memset(&ssid_le, 0, sizeof(ssid_le));
958 ssid_le.SSID_len =
959 cpu_to_le32(request->ssids[i].ssid_len);
960 memcpy(ssid_le.SSID, request->ssids[i].ssid,
961 request->ssids[i].ssid_len);
962 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100963 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200964 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100965 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
966 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200967 memcpy(ptr, &ssid_le, sizeof(ssid_le));
968 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200969 }
970 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100971 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200972 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100973 brcmf_dbg(SCAN, "SSID %s len=%d\n",
974 params_le->ssid_le.SSID,
975 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200976 params_le->ssid_le.SSID_len =
977 cpu_to_le32(request->ssids->ssid_len);
978 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
979 request->ssids->ssid_len);
980 }
981 }
982 /* Adding mask to channel numbers */
983 params_le->channel_num =
984 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
985 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
986}
987
988static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200989brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +0100990 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200991{
992 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
993 offsetof(struct brcmf_escan_params_le, params_le);
994 struct brcmf_escan_params_le *params;
995 s32 err = 0;
996
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100997 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200998
999 if (request != NULL) {
1000 /* Allocate space for populating ssids in struct */
1001 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1002
1003 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001004 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001005 }
1006
1007 params = kzalloc(params_size, GFP_KERNEL);
1008 if (!params) {
1009 err = -ENOMEM;
1010 goto exit;
1011 }
1012 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001013 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001014 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001015 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001016 params->sync_id = cpu_to_le16(0x1234);
1017
Arend van Spriela0f472a2013-04-05 10:57:49 +02001018 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001019 if (err) {
1020 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001021 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001022 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001023 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001024 }
1025
1026 kfree(params);
1027exit:
1028 return err;
1029}
1030
1031static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001032brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001033 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001034{
1035 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001036 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001037 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001038 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001039
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001040 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001041 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001042 escan->wiphy = wiphy;
1043 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001044 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001045 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001046 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001047 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001048 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001049 return err;
1050 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001051 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001052 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001053 results->version = 0;
1054 results->count = 0;
1055 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1056
Hante Meulemanc4958102015-11-25 11:32:41 +01001057 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001058 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001059 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001060 return err;
1061}
1062
1063static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001064brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001065 struct cfg80211_scan_request *request,
1066 struct cfg80211_ssid *this_ssid)
1067{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001068 struct brcmf_if *ifp = vif->ifp;
1069 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001070 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001071 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001072 bool escan_req;
1073 bool spec_scan;
1074 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001075 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001076 u32 SSID_len;
1077
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001078 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001079
Arend van Sprielc1179032012-10-22 13:55:33 -07001080 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001081 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001082 return -EAGAIN;
1083 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001084 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001085 brcmf_err("Scanning being aborted: status (%lu)\n",
1086 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001087 return -EAGAIN;
1088 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001089 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1090 brcmf_err("Scanning suppressed: status (%lu)\n",
1091 cfg->scan_status);
1092 return -EAGAIN;
1093 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001094 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001095 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001096 return -EAGAIN;
1097 }
1098
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001099 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001100 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1101 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001102
Hante Meulemane756af52012-09-11 21:18:52 +02001103 escan_req = false;
1104 if (request) {
1105 /* scan bss */
1106 ssids = request->ssids;
1107 escan_req = true;
1108 } else {
1109 /* scan in ibss */
1110 /* we don't do escan in ibss */
1111 ssids = this_ssid;
1112 }
1113
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001114 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001115 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001116 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001117 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001118 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001119 if (err)
1120 goto scan_out;
1121
Arend van Spriela0f472a2013-04-05 10:57:49 +02001122 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001123 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001124 goto scan_out;
1125 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001126 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1127 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001128 memset(&ssid_le, 0, sizeof(ssid_le));
1129 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1130 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001131 spec_scan = false;
1132 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001133 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1134 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001135 spec_scan = true;
1136 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001137 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001138
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001139 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001140 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001141 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001142 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001143 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001144 goto scan_out;
1145 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001146 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001147 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1148 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001149 if (err) {
1150 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001151 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001152 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001153 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001154 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001155
Daniel Kim5e787f72014-06-21 12:11:18 +02001156 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001157 goto scan_out;
1158 }
1159 }
1160
Hante Meuleman661fa952015-02-06 18:36:47 +01001161 /* Arm scan timeout timer */
1162 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001163 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001164
Hante Meulemane756af52012-09-11 21:18:52 +02001165 return 0;
1166
1167scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001168 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001169 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001170 return err;
1171}
1172
Arend van Spriel5b435de2011-10-05 13:19:03 +02001173static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001174brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001175{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001176 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001177 s32 err = 0;
1178
Arend van Sprield96b8012012-12-05 15:26:02 +01001179 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001180 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1181 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001182 return -EIO;
1183
Arend van Spriela0f472a2013-04-05 10:57:49 +02001184 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001185
Arend van Spriel5b435de2011-10-05 13:19:03 +02001186 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001187 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001188
Arend van Sprield96b8012012-12-05 15:26:02 +01001189 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001190 return err;
1191}
1192
1193static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1194{
1195 s32 err = 0;
1196
Arend van Sprielac24be62012-10-22 10:36:23 -07001197 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1198 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001200 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001201
1202 return err;
1203}
1204
1205static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1206{
1207 s32 err = 0;
1208
Arend van Sprielac24be62012-10-22 10:36:23 -07001209 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1210 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001212 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001213
1214 return err;
1215}
1216
1217static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1218{
1219 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001220 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001221
Arend van Sprielac24be62012-10-22 10:36:23 -07001222 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001223 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001224 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001225 return err;
1226 }
1227 return err;
1228}
1229
1230static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1231{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001232 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1233 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001234 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 s32 err = 0;
1236
Arend van Sprield96b8012012-12-05 15:26:02 +01001237 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001238 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 return -EIO;
1240
1241 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001242 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1243 cfg->conf->rts_threshold = wiphy->rts_threshold;
1244 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001245 if (!err)
1246 goto done;
1247 }
1248 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001249 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1250 cfg->conf->frag_threshold = wiphy->frag_threshold;
1251 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001252 if (!err)
1253 goto done;
1254 }
1255 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001256 && (cfg->conf->retry_long != wiphy->retry_long)) {
1257 cfg->conf->retry_long = wiphy->retry_long;
1258 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259 if (!err)
1260 goto done;
1261 }
1262 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001263 && (cfg->conf->retry_short != wiphy->retry_short)) {
1264 cfg->conf->retry_short = wiphy->retry_short;
1265 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001266 if (!err)
1267 goto done;
1268 }
1269
1270done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001271 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 return err;
1273}
1274
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1276{
1277 memset(prof, 0, sizeof(*prof));
1278}
1279
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001280static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1281{
1282 u16 reason;
1283
1284 switch (e->event_code) {
1285 case BRCMF_E_DEAUTH:
1286 case BRCMF_E_DEAUTH_IND:
1287 case BRCMF_E_DISASSOC_IND:
1288 reason = e->reason;
1289 break;
1290 case BRCMF_E_LINK:
1291 default:
1292 reason = 0;
1293 break;
1294 }
1295 return reason;
1296}
1297
1298static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001299{
Piotr Haber61730d42013-04-23 12:53:12 +02001300 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301 s32 err = 0;
1302
Arend van Sprield96b8012012-12-05 15:26:02 +01001303 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001304
Hante Meulemanb0a79082015-12-10 13:43:07 +01001305 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001306 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001307 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001308 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001309 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001310 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001311 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001312 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1313 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1314 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1315 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001316 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001317 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001318 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1319 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001320 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321}
1322
1323static s32
1324brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1325 struct cfg80211_ibss_params *params)
1326{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001327 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001328 struct brcmf_if *ifp = netdev_priv(ndev);
1329 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001330 struct brcmf_join_params join_params;
1331 size_t join_params_size = 0;
1332 s32 err = 0;
1333 s32 wsec = 0;
1334 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001335 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001336 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001337
Arend van Sprield96b8012012-12-05 15:26:02 +01001338 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001339 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001340 return -EIO;
1341
1342 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001343 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001344 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001345 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001346 return -EOPNOTSUPP;
1347 }
1348
Arend van Sprielc1179032012-10-22 13:55:33 -07001349 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001350
1351 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001352 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353 else
Arend van Spriel16886732012-12-05 15:26:04 +01001354 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001355
Johannes Berg683b6d32012-11-08 21:25:48 +01001356 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001357 brcmf_dbg(CONN, "channel: %d\n",
1358 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001359 else
Arend van Spriel16886732012-12-05 15:26:04 +01001360 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001361
1362 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001363 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001364 else
Arend van Spriel16886732012-12-05 15:26:04 +01001365 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001366
1367 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001368 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001369 else
Arend van Spriel16886732012-12-05 15:26:04 +01001370 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001371
1372 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001373 brcmf_dbg(CONN, "beacon interval: %d\n",
1374 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001375 else
Arend van Spriel16886732012-12-05 15:26:04 +01001376 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001377
1378 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001379 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001380 else
Arend van Spriel16886732012-12-05 15:26:04 +01001381 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001382
1383 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001384 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001385 else
Arend van Spriel16886732012-12-05 15:26:04 +01001386 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387
1388 /* Configure Privacy for starter */
1389 if (params->privacy)
1390 wsec |= WEP_ENABLED;
1391
Arend van Sprielc1179032012-10-22 13:55:33 -07001392 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001393 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001394 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001395 goto done;
1396 }
1397
1398 /* Configure Beacon Interval for starter */
1399 if (params->beacon_interval)
1400 bcnprd = params->beacon_interval;
1401 else
1402 bcnprd = 100;
1403
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001404 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001405 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001406 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001407 goto done;
1408 }
1409
1410 /* Configure required join parameter */
1411 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1412
1413 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001414 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1415 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1416 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001417 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418
1419 /* BSSID */
1420 if (params->bssid) {
1421 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001422 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001423 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001425 eth_broadcast_addr(join_params.params_le.bssid);
1426 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 }
1428
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001430 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431 u32 target_channel;
1432
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001433 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001434 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001435 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436 if (params->channel_fixed) {
1437 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001438 chanspec = chandef_to_chanspec(&cfg->d11inf,
1439 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001440 join_params.params_le.chanspec_list[0] =
1441 cpu_to_le16(chanspec);
1442 join_params.params_le.chanspec_num = cpu_to_le32(1);
1443 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001444 }
1445
1446 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001447 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001448 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001449 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001450 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001451 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 goto done;
1453 }
1454 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001455 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001457 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458
1459
Arend van Sprielc1179032012-10-22 13:55:33 -07001460 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001461 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001462 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001463 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001464 goto done;
1465 }
1466
1467done:
1468 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001469 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001470 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471 return err;
1472}
1473
1474static s32
1475brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1476{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001477 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001478
Arend van Sprield96b8012012-12-05 15:26:02 +01001479 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001480 if (!check_vif_up(ifp->vif)) {
1481 /* When driver is being unloaded, it can end up here. If an
1482 * error is returned then later on a debug trace in the wireless
1483 * core module will be printed. To avoid this 0 is returned.
1484 */
1485 return 0;
1486 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001488 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001489 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001490
Arend van Sprield96b8012012-12-05 15:26:02 +01001491 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001492
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001493 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494}
1495
1496static s32 brcmf_set_wpa_version(struct net_device *ndev,
1497 struct cfg80211_connect_params *sme)
1498{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001499 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001500 struct brcmf_cfg80211_security *sec;
1501 s32 val = 0;
1502 s32 err = 0;
1503
1504 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1505 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1506 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1507 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1508 else
1509 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001510 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001511 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001513 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001514 return err;
1515 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001516 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001517 sec->wpa_versions = sme->crypto.wpa_versions;
1518 return err;
1519}
1520
1521static s32 brcmf_set_auth_type(struct net_device *ndev,
1522 struct cfg80211_connect_params *sme)
1523{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001524 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001525 struct brcmf_cfg80211_security *sec;
1526 s32 val = 0;
1527 s32 err = 0;
1528
1529 switch (sme->auth_type) {
1530 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1531 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001532 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001533 break;
1534 case NL80211_AUTHTYPE_SHARED_KEY:
1535 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001536 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537 break;
1538 case NL80211_AUTHTYPE_AUTOMATIC:
1539 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001540 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001541 break;
1542 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001543 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001544 default:
1545 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001546 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001547 break;
1548 }
1549
Hante Meuleman89286dc2013-02-08 15:53:46 +01001550 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001552 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001553 return err;
1554 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001555 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001556 sec->auth_type = sme->auth_type;
1557 return err;
1558}
1559
1560static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001561brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001562 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001563{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001564 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001565 struct brcmf_cfg80211_security *sec;
1566 s32 pval = 0;
1567 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001568 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569 s32 err = 0;
1570
1571 if (sme->crypto.n_ciphers_pairwise) {
1572 switch (sme->crypto.ciphers_pairwise[0]) {
1573 case WLAN_CIPHER_SUITE_WEP40:
1574 case WLAN_CIPHER_SUITE_WEP104:
1575 pval = WEP_ENABLED;
1576 break;
1577 case WLAN_CIPHER_SUITE_TKIP:
1578 pval = TKIP_ENABLED;
1579 break;
1580 case WLAN_CIPHER_SUITE_CCMP:
1581 pval = AES_ENABLED;
1582 break;
1583 case WLAN_CIPHER_SUITE_AES_CMAC:
1584 pval = AES_ENABLED;
1585 break;
1586 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001587 brcmf_err("invalid cipher pairwise (%d)\n",
1588 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001589 return -EINVAL;
1590 }
1591 }
1592 if (sme->crypto.cipher_group) {
1593 switch (sme->crypto.cipher_group) {
1594 case WLAN_CIPHER_SUITE_WEP40:
1595 case WLAN_CIPHER_SUITE_WEP104:
1596 gval = WEP_ENABLED;
1597 break;
1598 case WLAN_CIPHER_SUITE_TKIP:
1599 gval = TKIP_ENABLED;
1600 break;
1601 case WLAN_CIPHER_SUITE_CCMP:
1602 gval = AES_ENABLED;
1603 break;
1604 case WLAN_CIPHER_SUITE_AES_CMAC:
1605 gval = AES_ENABLED;
1606 break;
1607 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001608 brcmf_err("invalid cipher group (%d)\n",
1609 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001610 return -EINVAL;
1611 }
1612 }
1613
Arend van Spriel16886732012-12-05 15:26:04 +01001614 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001615 /* In case of privacy, but no security and WPS then simulate */
1616 /* setting AES. WPS-2.0 allows no security */
1617 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1618 sme->privacy)
1619 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001620
Hante Meuleman240d61a2016-02-17 11:27:10 +01001621 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001622 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001624 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 return err;
1626 }
1627
Arend van Spriel06bb1232012-09-27 14:17:56 +02001628 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1630 sec->cipher_group = sme->crypto.cipher_group;
1631
1632 return err;
1633}
1634
1635static s32
1636brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1637{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001638 struct brcmf_if *ifp = netdev_priv(ndev);
1639 s32 val;
1640 s32 err;
1641 const struct brcmf_tlv *rsn_ie;
1642 const u8 *ie;
1643 u32 ie_len;
1644 u32 offset;
1645 u16 rsn_cap;
1646 u32 mfp;
1647 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001648
Hante Meuleman240d61a2016-02-17 11:27:10 +01001649 if (!sme->crypto.n_akm_suites)
1650 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001651
Hante Meuleman240d61a2016-02-17 11:27:10 +01001652 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1653 if (err) {
1654 brcmf_err("could not get wpa_auth (%d)\n", err);
1655 return err;
1656 }
1657 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1658 switch (sme->crypto.akm_suites[0]) {
1659 case WLAN_AKM_SUITE_8021X:
1660 val = WPA_AUTH_UNSPECIFIED;
1661 break;
1662 case WLAN_AKM_SUITE_PSK:
1663 val = WPA_AUTH_PSK;
1664 break;
1665 default:
1666 brcmf_err("invalid cipher group (%d)\n",
1667 sme->crypto.cipher_group);
1668 return -EINVAL;
1669 }
1670 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1671 switch (sme->crypto.akm_suites[0]) {
1672 case WLAN_AKM_SUITE_8021X:
1673 val = WPA2_AUTH_UNSPECIFIED;
1674 break;
1675 case WLAN_AKM_SUITE_8021X_SHA256:
1676 val = WPA2_AUTH_1X_SHA256;
1677 break;
1678 case WLAN_AKM_SUITE_PSK_SHA256:
1679 val = WPA2_AUTH_PSK_SHA256;
1680 break;
1681 case WLAN_AKM_SUITE_PSK:
1682 val = WPA2_AUTH_PSK;
1683 break;
1684 default:
1685 brcmf_err("invalid cipher group (%d)\n",
1686 sme->crypto.cipher_group);
1687 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001688 }
1689 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001690
1691 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1692 goto skip_mfp_config;
1693 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1694 * IE will not be verified, just a quick search for MFP config
1695 */
1696 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1697 WLAN_EID_RSN);
1698 if (!rsn_ie)
1699 goto skip_mfp_config;
1700 ie = (const u8 *)rsn_ie;
1701 ie_len = rsn_ie->len + TLV_HDR_LEN;
1702 /* Skip unicast suite */
1703 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1704 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1705 goto skip_mfp_config;
1706 /* Skip multicast suite */
1707 count = ie[offset] + (ie[offset + 1] << 8);
1708 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1709 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1710 goto skip_mfp_config;
1711 /* Skip auth key management suite(s) */
1712 count = ie[offset] + (ie[offset + 1] << 8);
1713 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1714 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1715 goto skip_mfp_config;
1716 /* Ready to read capabilities */
1717 mfp = BRCMF_MFP_NONE;
1718 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1719 if (rsn_cap & RSN_CAP_MFPR_MASK)
1720 mfp = BRCMF_MFP_REQUIRED;
1721 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1722 mfp = BRCMF_MFP_CAPABLE;
1723 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1724
1725skip_mfp_config:
1726 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1727 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1728 if (err) {
1729 brcmf_err("could not set wpa_auth (%d)\n", err);
1730 return err;
1731 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001732
1733 return err;
1734}
1735
1736static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001737brcmf_set_sharedkey(struct net_device *ndev,
1738 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001739{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001740 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001741 struct brcmf_cfg80211_security *sec;
1742 struct brcmf_wsec_key key;
1743 s32 val;
1744 s32 err = 0;
1745
Arend van Spriel16886732012-12-05 15:26:04 +01001746 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001747
Roland Vossena718e2f2011-10-12 20:51:24 +02001748 if (sme->key_len == 0)
1749 return 0;
1750
Arend van Spriel06bb1232012-09-27 14:17:56 +02001751 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001752 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1753 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001754
1755 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1756 return 0;
1757
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001758 if (!(sec->cipher_pairwise &
1759 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1760 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001761
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001762 memset(&key, 0, sizeof(key));
1763 key.len = (u32) sme->key_len;
1764 key.index = (u32) sme->key_idx;
1765 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001766 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001767 return -EINVAL;
1768 }
1769 memcpy(key.data, sme->key, key.len);
1770 key.flags = BRCMF_PRIMARY_KEY;
1771 switch (sec->cipher_pairwise) {
1772 case WLAN_CIPHER_SUITE_WEP40:
1773 key.algo = CRYPTO_ALGO_WEP1;
1774 break;
1775 case WLAN_CIPHER_SUITE_WEP104:
1776 key.algo = CRYPTO_ALGO_WEP128;
1777 break;
1778 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001779 brcmf_err("Invalid algorithm (%d)\n",
1780 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001781 return -EINVAL;
1782 }
1783 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001784 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1785 key.len, key.index, key.algo);
1786 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001787 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001788 if (err)
1789 return err;
1790
1791 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001792 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001793 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001794 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001795 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001796 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 }
1798 return err;
1799}
1800
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001801static
1802enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1803 enum nl80211_auth_type type)
1804{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001805 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1806 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1807 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1808 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001809 }
1810 return type;
1811}
1812
Arend van Spriel7705ba62016-04-17 16:44:58 +02001813static void brcmf_set_join_pref(struct brcmf_if *ifp,
1814 struct cfg80211_bss_selection *bss_select)
1815{
1816 struct brcmf_join_pref_params join_pref_params[2];
1817 enum nl80211_band band;
1818 int err, i = 0;
1819
1820 join_pref_params[i].len = 2;
1821 join_pref_params[i].rssi_gain = 0;
1822
1823 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1824 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1825
1826 switch (bss_select->behaviour) {
1827 case __NL80211_BSS_SELECT_ATTR_INVALID:
1828 brcmf_c_set_joinpref_default(ifp);
1829 return;
1830 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1831 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1832 band = bss_select->param.band_pref;
1833 join_pref_params[i].band = nl80211_band_to_fwil(band);
1834 i++;
1835 break;
1836 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1837 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1838 band = bss_select->param.adjust.band;
1839 join_pref_params[i].band = nl80211_band_to_fwil(band);
1840 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1841 i++;
1842 break;
1843 case NL80211_BSS_SELECT_ATTR_RSSI:
1844 default:
1845 break;
1846 }
1847 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1848 join_pref_params[i].len = 2;
1849 join_pref_params[i].rssi_gain = 0;
1850 join_pref_params[i].band = 0;
1851 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1852 sizeof(join_pref_params));
1853 if (err)
1854 brcmf_err("Set join_pref error (%d)\n", err);
1855}
1856
Arend van Spriel5b435de2011-10-05 13:19:03 +02001857static s32
1858brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001859 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001860{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001861 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001862 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001863 struct ieee80211_channel *chan = sme->channel;
1864 struct brcmf_join_params join_params;
1865 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001866 const struct brcmf_tlv *rsn_ie;
1867 const struct brcmf_vs_tlv *wpa_ie;
1868 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001869 u32 ie_len;
1870 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001871 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001872 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001873 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001874
Arend van Sprield96b8012012-12-05 15:26:02 +01001875 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001876 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001877 return -EIO;
1878
1879 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001880 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001881 return -EOPNOTSUPP;
1882 }
1883
Hante Meuleman89286dc2013-02-08 15:53:46 +01001884 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1885 /* A normal (non P2P) connection request setup. */
1886 ie = NULL;
1887 ie_len = 0;
1888 /* find the WPA_IE */
1889 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1890 if (wpa_ie) {
1891 ie = wpa_ie;
1892 ie_len = wpa_ie->len + TLV_HDR_LEN;
1893 } else {
1894 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001895 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1896 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001897 WLAN_EID_RSN);
1898 if (rsn_ie) {
1899 ie = rsn_ie;
1900 ie_len = rsn_ie->len + TLV_HDR_LEN;
1901 }
1902 }
1903 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1904 }
1905
1906 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1907 sme->ie, sme->ie_len);
1908 if (err)
1909 brcmf_err("Set Assoc REQ IE Failed\n");
1910 else
1911 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1912
Arend van Sprielc1179032012-10-22 13:55:33 -07001913 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001914
1915 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001916 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001918 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001919 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1920 cfg->channel, chan->center_freq, chanspec);
1921 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001922 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001923 chanspec = 0;
1924 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001925
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001926 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001927
1928 err = brcmf_set_wpa_version(ndev, sme);
1929 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001930 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001931 goto done;
1932 }
1933
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001934 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001935 err = brcmf_set_auth_type(ndev, sme);
1936 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001937 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001938 goto done;
1939 }
1940
Hante Meuleman240d61a2016-02-17 11:27:10 +01001941 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001942 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001943 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001944 goto done;
1945 }
1946
1947 err = brcmf_set_key_mgmt(ndev, sme);
1948 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001949 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950 goto done;
1951 }
1952
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001953 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001954 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001955 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001956 goto done;
1957 }
1958
Hante Meuleman89286dc2013-02-08 15:53:46 +01001959 /* Join with specific BSSID and cached SSID
1960 * If SSID is zero join based on BSSID only
1961 */
1962 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1963 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1964 if (cfg->channel)
1965 join_params_size += sizeof(u16);
1966 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1967 if (ext_join_params == NULL) {
1968 err = -ENOMEM;
1969 goto done;
1970 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001971 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1972 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1973 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1974 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1975 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1976 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001977
Hante Meuleman89286dc2013-02-08 15:53:46 +01001978 /* Set up join scan parameters */
1979 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001980 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1981
1982 if (sme->bssid)
1983 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1984 else
Joe Perches93803b32015-03-02 19:54:49 -08001985 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001986
1987 if (cfg->channel) {
1988 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1989
1990 ext_join_params->assoc_le.chanspec_list[0] =
1991 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001992 /* Increase dwell time to receive probe response or detect
1993 * beacon from target AP at a noisy air only during connect
1994 * command.
1995 */
1996 ext_join_params->scan_le.active_time =
1997 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1998 ext_join_params->scan_le.passive_time =
1999 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2000 /* To sync with presence period of VSDB GO send probe request
2001 * more frequently. Probe request will be stopped when it gets
2002 * probe response from target AP/GO.
2003 */
2004 ext_join_params->scan_le.nprobes =
2005 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2006 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2007 } else {
2008 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2009 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2010 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002011 }
2012
Arend van Spriel7705ba62016-04-17 16:44:58 +02002013 brcmf_set_join_pref(ifp, &sme->bss_select);
2014
Hante Meuleman89286dc2013-02-08 15:53:46 +01002015 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2016 join_params_size);
2017 kfree(ext_join_params);
2018 if (!err)
2019 /* This is it. join command worked, we are done */
2020 goto done;
2021
2022 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002023 memset(&join_params, 0, sizeof(join_params));
2024 join_params_size = sizeof(join_params.ssid_le);
2025
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002026 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2027 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002028
Hante Meuleman89286dc2013-02-08 15:53:46 +01002029 if (sme->bssid)
2030 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2031 else
Joe Perches93803b32015-03-02 19:54:49 -08002032 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002033
Hante Meuleman17012612013-02-06 18:40:44 +01002034 if (cfg->channel) {
2035 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2036 join_params.params_le.chanspec_num = cpu_to_le32(1);
2037 join_params_size += sizeof(join_params.params_le);
2038 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002039 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002040 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002041 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002042 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002043
2044done:
2045 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002046 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002047 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 return err;
2049}
2050
2051static s32
2052brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2053 u16 reason_code)
2054{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002055 struct brcmf_if *ifp = netdev_priv(ndev);
2056 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 struct brcmf_scb_val_le scbval;
2058 s32 err = 0;
2059
Arend van Sprield96b8012012-12-05 15:26:02 +01002060 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002061 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002062 return -EIO;
2063
Arend van Sprielc1179032012-10-22 13:55:33 -07002064 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002065 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002066 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067
Arend van Spriel06bb1232012-09-27 14:17:56 +02002068 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002070 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002071 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002073 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002074
Arend van Sprield96b8012012-12-05 15:26:02 +01002075 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002076 return err;
2077}
2078
2079static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002080brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002081 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002082{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002083 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002084 struct net_device *ndev = cfg_to_ndev(cfg);
2085 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002086 s32 err;
2087 s32 disable;
2088 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002090 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002091 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002092 return -EIO;
2093
2094 switch (type) {
2095 case NL80211_TX_POWER_AUTOMATIC:
2096 break;
2097 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002098 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002099 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002100 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002101 err = -EINVAL;
2102 goto done;
2103 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002104 qdbm = MBM_TO_DBM(4 * mbm);
2105 if (qdbm > 127)
2106 qdbm = 127;
2107 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002108 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002109 default:
2110 brcmf_err("Unsupported type %d\n", type);
2111 err = -EINVAL;
2112 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113 }
2114 /* Make sure radio is off or on as far as software is concerned */
2115 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002116 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002118 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002120 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002121 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002122 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123
2124done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002125 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002126 return err;
2127}
2128
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002129static s32
2130brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2131 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002133 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002134 struct net_device *ndev = cfg_to_ndev(cfg);
2135 struct brcmf_if *ifp = netdev_priv(ndev);
2136 s32 qdbm = 0;
2137 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002138
Arend van Sprield96b8012012-12-05 15:26:02 +01002139 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002140 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 return -EIO;
2142
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002143 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002145 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002146 goto done;
2147 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002148 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149
2150done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002151 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002152 return err;
2153}
2154
2155static s32
2156brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002157 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002158{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002159 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 u32 index;
2161 u32 wsec;
2162 s32 err = 0;
2163
Arend van Sprield96b8012012-12-05 15:26:02 +01002164 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002165 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002166 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 return -EIO;
2168
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002169 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002171 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002172 goto done;
2173 }
2174
2175 if (wsec & WEP_ENABLED) {
2176 /* Just select a new current key */
2177 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002178 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002179 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002180 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002181 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002182 }
2183done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002184 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002185 return err;
2186}
2187
2188static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002189brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2190 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002191{
Hante Meuleman992f6062013-04-02 21:06:17 +02002192 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002193 struct brcmf_wsec_key *key;
2194 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002195
2196 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002197 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2198
Hante Meuleman219e0f72016-02-17 11:27:09 +01002199 if (!check_vif_up(ifp->vif))
2200 return -EIO;
2201
2202 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2203 /* we ignore this key index in this case */
2204 return -EINVAL;
2205 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002206
Hante Meuleman240d61a2016-02-17 11:27:10 +01002207 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002208
Hante Meuleman240d61a2016-02-17 11:27:10 +01002209 if (key->algo == CRYPTO_ALGO_OFF) {
2210 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2211 return -EINVAL;
2212 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002213
Hante Meuleman240d61a2016-02-17 11:27:10 +01002214 memset(key, 0, sizeof(*key));
2215 key->index = (u32)key_idx;
2216 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217
Hante Meuleman240d61a2016-02-17 11:27:10 +01002218 /* Clear the key/index */
2219 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220
Hante Meuleman219e0f72016-02-17 11:27:09 +01002221 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002222 return err;
2223}
2224
2225static s32
2226brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002227 u8 key_idx, bool pairwise, const u8 *mac_addr,
2228 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002230 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002231 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 s32 val;
2233 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002234 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002235 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002236 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002237
Arend van Sprield96b8012012-12-05 15:26:02 +01002238 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002239 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002240 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002241 return -EIO;
2242
Hante Meuleman118eb302014-12-21 12:43:49 +01002243 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2244 /* we ignore this key index in this case */
2245 brcmf_err("invalid key index (%d)\n", key_idx);
2246 return -EINVAL;
2247 }
2248
Hante Meuleman219e0f72016-02-17 11:27:09 +01002249 if (params->key_len == 0)
2250 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2251 mac_addr);
2252
2253 if (params->key_len > sizeof(key->data)) {
2254 brcmf_err("Too long key length (%u)\n", params->key_len);
2255 return -EINVAL;
2256 }
2257
2258 ext_key = false;
2259 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2260 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2261 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2262 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002264
Hante Meuleman118eb302014-12-21 12:43:49 +01002265 key = &ifp->vif->profile.key[key_idx];
2266 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002267 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2268 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002269 key->len = params->key_len;
2270 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002271 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002272 if (!ext_key)
2273 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002274
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275 switch (params->cipher) {
2276 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002277 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002278 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002279 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002280 break;
2281 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002282 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002283 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002284 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002285 break;
2286 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002287 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002288 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002289 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2290 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2291 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002292 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002293 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002294 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002295 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002296 break;
2297 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002298 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002299 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002300 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 break;
2302 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002303 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002304 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002305 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306 break;
2307 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002308 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002309 err = -EINVAL;
2310 goto done;
2311 }
2312
Hante Meuleman118eb302014-12-21 12:43:49 +01002313 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002314 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002315 goto done;
2316
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002317 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002318 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002319 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002320 goto done;
2321 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002323 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002325 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002326 goto done;
2327 }
2328
Arend van Spriel5b435de2011-10-05 13:19:03 +02002329done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002330 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002331 return err;
2332}
2333
2334static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002335brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2336 bool pairwise, const u8 *mac_addr, void *cookie,
2337 void (*callback)(void *cookie,
2338 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002339{
2340 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002341 struct brcmf_if *ifp = netdev_priv(ndev);
2342 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002343 struct brcmf_cfg80211_security *sec;
2344 s32 wsec;
2345 s32 err = 0;
2346
Arend van Sprield96b8012012-12-05 15:26:02 +01002347 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002348 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002349 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002350 return -EIO;
2351
2352 memset(&params, 0, sizeof(params));
2353
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002354 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002355 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002356 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002357 /* Ignore this error, may happen during DISASSOC */
2358 err = -EAGAIN;
2359 goto done;
2360 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002361 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002362 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002363 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2364 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002365 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2367 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002368 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002370 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002372 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002373 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002374 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002375 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002376 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002377 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 err = -EINVAL;
2379 goto done;
2380 }
2381 callback(cookie, &params);
2382
2383done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002384 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002385 return err;
2386}
2387
2388static s32
2389brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002390 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002391{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002392 struct brcmf_if *ifp = netdev_priv(ndev);
2393
2394 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2395
2396 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2397 return 0;
2398
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002399 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400
2401 return -EOPNOTSUPP;
2402}
2403
Hante Meuleman118eb302014-12-21 12:43:49 +01002404static void
2405brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2406{
2407 s32 err;
2408 u8 key_idx;
2409 struct brcmf_wsec_key *key;
2410 s32 wsec;
2411
2412 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2413 key = &ifp->vif->profile.key[key_idx];
2414 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2415 (key->algo == CRYPTO_ALGO_WEP128))
2416 break;
2417 }
2418 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2419 return;
2420
2421 err = send_key_to_dongle(ifp, key);
2422 if (err) {
2423 brcmf_err("Setting WEP key failed (%d)\n", err);
2424 return;
2425 }
2426 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2427 if (err) {
2428 brcmf_err("get wsec error (%d)\n", err);
2429 return;
2430 }
2431 wsec |= WEP_ENABLED;
2432 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2433 if (err)
2434 brcmf_err("set wsec error (%d)\n", err);
2435}
2436
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002437static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2438{
2439 struct nl80211_sta_flag_update *sfu;
2440
2441 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2442 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2443 sfu = &si->sta_flags;
2444 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2445 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2446 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2447 BIT(NL80211_STA_FLAG_AUTHORIZED);
2448 if (fw_sta_flags & BRCMF_STA_WME)
2449 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2450 if (fw_sta_flags & BRCMF_STA_AUTHE)
2451 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2452 if (fw_sta_flags & BRCMF_STA_ASSOC)
2453 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2454 if (fw_sta_flags & BRCMF_STA_AUTHO)
2455 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2456}
2457
2458static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2459{
2460 struct {
2461 __le32 len;
2462 struct brcmf_bss_info_le bss_le;
2463 } *buf;
2464 u16 capability;
2465 int err;
2466
2467 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2468 if (!buf)
2469 return;
2470
2471 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2472 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2473 WL_BSS_INFO_MAX);
2474 if (err) {
2475 brcmf_err("Failed to get bss info (%d)\n", err);
2476 return;
2477 }
2478 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2479 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2480 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2481 capability = le16_to_cpu(buf->bss_le.capability);
2482 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2483 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2484 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2485 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2486 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2487 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2488}
2489
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002491brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2492 struct station_info *sinfo)
2493{
2494 struct brcmf_scb_val_le scbval;
2495 struct brcmf_pktcnt_le pktcnt;
2496 s32 err;
2497 u32 rate;
2498 u32 rssi;
2499
2500 /* Get the current tx rate */
2501 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2502 if (err < 0) {
2503 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2504 return err;
2505 }
2506 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2507 sinfo->txrate.legacy = rate * 5;
2508
2509 memset(&scbval, 0, sizeof(scbval));
2510 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2511 sizeof(scbval));
2512 if (err) {
2513 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2514 return err;
2515 }
2516 rssi = le32_to_cpu(scbval.val);
2517 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2518 sinfo->signal = rssi;
2519
2520 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2521 sizeof(pktcnt));
2522 if (err) {
2523 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2524 return err;
2525 }
2526 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2527 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2528 BIT(NL80211_STA_INFO_TX_PACKETS) |
2529 BIT(NL80211_STA_INFO_TX_FAILED);
2530 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2531 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2532 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2533 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2534
2535 return 0;
2536}
2537
2538static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002539brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002540 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002541{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002542 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002543 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002544 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002545 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002546 u32 sta_flags;
2547 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002548 s32 total_rssi;
2549 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002550 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002551 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002552
Arend van Sprield96b8012012-12-05 15:26:02 +01002553 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002554 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002555 return -EIO;
2556
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002557 if (brcmf_is_ibssmode(ifp->vif))
2558 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2559
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002560 memset(&sta_info_le, 0, sizeof(sta_info_le));
2561 memcpy(&sta_info_le, mac, ETH_ALEN);
2562 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2563 &sta_info_le,
2564 sizeof(sta_info_le));
2565 is_tdls_peer = !err;
2566 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002567 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002568 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002569 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002570 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002571 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002572 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002573 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002574 }
2575 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2576 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2577 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2578 sta_flags = le32_to_cpu(sta_info_le.flags);
2579 brcmf_convert_sta_flags(sta_flags, sinfo);
2580 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2581 if (is_tdls_peer)
2582 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2583 else
2584 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2585 if (sta_flags & BRCMF_STA_ASSOC) {
2586 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2587 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2588 brcmf_fill_bss_param(ifp, sinfo);
2589 }
2590 if (sta_flags & BRCMF_STA_SCBSTATS) {
2591 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2592 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2593 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2594 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2595 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2596 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2597 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2598 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2599 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002600 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002601 sinfo->txrate.legacy =
2602 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002603 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002604 if (sinfo->rx_packets) {
2605 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002606 sinfo->rxrate.legacy =
2607 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002608 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002609 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2610 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2611 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2612 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2613 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2614 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002615 total_rssi = 0;
2616 count_rssi = 0;
2617 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2618 if (sta_info_le.rssi[i]) {
2619 sinfo->chain_signal_avg[count_rssi] =
2620 sta_info_le.rssi[i];
2621 sinfo->chain_signal[count_rssi] =
2622 sta_info_le.rssi[i];
2623 total_rssi += sta_info_le.rssi[i];
2624 count_rssi++;
2625 }
2626 }
2627 if (count_rssi) {
2628 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2629 sinfo->chains = count_rssi;
2630
2631 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2632 total_rssi /= count_rssi;
2633 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002634 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2635 &ifp->vif->sme_state)) {
2636 memset(&scb_val, 0, sizeof(scb_val));
2637 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2638 &scb_val, sizeof(scb_val));
2639 if (err) {
2640 brcmf_err("Could not get rssi (%d)\n", err);
2641 goto done;
2642 } else {
2643 rssi = le32_to_cpu(scb_val.val);
2644 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2645 sinfo->signal = rssi;
2646 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2647 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002648 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002649 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002651 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002652 return err;
2653}
2654
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002655static int
2656brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2657 int idx, u8 *mac, struct station_info *sinfo)
2658{
2659 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2660 struct brcmf_if *ifp = netdev_priv(ndev);
2661 s32 err;
2662
2663 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2664
2665 if (idx == 0) {
2666 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2667 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2668 &cfg->assoclist,
2669 sizeof(cfg->assoclist));
2670 if (err) {
2671 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2672 err);
2673 cfg->assoclist.count = 0;
2674 return -EOPNOTSUPP;
2675 }
2676 }
2677 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2678 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2679 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2680 }
2681 return -ENOENT;
2682}
2683
Arend van Spriel5b435de2011-10-05 13:19:03 +02002684static s32
2685brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2686 bool enabled, s32 timeout)
2687{
2688 s32 pm;
2689 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002690 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002691 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002692
Arend van Sprield96b8012012-12-05 15:26:02 +01002693 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002694
2695 /*
2696 * Powersave enable/disable request is coming from the
2697 * cfg80211 even before the interface is up. In that
2698 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002699 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700 * FW later while initializing the dongle
2701 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002702 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002703 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002704
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002705 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002706 goto done;
2707 }
2708
2709 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002710 /* Do not enable the power save after assoc if it is a p2p interface */
2711 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2712 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2713 pm = PM_OFF;
2714 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002715 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002716
Arend van Sprielc1179032012-10-22 13:55:33 -07002717 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718 if (err) {
2719 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002720 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002721 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002722 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002723 }
2724done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002725 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002726 return err;
2727}
2728
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002729static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002730 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002731{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002732 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002733 struct ieee80211_channel *notify_channel;
2734 struct cfg80211_bss *bss;
2735 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002736 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002737 u16 channel;
2738 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739 u16 notify_capability;
2740 u16 notify_interval;
2741 u8 *notify_ie;
2742 size_t notify_ielen;
2743 s32 notify_signal;
2744
2745 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002746 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002747 return 0;
2748 }
2749
Franky Lin83cf17a2013-04-11 13:28:50 +02002750 if (!bi->ctl_ch) {
2751 ch.chspec = le16_to_cpu(bi->chanspec);
2752 cfg->d11inf.decchspec(&ch);
2753 bi->ctl_ch = ch.chnum;
2754 }
2755 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756
2757 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002758 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002759 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002760 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002761
2762 freq = ieee80211_channel_to_frequency(channel, band->band);
2763 notify_channel = ieee80211_get_channel(wiphy, freq);
2764
Arend van Spriel5b435de2011-10-05 13:19:03 +02002765 notify_capability = le16_to_cpu(bi->capability);
2766 notify_interval = le16_to_cpu(bi->beacon_period);
2767 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2768 notify_ielen = le32_to_cpu(bi->ie_length);
2769 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2770
Arend van Spriel16886732012-12-05 15:26:04 +01002771 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2772 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2773 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2774 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2775 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002776
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002777 bss = cfg80211_inform_bss(wiphy, notify_channel,
2778 CFG80211_BSS_FTYPE_UNKNOWN,
2779 (const u8 *)bi->BSSID,
2780 0, notify_capability,
2781 notify_interval, notify_ie,
2782 notify_ielen, notify_signal,
2783 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002784
Franky Line78946e2011-11-10 20:30:34 +01002785 if (!bss)
2786 return -ENOMEM;
2787
Johannes Berg5b112d32013-02-01 01:49:58 +01002788 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002789
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002790 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002791}
2792
Roland Vossen6f09be02011-10-18 14:03:02 +02002793static struct brcmf_bss_info_le *
2794next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2795{
2796 if (bss == NULL)
2797 return list->bss_info_le;
2798 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2799 le32_to_cpu(bss->length));
2800}
2801
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002802static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002803{
2804 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002805 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806 s32 err = 0;
2807 int i;
2808
Hante Meulemanef8596e2014-09-30 10:23:13 +02002809 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002810 if (bss_list->count != 0 &&
2811 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002812 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2813 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814 return -EOPNOTSUPP;
2815 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002816 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002817 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002818 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002819 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002820 if (err)
2821 break;
2822 }
2823 return err;
2824}
2825
Hante Meulemanb0a79082015-12-10 13:43:07 +01002826static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2827 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002828{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002829 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002831 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002832 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002833 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002834 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002835 u8 *buf = NULL;
2836 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002838 u16 notify_capability;
2839 u16 notify_interval;
2840 u8 *notify_ie;
2841 size_t notify_ielen;
2842 s32 notify_signal;
2843
Arend van Sprield96b8012012-12-05 15:26:02 +01002844 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845
2846 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2847 if (buf == NULL) {
2848 err = -ENOMEM;
2849 goto CleanUp;
2850 }
2851
2852 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2853
Arend van Sprielac24be62012-10-22 10:36:23 -07002854 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2855 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002857 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002858 goto CleanUp;
2859 }
2860
Roland Vossend34bf642011-10-18 14:03:01 +02002861 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002862
Franky Lin83cf17a2013-04-11 13:28:50 +02002863 ch.chspec = le16_to_cpu(bi->chanspec);
2864 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002865
Franky Lin83cf17a2013-04-11 13:28:50 +02002866 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002867 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002868 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002869 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002870
Franky Lin83cf17a2013-04-11 13:28:50 +02002871 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002872 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002873 notify_channel = ieee80211_get_channel(wiphy, freq);
2874
Arend van Spriel5b435de2011-10-05 13:19:03 +02002875 notify_capability = le16_to_cpu(bi->capability);
2876 notify_interval = le16_to_cpu(bi->beacon_period);
2877 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2878 notify_ielen = le32_to_cpu(bi->ie_length);
2879 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2880
Franky Lin83cf17a2013-04-11 13:28:50 +02002881 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002882 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2883 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2884 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002886 bss = cfg80211_inform_bss(wiphy, notify_channel,
2887 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2888 notify_capability, notify_interval,
2889 notify_ie, notify_ielen, notify_signal,
2890 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891
Franky Line78946e2011-11-10 20:30:34 +01002892 if (!bss) {
2893 err = -ENOMEM;
2894 goto CleanUp;
2895 }
2896
Johannes Berg5b112d32013-02-01 01:49:58 +01002897 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002898
Arend van Spriel5b435de2011-10-05 13:19:03 +02002899CleanUp:
2900
2901 kfree(buf);
2902
Arend van Sprield96b8012012-12-05 15:26:02 +01002903 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002904
2905 return err;
2906}
2907
Hante Meuleman89286dc2013-02-08 15:53:46 +01002908static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2909 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002910{
Roland Vossend34bf642011-10-18 14:03:01 +02002911 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002912 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002913 u16 beacon_interval;
2914 u8 dtim_period;
2915 size_t ie_len;
2916 u8 *ie;
2917 s32 err = 0;
2918
Arend van Sprield96b8012012-12-05 15:26:02 +01002919 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002920 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002921 return err;
2922
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002923 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002924 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002925 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002926 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002927 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002928 goto update_bss_info_out;
2929 }
2930
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002931 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2932 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002933 if (err)
2934 goto update_bss_info_out;
2935
2936 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2937 ie_len = le32_to_cpu(bi->ie_length);
2938 beacon_interval = le16_to_cpu(bi->beacon_period);
2939
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002940 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002941 if (tim)
2942 dtim_period = tim->data[1];
2943 else {
2944 /*
2945 * active scan was done so we could not get dtim
2946 * information out of probe response.
2947 * so we speficially query dtim information to dongle.
2948 */
2949 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002950 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002951 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002952 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002953 goto update_bss_info_out;
2954 }
2955 dtim_period = (u8)var;
2956 }
2957
Arend van Spriel5b435de2011-10-05 13:19:03 +02002958update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002959 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002960 return err;
2961}
2962
Hante Meuleman18e2f612013-02-08 15:53:49 +01002963void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002964{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002965 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002966
Arend van Sprielc1179032012-10-22 13:55:33 -07002967 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002968 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002969 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002970 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002971 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002972 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2973 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974}
2975
Hante Meulemane756af52012-09-11 21:18:52 +02002976static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2977{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002978 struct brcmf_cfg80211_info *cfg =
2979 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002980 escan_timeout_work);
2981
Hante Meulemanef8596e2014-09-30 10:23:13 +02002982 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002983 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002984}
2985
2986static void brcmf_escan_timeout(unsigned long data)
2987{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002988 struct brcmf_cfg80211_info *cfg =
2989 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002990
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002991 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002992 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002993 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002994 }
2995}
2996
2997static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002998brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2999 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003000 struct brcmf_bss_info_le *bss_info_le)
3001{
Franky Lin83cf17a2013-04-11 13:28:50 +02003002 struct brcmu_chan ch_bss, ch_bss_info_le;
3003
3004 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3005 cfg->d11inf.decchspec(&ch_bss);
3006 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3007 cfg->d11inf.decchspec(&ch_bss_info_le);
3008
Hante Meulemane756af52012-09-11 21:18:52 +02003009 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003010 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003011 bss_info_le->SSID_len == bss->SSID_len &&
3012 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003013 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3014 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003015 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3016 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3017
Hante Meulemane756af52012-09-11 21:18:52 +02003018 /* preserve max RSSI if the measurements are
3019 * both on-channel or both off-channel
3020 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003021 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003022 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003023 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3024 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003025 /* preserve the on-channel rssi measurement
3026 * if the new measurement is off channel
3027 */
3028 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003029 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003030 }
3031 return 1;
3032 }
3033 return 0;
3034}
3035
3036static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003037brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003038 const struct brcmf_event_msg *e, void *data)
3039{
Arend van Spriel19937322012-11-05 16:22:32 -08003040 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003041 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003042 struct brcmf_escan_result_le *escan_result_le;
3043 struct brcmf_bss_info_le *bss_info_le;
3044 struct brcmf_bss_info_le *bss = NULL;
3045 u32 bi_length;
3046 struct brcmf_scan_results *list;
3047 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003048 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003049
Arend van Spriel5c36b992012-11-14 18:46:05 -08003050 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003051
Arend van Spriela0f472a2013-04-05 10:57:49 +02003052 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003053 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003054 return -EPERM;
3055 }
3056
3057 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003058 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003059 escan_result_le = (struct brcmf_escan_result_le *) data;
3060 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003061 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003062 goto exit;
3063 }
Hante Meulemane756af52012-09-11 21:18:52 +02003064 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003065 brcmf_err("Invalid bss_count %d: ignoring\n",
3066 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003067 goto exit;
3068 }
3069 bss_info_le = &escan_result_le->bss_info_le;
3070
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003071 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3072 goto exit;
3073
3074 if (!cfg->scan_request) {
3075 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3076 goto exit;
3077 }
3078
Hante Meulemane756af52012-09-11 21:18:52 +02003079 bi_length = le32_to_cpu(bss_info_le->length);
3080 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3081 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003082 brcmf_err("Invalid bss_info length %d: ignoring\n",
3083 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003084 goto exit;
3085 }
3086
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003087 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003088 BIT(NL80211_IFTYPE_ADHOC))) {
3089 if (le16_to_cpu(bss_info_le->capability) &
3090 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003091 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003092 goto exit;
3093 }
3094 }
3095
3096 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003097 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003098 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003099 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003100 goto exit;
3101 }
3102
3103 for (i = 0; i < list->count; i++) {
3104 bss = bss ? (struct brcmf_bss_info_le *)
3105 ((unsigned char *)bss +
3106 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003107 if (brcmf_compare_update_same_bss(cfg, bss,
3108 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003109 goto exit;
3110 }
Hante Meulemand5367332016-02-17 11:26:51 +01003111 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3112 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003113 list->version = le32_to_cpu(bss_info_le->version);
3114 list->buflen += bi_length;
3115 list->count++;
3116 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003117 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003118 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3119 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003120 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003121 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003122 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003123 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003124 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003125 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3126 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003127 }
3128exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003129 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003130}
3131
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003132static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003133{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003134 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3135 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003136 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3137 /* Init scan_timeout timer */
3138 init_timer(&cfg->escan_timeout);
3139 cfg->escan_timeout.data = (unsigned long) cfg;
3140 cfg->escan_timeout.function = brcmf_escan_timeout;
3141 INIT_WORK(&cfg->escan_timeout_work,
3142 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003143}
3144
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003145/* PFN result doesn't have all the info which are required by the supplicant
3146 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3147 * via wl_inform_single_bss in the required format. Escan does require the
3148 * scan request in the form of cfg80211_scan_request. For timebeing, create
3149 * cfg80211_scan_request one out of the received PNO event.
3150 */
3151static s32
3152brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3153 const struct brcmf_event_msg *e, void *data)
3154{
3155 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3156 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3157 struct cfg80211_scan_request *request = NULL;
3158 struct cfg80211_ssid *ssid = NULL;
3159 struct ieee80211_channel *channel = NULL;
3160 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3161 int err = 0;
3162 int channel_req = 0;
3163 int band = 0;
3164 struct brcmf_pno_scanresults_le *pfn_result;
3165 u32 result_count;
3166 u32 status;
3167
3168 brcmf_dbg(SCAN, "Enter\n");
3169
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003170 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3171 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3172 return 0;
3173 }
3174
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003175 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3176 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3177 return 0;
3178 }
3179
3180 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3181 result_count = le32_to_cpu(pfn_result->count);
3182 status = le32_to_cpu(pfn_result->status);
3183
3184 /* PFN event is limited to fit 512 bytes so we may get
3185 * multiple NET_FOUND events. For now place a warning here.
3186 */
3187 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3188 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3189 if (result_count > 0) {
3190 int i;
3191
3192 request = kzalloc(sizeof(*request), GFP_KERNEL);
3193 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3194 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3195 if (!request || !ssid || !channel) {
3196 err = -ENOMEM;
3197 goto out_err;
3198 }
3199
3200 request->wiphy = wiphy;
3201 data += sizeof(struct brcmf_pno_scanresults_le);
3202 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3203
3204 for (i = 0; i < result_count; i++) {
3205 netinfo = &netinfo_start[i];
3206 if (!netinfo) {
3207 brcmf_err("Invalid netinfo ptr. index: %d\n",
3208 i);
3209 err = -EINVAL;
3210 goto out_err;
3211 }
3212
3213 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3214 netinfo->SSID, netinfo->channel);
3215 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3216 ssid[i].ssid_len = netinfo->SSID_len;
3217 request->n_ssids++;
3218
3219 channel_req = netinfo->channel;
3220 if (channel_req <= CH_MAX_2G_CHANNEL)
3221 band = NL80211_BAND_2GHZ;
3222 else
3223 band = NL80211_BAND_5GHZ;
3224 channel[i].center_freq =
3225 ieee80211_channel_to_frequency(channel_req,
3226 band);
3227 channel[i].band = band;
3228 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3229 request->channels[i] = &channel[i];
3230 request->n_channels++;
3231 }
3232
3233 /* assign parsed ssid array */
3234 if (request->n_ssids)
3235 request->ssids = &ssid[0];
3236
3237 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3238 /* Abort any on-going scan */
3239 brcmf_abort_scanning(cfg);
3240 }
3241
3242 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3243 cfg->escan_info.run = brcmf_run_escan;
3244 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3245 if (err) {
3246 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3247 goto out_err;
3248 }
3249 cfg->sched_escan = true;
3250 cfg->scan_request = request;
3251 } else {
3252 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3253 goto out_err;
3254 }
3255
3256 kfree(ssid);
3257 kfree(channel);
3258 kfree(request);
3259 return 0;
3260
3261out_err:
3262 kfree(ssid);
3263 kfree(channel);
3264 kfree(request);
3265 cfg80211_sched_scan_stopped(wiphy);
3266 return err;
3267}
3268
3269static int brcmf_dev_pno_clean(struct net_device *ndev)
3270{
3271 int ret;
3272
3273 /* Disable pfn */
3274 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3275 if (ret == 0) {
3276 /* clear pfn */
3277 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3278 NULL, 0);
3279 }
3280 if (ret < 0)
3281 brcmf_err("failed code %d\n", ret);
3282
3283 return ret;
3284}
3285
3286static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3287 struct cfg80211_sched_scan_request *request)
3288{
3289 struct brcmf_pno_param_le pfn_param;
3290 struct brcmf_pno_macaddr_le pfn_mac;
3291 s32 err;
3292 u8 *mac_mask;
3293 int i;
3294
3295 memset(&pfn_param, 0, sizeof(pfn_param));
3296 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3297
3298 /* set extra pno params */
3299 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3300 pfn_param.repeat = BRCMF_PNO_REPEAT;
3301 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3302
3303 /* set up pno scan fr */
3304 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3305
3306 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3307 sizeof(pfn_param));
3308 if (err) {
3309 brcmf_err("pfn_set failed, err=%d\n", err);
3310 return err;
3311 }
3312
3313 /* Find out if mac randomization should be turned on */
3314 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3315 return 0;
3316
3317 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3318 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3319
3320 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3321 mac_mask = request->mac_addr_mask;
3322 for (i = 0; i < ETH_ALEN; i++) {
3323 pfn_mac.mac[i] &= mac_mask[i];
3324 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3325 }
3326 /* Clear multi bit */
3327 pfn_mac.mac[0] &= 0xFE;
3328 /* Set locally administered */
3329 pfn_mac.mac[0] |= 0x02;
3330
3331 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3332 sizeof(pfn_mac));
3333 if (err)
3334 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3335
3336 return err;
3337}
3338
3339static int
3340brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3341 struct net_device *ndev,
3342 struct cfg80211_sched_scan_request *request)
3343{
3344 struct brcmf_if *ifp = netdev_priv(ndev);
3345 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3346 struct brcmf_pno_net_param_le pfn;
3347 int i;
3348 int ret = 0;
3349
3350 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3351 request->n_match_sets, request->n_ssids);
3352 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3353 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3354 return -EAGAIN;
3355 }
3356 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3357 brcmf_err("Scanning suppressed: status (%lu)\n",
3358 cfg->scan_status);
3359 return -EAGAIN;
3360 }
3361
3362 if (!request->n_ssids || !request->n_match_sets) {
3363 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3364 request->n_ssids);
3365 return -EINVAL;
3366 }
3367
3368 if (request->n_ssids > 0) {
3369 for (i = 0; i < request->n_ssids; i++) {
3370 /* Active scan req for ssids */
3371 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3372 request->ssids[i].ssid);
3373
3374 /* match_set ssids is a supert set of n_ssid list,
3375 * so we need not add these set separately.
3376 */
3377 }
3378 }
3379
3380 if (request->n_match_sets > 0) {
3381 /* clean up everything */
3382 ret = brcmf_dev_pno_clean(ndev);
3383 if (ret < 0) {
3384 brcmf_err("failed error=%d\n", ret);
3385 return ret;
3386 }
3387
3388 /* configure pno */
3389 if (brcmf_dev_pno_config(ifp, request))
3390 return -EINVAL;
3391
3392 /* configure each match set */
3393 for (i = 0; i < request->n_match_sets; i++) {
3394 struct cfg80211_ssid *ssid;
3395 u32 ssid_len;
3396
3397 ssid = &request->match_sets[i].ssid;
3398 ssid_len = ssid->ssid_len;
3399
3400 if (!ssid_len) {
3401 brcmf_err("skip broadcast ssid\n");
3402 continue;
3403 }
3404 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3405 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3406 pfn.wsec = cpu_to_le32(0);
3407 pfn.infra = cpu_to_le32(1);
3408 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3409 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3410 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3411 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3412 sizeof(pfn));
3413 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3414 ret == 0 ? "set" : "failed", ssid->ssid);
3415 }
3416 /* Enable the PNO */
3417 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3418 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3419 return -EINVAL;
3420 }
3421 } else {
3422 return -EINVAL;
3423 }
3424
3425 return 0;
3426}
3427
3428static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3429 struct net_device *ndev)
3430{
3431 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3432
3433 brcmf_dbg(SCAN, "enter\n");
3434 brcmf_dev_pno_clean(ndev);
3435 if (cfg->sched_escan)
3436 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3437 return 0;
3438}
3439
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003440static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003441{
3442 if (ms < 1000 / HZ) {
3443 cond_resched();
3444 mdelay(ms);
3445 } else {
3446 msleep(ms);
3447 }
3448}
3449
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003450static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3451 u8 *pattern, u32 patternsize, u8 *mask,
3452 u32 packet_offset)
3453{
3454 struct brcmf_fil_wowl_pattern_le *filter;
3455 u32 masksize;
3456 u32 patternoffset;
3457 u8 *buf;
3458 u32 bufsize;
3459 s32 ret;
3460
3461 masksize = (patternsize + 7) / 8;
3462 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3463
3464 bufsize = sizeof(*filter) + patternsize + masksize;
3465 buf = kzalloc(bufsize, GFP_KERNEL);
3466 if (!buf)
3467 return -ENOMEM;
3468 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3469
3470 memcpy(filter->cmd, cmd, 4);
3471 filter->masksize = cpu_to_le32(masksize);
3472 filter->offset = cpu_to_le32(packet_offset);
3473 filter->patternoffset = cpu_to_le32(patternoffset);
3474 filter->patternsize = cpu_to_le32(patternsize);
3475 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3476
3477 if ((mask) && (masksize))
3478 memcpy(buf + sizeof(*filter), mask, masksize);
3479 if ((pattern) && (patternsize))
3480 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3481
3482 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3483
3484 kfree(buf);
3485 return ret;
3486}
3487
Hante Meuleman3021ad92016-01-05 11:05:45 +01003488static s32
3489brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3490 void *data)
3491{
3492 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3493 struct brcmf_pno_scanresults_le *pfn_result;
3494 struct brcmf_pno_net_info_le *netinfo;
3495
3496 brcmf_dbg(SCAN, "Enter\n");
3497
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003498 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3499 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3500 return 0;
3501 }
3502
Hante Meuleman3021ad92016-01-05 11:05:45 +01003503 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3504
3505 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3506 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3507 return 0;
3508 }
3509
3510 if (le32_to_cpu(pfn_result->count) < 1) {
3511 brcmf_err("Invalid result count, expected 1 (%d)\n",
3512 le32_to_cpu(pfn_result->count));
3513 return -EINVAL;
3514 }
3515
3516 data += sizeof(struct brcmf_pno_scanresults_le);
3517 netinfo = (struct brcmf_pno_net_info_le *)data;
3518 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3519 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3520 cfg->wowl.nd->n_channels = 1;
3521 cfg->wowl.nd->channels[0] =
3522 ieee80211_channel_to_frequency(netinfo->channel,
3523 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3524 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3525 cfg->wowl.nd_info->n_matches = 1;
3526 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3527
3528 /* Inform (the resume task) that the net detect information was recvd */
3529 cfg->wowl.nd_data_completed = true;
3530 wake_up(&cfg->wowl.nd_data_wait);
3531
3532 return 0;
3533}
3534
Hante Meulemanaeb64222015-10-29 20:33:19 +01003535#ifdef CONFIG_PM
3536
3537static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3538{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003539 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003540 struct brcmf_wowl_wakeind_le wake_ind_le;
3541 struct cfg80211_wowlan_wakeup wakeup_data;
3542 struct cfg80211_wowlan_wakeup *wakeup;
3543 u32 wakeind;
3544 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003545 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003546
3547 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3548 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003549 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003550 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3551 return;
3552 }
3553
3554 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3555 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003556 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3557 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003558 wakeup = &wakeup_data;
3559 memset(&wakeup_data, 0, sizeof(wakeup_data));
3560 wakeup_data.pattern_idx = -1;
3561
3562 if (wakeind & BRCMF_WOWL_MAGIC) {
3563 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3564 wakeup_data.magic_pkt = true;
3565 }
3566 if (wakeind & BRCMF_WOWL_DIS) {
3567 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3568 wakeup_data.disconnect = true;
3569 }
3570 if (wakeind & BRCMF_WOWL_BCN) {
3571 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3572 wakeup_data.disconnect = true;
3573 }
3574 if (wakeind & BRCMF_WOWL_RETR) {
3575 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3576 wakeup_data.disconnect = true;
3577 }
3578 if (wakeind & BRCMF_WOWL_NET) {
3579 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3580 /* For now always map to pattern 0, no API to get
3581 * correct information available at the moment.
3582 */
3583 wakeup_data.pattern_idx = 0;
3584 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003585 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3586 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3587 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3588 cfg->wowl.nd_data_completed,
3589 BRCMF_ND_INFO_TIMEOUT);
3590 if (!timeout)
3591 brcmf_err("No result for wowl net detect\n");
3592 else
3593 wakeup_data.net_detect = cfg->wowl.nd_info;
3594 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003595 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3596 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3597 wakeup_data.gtk_rekey_failure = true;
3598 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003599 } else {
3600 wakeup = NULL;
3601 }
3602 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3603}
3604
3605#else
3606
3607static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3608{
3609}
3610
3611#endif /* CONFIG_PM */
3612
Arend van Spriel5b435de2011-10-05 13:19:03 +02003613static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3614{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003615 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3616 struct net_device *ndev = cfg_to_ndev(cfg);
3617 struct brcmf_if *ifp = netdev_priv(ndev);
3618
Arend van Sprield96b8012012-12-05 15:26:02 +01003619 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003620
Hante Meuleman3021ad92016-01-05 11:05:45 +01003621 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003622 brcmf_report_wowl_wakeind(wiphy, ifp);
3623 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3624 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003625 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3626 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003627 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003628 cfg->wowl.pre_pmmode);
3629 cfg->wowl.active = false;
3630 if (cfg->wowl.nd_enabled) {
3631 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3632 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3633 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3634 brcmf_notify_sched_scan_results);
3635 cfg->wowl.nd_enabled = false;
3636 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003637 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003638 return 0;
3639}
3640
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003641static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3642 struct brcmf_if *ifp,
3643 struct cfg80211_wowlan *wowl)
3644{
3645 u32 wowl_config;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003646 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003647
3648 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3649
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003650 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3651 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003652 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003653 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3654
3655 wowl_config = 0;
3656 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003657 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003658 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003659 wowl_config |= BRCMF_WOWL_MAGIC;
3660 if ((wowl->patterns) && (wowl->n_patterns)) {
3661 wowl_config |= BRCMF_WOWL_NET;
3662 for (i = 0; i < wowl->n_patterns; i++) {
3663 brcmf_config_wowl_pattern(ifp, "add",
3664 (u8 *)wowl->patterns[i].pattern,
3665 wowl->patterns[i].pattern_len,
3666 (u8 *)wowl->patterns[i].mask,
3667 wowl->patterns[i].pkt_offset);
3668 }
3669 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003670 if (wowl->nd_config) {
3671 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3672 wowl->nd_config);
3673 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3674
3675 cfg->wowl.nd_data_completed = false;
3676 cfg->wowl.nd_enabled = true;
3677 /* Now reroute the event for PFN to the wowl function. */
3678 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3679 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3680 brcmf_wowl_nd_results);
3681 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003682 if (wowl->gtk_rekey_failure)
3683 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003684 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3685 wowl_config |= BRCMF_WOWL_UNASSOC;
3686
Hante Meuleman28b285a2016-04-11 11:35:22 +02003687 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear",
3688 sizeof(struct brcmf_wowl_wakeind_le));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003689 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3690 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3691 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003692 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003693}
3694
Arend van Spriel5b435de2011-10-05 13:19:03 +02003695static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003696 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003697{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003698 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3699 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003700 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003701 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003702
Arend van Sprield96b8012012-12-05 15:26:02 +01003703 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003704
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003705 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003706 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003707 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003708 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003709 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003710
Hante Meuleman3021ad92016-01-05 11:05:45 +01003711 /* Stop scheduled scan */
3712 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3713 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3714
Arend van Spriel7d641072012-10-22 13:55:39 -07003715 /* end any scanning */
3716 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003717 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003718
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003719 if (wowl == NULL) {
3720 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3721 list_for_each_entry(vif, &cfg->vif_list, list) {
3722 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3723 continue;
3724 /* While going to suspend if associated with AP
3725 * disassociate from AP to save power while system is
3726 * in suspended state
3727 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003728 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003729 /* Make sure WPA_Supplicant receives all the event
3730 * generated due to DISASSOC call to the fw to keep
3731 * the state fw and WPA_Supplicant state consistent
3732 */
3733 brcmf_delay(500);
3734 }
3735 /* Configure MPC */
3736 brcmf_set_mpc(ifp, 1);
3737
3738 } else {
3739 /* Configure WOWL paramaters */
3740 brcmf_configure_wowl(cfg, ifp, wowl);
3741 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003742
Arend van Spriel7d641072012-10-22 13:55:39 -07003743exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003744 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003745 /* clear any scanning activity */
3746 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003747 return 0;
3748}
3749
3750static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003751brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003752{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003753 struct brcmf_pmk_list_le *pmk_list;
3754 int i;
3755 u32 npmk;
3756 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003757
Hante Meuleman6c404f32015-12-10 13:43:03 +01003758 pmk_list = &cfg->pmk_list;
3759 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003760
Hante Meuleman6c404f32015-12-10 13:43:03 +01003761 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3762 for (i = 0; i < npmk; i++)
3763 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003764
Hante Meuleman6c404f32015-12-10 13:43:03 +01003765 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3766 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003767
3768 return err;
3769}
3770
3771static s32
3772brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3773 struct cfg80211_pmksa *pmksa)
3774{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003775 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003776 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003777 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3778 s32 err;
3779 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780
Arend van Sprield96b8012012-12-05 15:26:02 +01003781 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003782 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003783 return -EIO;
3784
Hante Meuleman6c404f32015-12-10 13:43:03 +01003785 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3786 for (i = 0; i < npmk; i++)
3787 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003788 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003789 if (i < BRCMF_MAXPMKID) {
3790 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3791 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3792 if (i == npmk) {
3793 npmk++;
3794 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003795 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003796 } else {
3797 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3798 return -EINVAL;
3799 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003800
Hante Meuleman6c404f32015-12-10 13:43:03 +01003801 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3802 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3803 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3804 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3805 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003806
Hante Meuleman6c404f32015-12-10 13:43:03 +01003807 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003808
Arend van Sprield96b8012012-12-05 15:26:02 +01003809 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003810 return err;
3811}
3812
3813static s32
3814brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003815 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003816{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003817 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003818 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003819 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3820 s32 err;
3821 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003822
Arend van Sprield96b8012012-12-05 15:26:02 +01003823 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003824 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003825 return -EIO;
3826
Hante Meuleman6c404f32015-12-10 13:43:03 +01003827 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003828
Hante Meuleman6c404f32015-12-10 13:43:03 +01003829 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3830 for (i = 0; i < npmk; i++)
3831 if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003832 break;
3833
Hante Meuleman6c404f32015-12-10 13:43:03 +01003834 if ((npmk > 0) && (i < npmk)) {
3835 for (; i < (npmk - 1); i++) {
3836 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3837 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003838 WLAN_PMKID_LEN);
3839 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003840 memset(&pmk[i], 0, sizeof(*pmk));
3841 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3842 } else {
3843 brcmf_err("Cache entry not found\n");
3844 return -EINVAL;
3845 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003846
Hante Meuleman6c404f32015-12-10 13:43:03 +01003847 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003848
Arend van Sprield96b8012012-12-05 15:26:02 +01003849 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003850 return err;
3851
3852}
3853
3854static s32
3855brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3856{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003857 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003858 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003859 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003860
Arend van Sprield96b8012012-12-05 15:26:02 +01003861 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003862 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003863 return -EIO;
3864
Hante Meuleman6c404f32015-12-10 13:43:03 +01003865 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3866 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003867
Arend van Sprield96b8012012-12-05 15:26:02 +01003868 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003869 return err;
3870
3871}
3872
Hante Meuleman1f170112013-02-06 18:40:38 +01003873static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003874{
3875 s32 err;
3876
3877 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003878 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003879 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003880 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003881 return err;
3882 }
3883 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003884 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003885 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003886 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003887 return err;
3888 }
3889 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003890 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003891 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003892 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003893 return err;
3894 }
3895
3896 return 0;
3897}
3898
3899static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3900{
3901 if (is_rsn_ie)
3902 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3903
3904 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3905}
3906
3907static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003908brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003909 const struct brcmf_vs_tlv *wpa_ie,
3910 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003911{
3912 u32 auth = 0; /* d11 open authentication */
3913 u16 count;
3914 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003915 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003916 u32 i;
3917 u32 wsec;
3918 u32 pval = 0;
3919 u32 gval = 0;
3920 u32 wpa_auth = 0;
3921 u32 offset;
3922 u8 *data;
3923 u16 rsn_cap;
3924 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003925 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003926
Arend van Sprield96b8012012-12-05 15:26:02 +01003927 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003928 if (wpa_ie == NULL)
3929 goto exit;
3930
3931 len = wpa_ie->len + TLV_HDR_LEN;
3932 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003933 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003934 if (!is_rsn_ie)
3935 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003936 else
3937 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003938
3939 /* check for multicast cipher suite */
3940 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3941 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003942 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003943 goto exit;
3944 }
3945
3946 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3947 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003948 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003949 goto exit;
3950 }
3951 offset += TLV_OUI_LEN;
3952
3953 /* pick up multicast cipher */
3954 switch (data[offset]) {
3955 case WPA_CIPHER_NONE:
3956 gval = 0;
3957 break;
3958 case WPA_CIPHER_WEP_40:
3959 case WPA_CIPHER_WEP_104:
3960 gval = WEP_ENABLED;
3961 break;
3962 case WPA_CIPHER_TKIP:
3963 gval = TKIP_ENABLED;
3964 break;
3965 case WPA_CIPHER_AES_CCM:
3966 gval = AES_ENABLED;
3967 break;
3968 default:
3969 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003970 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003971 goto exit;
3972 }
3973
3974 offset++;
3975 /* walk thru unicast cipher list and pick up what we recognize */
3976 count = data[offset] + (data[offset + 1] << 8);
3977 offset += WPA_IE_SUITE_COUNT_LEN;
3978 /* Check for unicast suite(s) */
3979 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3980 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003981 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003982 goto exit;
3983 }
3984 for (i = 0; i < count; i++) {
3985 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3986 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003987 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 goto exit;
3989 }
3990 offset += TLV_OUI_LEN;
3991 switch (data[offset]) {
3992 case WPA_CIPHER_NONE:
3993 break;
3994 case WPA_CIPHER_WEP_40:
3995 case WPA_CIPHER_WEP_104:
3996 pval |= WEP_ENABLED;
3997 break;
3998 case WPA_CIPHER_TKIP:
3999 pval |= TKIP_ENABLED;
4000 break;
4001 case WPA_CIPHER_AES_CCM:
4002 pval |= AES_ENABLED;
4003 break;
4004 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004005 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 }
4007 offset++;
4008 }
4009 /* walk thru auth management suite list and pick up what we recognize */
4010 count = data[offset] + (data[offset + 1] << 8);
4011 offset += WPA_IE_SUITE_COUNT_LEN;
4012 /* Check for auth key management suite(s) */
4013 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4014 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004015 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004016 goto exit;
4017 }
4018 for (i = 0; i < count; i++) {
4019 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4020 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004021 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004022 goto exit;
4023 }
4024 offset += TLV_OUI_LEN;
4025 switch (data[offset]) {
4026 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004027 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004028 wpa_auth |= WPA_AUTH_NONE;
4029 break;
4030 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004031 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004032 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4033 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4034 break;
4035 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004036 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004037 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4038 (wpa_auth |= WPA_AUTH_PSK);
4039 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004040 case RSN_AKM_SHA256_PSK:
4041 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4042 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4043 break;
4044 case RSN_AKM_SHA256_1X:
4045 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4046 wpa_auth |= WPA2_AUTH_1X_SHA256;
4047 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004048 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004049 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004050 }
4051 offset++;
4052 }
4053
Hante Meuleman240d61a2016-02-17 11:27:10 +01004054 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004055 if (is_rsn_ie) {
4056 wme_bss_disable = 1;
4057 if ((offset + RSN_CAP_LEN) <= len) {
4058 rsn_cap = data[offset] + (data[offset + 1] << 8);
4059 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4060 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004061 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4062 brcmf_dbg(TRACE, "MFP Required\n");
4063 mfp = BRCMF_MFP_REQUIRED;
4064 /* Firmware only supports mfp required in
4065 * combination with WPA2_AUTH_PSK_SHA256 or
4066 * WPA2_AUTH_1X_SHA256.
4067 */
4068 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4069 WPA2_AUTH_1X_SHA256))) {
4070 err = -EINVAL;
4071 goto exit;
4072 }
4073 /* Firmware has requirement that WPA2_AUTH_PSK/
4074 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4075 * is to be included in the rsn ie.
4076 */
4077 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4078 wpa_auth |= WPA2_AUTH_PSK;
4079 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4080 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4081 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4082 brcmf_dbg(TRACE, "MFP Capable\n");
4083 mfp = BRCMF_MFP_CAPABLE;
4084 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004085 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004086 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004087 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004088 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004089 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004090 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004091 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004092 goto exit;
4093 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004094
4095 /* Skip PMKID cnt as it is know to be 0 for AP. */
4096 offset += RSN_PMKID_COUNT_LEN;
4097
4098 /* See if there is BIP wpa suite left for MFP */
4099 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4100 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4101 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4102 &data[offset],
4103 WPA_IE_MIN_OUI_LEN);
4104 if (err < 0) {
4105 brcmf_err("bip error %d\n", err);
4106 goto exit;
4107 }
4108 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004109 }
4110 /* FOR WPS , set SES_OW_ENABLED */
4111 wsec = (pval | gval | SES_OW_ENABLED);
4112
4113 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004114 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004115 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004116 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004117 goto exit;
4118 }
4119 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004120 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004121 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004122 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004123 goto exit;
4124 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004125 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4126 * will overwrite the values set by MFP
4127 */
4128 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4129 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4130 if (err < 0) {
4131 brcmf_err("mfp error %d\n", err);
4132 goto exit;
4133 }
4134 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004135 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004136 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004137 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004138 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004139 goto exit;
4140 }
4141
4142exit:
4143 return err;
4144}
4145
4146static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004147brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004148 struct parsed_vndr_ies *vndr_ies)
4149{
Hante Meuleman1a873342012-09-27 14:17:54 +02004150 struct brcmf_vs_tlv *vndrie;
4151 struct brcmf_tlv *ie;
4152 struct parsed_vndr_ie_info *parsed_info;
4153 s32 remaining_len;
4154
4155 remaining_len = (s32)vndr_ie_len;
4156 memset(vndr_ies, 0, sizeof(*vndr_ies));
4157
4158 ie = (struct brcmf_tlv *)vndr_ie_buf;
4159 while (ie) {
4160 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4161 goto next;
4162 vndrie = (struct brcmf_vs_tlv *)ie;
4163 /* len should be bigger than OUI length + one */
4164 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004165 brcmf_err("invalid vndr ie. length is too small %d\n",
4166 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004167 goto next;
4168 }
4169 /* if wpa or wme ie, do not add ie */
4170 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4171 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4172 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004173 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004174 goto next;
4175 }
4176
4177 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4178
4179 /* save vndr ie information */
4180 parsed_info->ie_ptr = (char *)vndrie;
4181 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4182 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4183
4184 vndr_ies->count++;
4185
Arend van Sprield96b8012012-12-05 15:26:02 +01004186 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4187 parsed_info->vndrie.oui[0],
4188 parsed_info->vndrie.oui[1],
4189 parsed_info->vndrie.oui[2],
4190 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004191
Arend van Spriel9f440b72013-02-08 15:53:36 +01004192 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004193 break;
4194next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004195 remaining_len -= (ie->len + TLV_HDR_LEN);
4196 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004197 ie = NULL;
4198 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004199 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4200 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004201 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004202 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004203}
4204
4205static u32
4206brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4207{
4208
Hante Meuleman1a873342012-09-27 14:17:54 +02004209 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4210 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4211
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304212 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004213
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304214 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004215
4216 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4217
4218 return ie_len + VNDR_IE_HDR_SIZE;
4219}
4220
Arend van Spriel1332e262012-11-05 16:22:18 -08004221s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4222 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004223{
Arend van Spriel1332e262012-11-05 16:22:18 -08004224 struct brcmf_if *ifp;
4225 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004226 s32 err = 0;
4227 u8 *iovar_ie_buf;
4228 u8 *curr_ie_buf;
4229 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004230 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004231 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004232 u32 del_add_ie_buf_len = 0;
4233 u32 total_ie_buf_len = 0;
4234 u32 parsed_ie_buf_len = 0;
4235 struct parsed_vndr_ies old_vndr_ies;
4236 struct parsed_vndr_ies new_vndr_ies;
4237 struct parsed_vndr_ie_info *vndrie_info;
4238 s32 i;
4239 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004240 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004241
Arend van Spriel1332e262012-11-05 16:22:18 -08004242 if (!vif)
4243 return -ENODEV;
4244 ifp = vif->ifp;
4245 saved_ie = &vif->saved_ie;
4246
Hante Meuleman37a869e2015-10-29 20:33:17 +01004247 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4248 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004249 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4250 if (!iovar_ie_buf)
4251 return -ENOMEM;
4252 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004253 switch (pktflag) {
4254 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4255 mgmt_ie_buf = saved_ie->probe_req_ie;
4256 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4257 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4258 break;
4259 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4260 mgmt_ie_buf = saved_ie->probe_res_ie;
4261 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4262 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4263 break;
4264 case BRCMF_VNDR_IE_BEACON_FLAG:
4265 mgmt_ie_buf = saved_ie->beacon_ie;
4266 mgmt_ie_len = &saved_ie->beacon_ie_len;
4267 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4268 break;
4269 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4270 mgmt_ie_buf = saved_ie->assoc_req_ie;
4271 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4272 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4273 break;
4274 default:
4275 err = -EPERM;
4276 brcmf_err("not suitable type\n");
4277 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004278 }
4279
4280 if (vndr_ie_len > mgmt_ie_buf_len) {
4281 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004282 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004283 goto exit;
4284 }
4285
4286 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4287 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4288 ptr = curr_ie_buf;
4289 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4290 for (i = 0; i < new_vndr_ies.count; i++) {
4291 vndrie_info = &new_vndr_ies.ie_info[i];
4292 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4293 vndrie_info->ie_len);
4294 parsed_ie_buf_len += vndrie_info->ie_len;
4295 }
4296 }
4297
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004298 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004299 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4300 (memcmp(mgmt_ie_buf, curr_ie_buf,
4301 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004302 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004303 goto exit;
4304 }
4305
4306 /* parse old vndr_ie */
4307 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4308
4309 /* make a command to delete old ie */
4310 for (i = 0; i < old_vndr_ies.count; i++) {
4311 vndrie_info = &old_vndr_ies.ie_info[i];
4312
Arend van Sprield96b8012012-12-05 15:26:02 +01004313 brcmf_dbg(TRACE, "DEL 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 "del");
4324 curr_ie_buf += del_add_ie_buf_len;
4325 total_ie_buf_len += del_add_ie_buf_len;
4326 }
4327 }
4328
4329 *mgmt_ie_len = 0;
4330 /* Add if there is any extra IE */
4331 if (mgmt_ie_buf && parsed_ie_buf_len) {
4332 ptr = mgmt_ie_buf;
4333
4334 remained_buf_len = mgmt_ie_buf_len;
4335
4336 /* make a command to add new ie */
4337 for (i = 0; i < new_vndr_ies.count; i++) {
4338 vndrie_info = &new_vndr_ies.ie_info[i];
4339
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004340 /* verify remained buf size before copy data */
4341 if (remained_buf_len < (vndrie_info->vndrie.len +
4342 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004343 brcmf_err("no space in mgmt_ie_buf: len left %d",
4344 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004345 break;
4346 }
4347 remained_buf_len -= (vndrie_info->ie_len +
4348 VNDR_IE_VSIE_OFFSET);
4349
Arend van Sprield96b8012012-12-05 15:26:02 +01004350 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4351 vndrie_info->vndrie.id,
4352 vndrie_info->vndrie.len,
4353 vndrie_info->vndrie.oui[0],
4354 vndrie_info->vndrie.oui[1],
4355 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004356
4357 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4358 vndrie_info->ie_ptr,
4359 vndrie_info->ie_len,
4360 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004361
4362 /* save the parsed IE in wl struct */
4363 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4364 vndrie_info->ie_len);
4365 *mgmt_ie_len += vndrie_info->ie_len;
4366
4367 curr_ie_buf += del_add_ie_buf_len;
4368 total_ie_buf_len += del_add_ie_buf_len;
4369 }
4370 }
4371 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004372 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004373 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004374 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004375 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004376 }
4377
4378exit:
4379 kfree(iovar_ie_buf);
4380 return err;
4381}
4382
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004383s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4384{
4385 s32 pktflags[] = {
4386 BRCMF_VNDR_IE_PRBREQ_FLAG,
4387 BRCMF_VNDR_IE_PRBRSP_FLAG,
4388 BRCMF_VNDR_IE_BEACON_FLAG
4389 };
4390 int i;
4391
4392 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4393 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4394
4395 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4396 return 0;
4397}
4398
Hante Meuleman1a873342012-09-27 14:17:54 +02004399static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004400brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4401 struct cfg80211_beacon_data *beacon)
4402{
4403 s32 err;
4404
4405 /* Set Beacon IEs to FW */
4406 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4407 beacon->tail, beacon->tail_len);
4408 if (err) {
4409 brcmf_err("Set Beacon IE Failed\n");
4410 return err;
4411 }
4412 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4413
4414 /* Set Probe Response IEs to FW */
4415 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4416 beacon->proberesp_ies,
4417 beacon->proberesp_ies_len);
4418 if (err)
4419 brcmf_err("Set Probe Resp IE Failed\n");
4420 else
4421 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4422
4423 return err;
4424}
4425
4426static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004427brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4428 struct cfg80211_ap_settings *settings)
4429{
4430 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004431 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004432 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004433 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004434 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004435 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004436 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004437 const struct brcmf_tlv *rsn_ie;
4438 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004439 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004440 enum nl80211_iftype dev_role;
4441 struct brcmf_fil_bss_enable_le bss_enable;
Arend van Spriel06c01582014-05-12 10:47:37 +02004442 u16 chanspec;
Hante Meulemana44aa402014-12-03 21:05:33 +01004443 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004444 int is_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004445
Arend van Spriel06c01582014-05-12 10:47:37 +02004446 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4447 settings->chandef.chan->hw_value,
4448 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004449 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004450 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4451 settings->ssid, settings->ssid_len, settings->auth_type,
4452 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004453 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004454 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004455
Arend van Spriel98027762014-12-21 12:43:53 +01004456 /* store current 11d setting */
4457 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4458 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4459 settings->beacon.tail_len,
4460 WLAN_EID_COUNTRY);
4461 is_11d = country_ie ? 1 : 0;
4462
Hante Meuleman1a873342012-09-27 14:17:54 +02004463 memset(&ssid_le, 0, sizeof(ssid_le));
4464 if (settings->ssid == NULL || settings->ssid_len == 0) {
4465 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4466 ssid_ie = brcmf_parse_tlvs(
4467 (u8 *)&settings->beacon.head[ie_offset],
4468 settings->beacon.head_len - ie_offset,
4469 WLAN_EID_SSID);
4470 if (!ssid_ie)
4471 return -EINVAL;
4472
4473 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4474 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004475 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004476 } else {
4477 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4478 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4479 }
4480
Hante Meulemana44aa402014-12-03 21:05:33 +01004481 if (!mbss) {
4482 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004483 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004484 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004485
4486 /* find the RSN_IE */
4487 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4488 settings->beacon.tail_len, WLAN_EID_RSN);
4489
4490 /* find the WPA_IE */
4491 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4492 settings->beacon.tail_len);
4493
Hante Meuleman1a873342012-09-27 14:17:54 +02004494 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004495 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004496 if (wpa_ie != NULL) {
4497 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004498 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004499 if (err < 0)
4500 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004501 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004502 struct brcmf_vs_tlv *tmp_ie;
4503
4504 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4505
Hante Meuleman1a873342012-09-27 14:17:54 +02004506 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004507 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004508 if (err < 0)
4509 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004510 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004511 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004512 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004513 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004514 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004515
Hante Meulemana0f07952013-02-08 15:53:47 +01004516 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004517
Hante Meulemana44aa402014-12-03 21:05:33 +01004518 if (!mbss) {
4519 chanspec = chandef_to_chanspec(&cfg->d11inf,
4520 &settings->chandef);
4521 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004522 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004523 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4524 chanspec, err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004525 goto exit;
4526 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004527
Arend van Spriel98027762014-12-21 12:43:53 +01004528 if (is_11d != ifp->vif->is_11d) {
4529 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4530 is_11d);
4531 if (err < 0) {
4532 brcmf_err("Regulatory Set Error, %d\n", err);
4533 goto exit;
4534 }
4535 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004536 if (settings->beacon_interval) {
4537 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4538 settings->beacon_interval);
4539 if (err < 0) {
4540 brcmf_err("Beacon Interval Set Error, %d\n",
4541 err);
4542 goto exit;
4543 }
4544 }
4545 if (settings->dtim_period) {
4546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4547 settings->dtim_period);
4548 if (err < 0) {
4549 brcmf_err("DTIM Interval Set Error, %d\n", err);
4550 goto exit;
4551 }
4552 }
4553
Hante Meuleman8abffd82015-10-29 20:33:16 +01004554 if ((dev_role == NL80211_IFTYPE_AP) &&
4555 ((ifp->ifidx == 0) ||
4556 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004557 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4558 if (err < 0) {
4559 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4560 goto exit;
4561 }
4562 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4563 }
4564
4565 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004566 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004567 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004568 goto exit;
4569 }
Arend van Spriel98027762014-12-21 12:43:53 +01004570 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4571 /* Multiple-BSS should use same 11d configuration */
4572 err = -EINVAL;
4573 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004574 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004575 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004576 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4577 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4578
Hante Meulemana0f07952013-02-08 15:53:47 +01004579 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4580 if (err < 0) {
4581 brcmf_err("setting AP mode failed %d\n", err);
4582 goto exit;
4583 }
4584 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4585 if (err < 0) {
4586 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4587 goto exit;
4588 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004589 /* On DOWN the firmware removes the WEP keys, reconfigure
4590 * them if they were set.
4591 */
4592 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004593
4594 memset(&join_params, 0, sizeof(join_params));
4595 /* join parameters starts with ssid */
4596 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4597 /* create softap */
4598 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4599 &join_params, sizeof(join_params));
4600 if (err < 0) {
4601 brcmf_err("SET SSID error (%d)\n", err);
4602 goto exit;
4603 }
4604 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4605 } else {
4606 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4607 sizeof(ssid_le));
4608 if (err < 0) {
4609 brcmf_err("setting ssid failed %d\n", err);
4610 goto exit;
4611 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004612 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004613 bss_enable.enable = cpu_to_le32(1);
4614 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4615 sizeof(bss_enable));
4616 if (err < 0) {
4617 brcmf_err("bss_enable config failed %d\n", err);
4618 goto exit;
4619 }
4620
4621 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4622 }
Arend van Sprielc1179032012-10-22 13:55:33 -07004623 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004624 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004625
4626exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004627 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004628 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004629 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004630 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004631 return err;
4632}
4633
4634static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4635{
Arend van Sprielc1179032012-10-22 13:55:33 -07004636 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004637 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004638 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004639 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004640
Arend van Sprield96b8012012-12-05 15:26:02 +01004641 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004642
Hante Meuleman426d0a52013-02-08 15:53:53 +01004643 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004644 /* Due to most likely deauths outstanding we sleep */
4645 /* first to make sure they get processed by fw. */
4646 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004647
Hante Meulemana44aa402014-12-03 21:05:33 +01004648 if (ifp->vif->mbss) {
4649 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4650 return err;
4651 }
4652
Hante Meuleman5c33a942013-04-02 21:06:18 +02004653 memset(&join_params, 0, sizeof(join_params));
4654 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4655 &join_params, sizeof(join_params));
4656 if (err < 0)
4657 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004658 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004659 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004660 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004661 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4662 if (err < 0)
4663 brcmf_err("setting AP mode failed %d\n", err);
4664 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4665 if (err < 0)
4666 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004667 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4668 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Arend van Spriel98027762014-12-21 12:43:53 +01004669 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4670 ifp->vif->is_11d);
4671 if (err < 0)
4672 brcmf_err("restoring REGULATORY setting failed %d\n",
4673 err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004674 /* Bring device back up so it can be used again */
4675 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4676 if (err < 0)
4677 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004678 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004679 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004680 bss_enable.enable = cpu_to_le32(0);
4681 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4682 sizeof(bss_enable));
4683 if (err < 0)
4684 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004685 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004686 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004687 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004688 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004689 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004690
Hante Meuleman1a873342012-09-27 14:17:54 +02004691 return err;
4692}
4693
Hante Meulemana0f07952013-02-08 15:53:47 +01004694static s32
4695brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4696 struct cfg80211_beacon_data *info)
4697{
Hante Meulemana0f07952013-02-08 15:53:47 +01004698 struct brcmf_if *ifp = netdev_priv(ndev);
4699 s32 err;
4700
4701 brcmf_dbg(TRACE, "Enter\n");
4702
Hante Meulemana0f07952013-02-08 15:53:47 +01004703 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4704
4705 return err;
4706}
4707
Hante Meuleman1a873342012-09-27 14:17:54 +02004708static int
4709brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004710 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004711{
Hante Meulemana0f07952013-02-08 15:53:47 +01004712 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004713 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004714 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004715 s32 err;
4716
Jouni Malinen89c771e2014-10-10 20:52:40 +03004717 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004718 return -EFAULT;
4719
Jouni Malinen89c771e2014-10-10 20:52:40 +03004720 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004721
Hante Meulemana0f07952013-02-08 15:53:47 +01004722 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4723 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004724 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004725 return -EIO;
4726
Jouni Malinen89c771e2014-10-10 20:52:40 +03004727 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004728 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004729 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004730 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004731 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004732 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004733
Arend van Sprield96b8012012-12-05 15:26:02 +01004734 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004735 return err;
4736}
4737
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004738static int
4739brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4740 const u8 *mac, struct station_parameters *params)
4741{
4742 struct brcmf_if *ifp = netdev_priv(ndev);
4743 s32 err;
4744
4745 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4746 params->sta_flags_mask, params->sta_flags_set);
4747
4748 /* Ignore all 00 MAC */
4749 if (is_zero_ether_addr(mac))
4750 return 0;
4751
4752 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4753 return 0;
4754
4755 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4756 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4757 (void *)mac, ETH_ALEN);
4758 else
4759 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4760 (void *)mac, ETH_ALEN);
4761 if (err < 0)
4762 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4763
4764 return err;
4765}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004766
4767static void
4768brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4769 struct wireless_dev *wdev,
4770 u16 frame_type, bool reg)
4771{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004772 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004773 u16 mgmt_type;
4774
4775 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4776
4777 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004778 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004779 if (reg)
4780 vif->mgmt_rx_reg |= BIT(mgmt_type);
4781 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004782 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004783}
4784
4785
4786static int
4787brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004788 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004789{
4790 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004791 struct ieee80211_channel *chan = params->chan;
4792 const u8 *buf = params->buf;
4793 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004794 const struct ieee80211_mgmt *mgmt;
4795 struct brcmf_cfg80211_vif *vif;
4796 s32 err = 0;
4797 s32 ie_offset;
4798 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004799 struct brcmf_fil_action_frame_le *action_frame;
4800 struct brcmf_fil_af_params_le *af_params;
4801 bool ack;
4802 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004803 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004804
4805 brcmf_dbg(TRACE, "Enter\n");
4806
4807 *cookie = 0;
4808
4809 mgmt = (const struct ieee80211_mgmt *)buf;
4810
Hante Meulemana0f07952013-02-08 15:53:47 +01004811 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4812 brcmf_err("Driver only allows MGMT packet type\n");
4813 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004814 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004815
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004816 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4817
Hante Meulemana0f07952013-02-08 15:53:47 +01004818 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4819 /* Right now the only reason to get a probe response */
4820 /* is for p2p listen response or for p2p GO from */
4821 /* wpa_supplicant. Unfortunately the probe is send */
4822 /* on primary ndev, while dongle wants it on the p2p */
4823 /* vif. Since this is only reason for a probe */
4824 /* response to be sent, the vif is taken from cfg. */
4825 /* If ever desired to send proberesp for non p2p */
4826 /* response then data should be checked for */
4827 /* "DIRECT-". Note in future supplicant will take */
4828 /* dedicated p2p wdev to do this and then this 'hack'*/
4829 /* is not needed anymore. */
4830 ie_offset = DOT11_MGMT_HDR_LEN +
4831 DOT11_BCN_PRB_FIXED_LEN;
4832 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004833 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4834 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4835 err = brcmf_vif_set_mgmt_ie(vif,
4836 BRCMF_VNDR_IE_PRBRSP_FLAG,
4837 &buf[ie_offset],
4838 ie_len);
4839 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4840 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004841 } else if (ieee80211_is_action(mgmt->frame_control)) {
4842 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4843 if (af_params == NULL) {
4844 brcmf_err("unable to allocate frame\n");
4845 err = -ENOMEM;
4846 goto exit;
4847 }
4848 action_frame = &af_params->action_frame;
4849 /* Add the packet Id */
4850 action_frame->packet_id = cpu_to_le32(*cookie);
4851 /* Add BSSID */
4852 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4853 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4854 /* Add the length exepted for 802.11 header */
4855 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004856 /* Add the channel. Use the one specified as parameter if any or
4857 * the current one (got from the firmware) otherwise
4858 */
4859 if (chan)
4860 freq = chan->center_freq;
4861 else
4862 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4863 &freq);
4864 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004865 af_params->channel = cpu_to_le32(chan_nr);
4866
4867 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4868 le16_to_cpu(action_frame->len));
4869
4870 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004871 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004872
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004873 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004874 af_params);
4875
4876 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4877 GFP_KERNEL);
4878 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004879 } else {
4880 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4881 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4882 }
4883
Hante Meuleman18e2f612013-02-08 15:53:49 +01004884exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004885 return err;
4886}
4887
4888
4889static int
4890brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4891 struct wireless_dev *wdev,
4892 u64 cookie)
4893{
4894 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4895 struct brcmf_cfg80211_vif *vif;
4896 int err = 0;
4897
4898 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4899
4900 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4901 if (vif == NULL) {
4902 brcmf_err("No p2p device available for probe response\n");
4903 err = -ENODEV;
4904 goto exit;
4905 }
4906 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4907exit:
4908 return err;
4909}
4910
Piotr Haber61730d42013-04-23 12:53:12 +02004911static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4912 struct wireless_dev *wdev,
4913 enum nl80211_crit_proto_id proto,
4914 u16 duration)
4915{
4916 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4917 struct brcmf_cfg80211_vif *vif;
4918
4919 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4920
4921 /* only DHCP support for now */
4922 if (proto != NL80211_CRIT_PROTO_DHCP)
4923 return -EINVAL;
4924
4925 /* suppress and abort scanning */
4926 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4927 brcmf_abort_scanning(cfg);
4928
4929 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4930}
4931
4932static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4933 struct wireless_dev *wdev)
4934{
4935 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4936 struct brcmf_cfg80211_vif *vif;
4937
4938 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4939
4940 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4941 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4942}
4943
Hante Meuleman70b7d942014-07-30 13:20:07 +02004944static s32
4945brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4946 const struct brcmf_event_msg *e, void *data)
4947{
4948 switch (e->reason) {
4949 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4950 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4951 break;
4952 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4953 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4954 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4955 break;
4956 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4957 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4958 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4959 break;
4960 }
4961
4962 return 0;
4963}
4964
Arend van Spriel89c2f382013-08-10 12:27:25 +02004965static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4966{
4967 int ret;
4968
4969 switch (oper) {
4970 case NL80211_TDLS_DISCOVERY_REQ:
4971 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4972 break;
4973 case NL80211_TDLS_SETUP:
4974 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4975 break;
4976 case NL80211_TDLS_TEARDOWN:
4977 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4978 break;
4979 default:
4980 brcmf_err("unsupported operation: %d\n", oper);
4981 ret = -EOPNOTSUPP;
4982 }
4983 return ret;
4984}
4985
4986static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02004987 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004988 enum nl80211_tdls_operation oper)
4989{
4990 struct brcmf_if *ifp;
4991 struct brcmf_tdls_iovar_le info;
4992 int ret = 0;
4993
4994 ret = brcmf_convert_nl80211_tdls_oper(oper);
4995 if (ret < 0)
4996 return ret;
4997
4998 ifp = netdev_priv(ndev);
4999 memset(&info, 0, sizeof(info));
5000 info.mode = (u8)ret;
5001 if (peer)
5002 memcpy(info.ea, peer, ETH_ALEN);
5003
5004 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5005 &info, sizeof(info));
5006 if (ret < 0)
5007 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5008
5009 return ret;
5010}
5011
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005012#ifdef CONFIG_PM
5013static int
5014brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5015 struct cfg80211_gtk_rekey_data *gtk)
5016{
5017 struct brcmf_if *ifp = netdev_priv(ndev);
5018 struct brcmf_gtk_keyinfo_le gtk_le;
5019 int ret;
5020
5021 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5022
5023 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5024 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5025 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5026 sizeof(gtk_le.replay_counter));
5027
5028 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5029 sizeof(gtk_le));
5030 if (ret < 0)
5031 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5032
5033 return ret;
5034}
5035#endif
5036
5037static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005038 .add_virtual_intf = brcmf_cfg80211_add_iface,
5039 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005040 .change_virtual_intf = brcmf_cfg80211_change_iface,
5041 .scan = brcmf_cfg80211_scan,
5042 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5043 .join_ibss = brcmf_cfg80211_join_ibss,
5044 .leave_ibss = brcmf_cfg80211_leave_ibss,
5045 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005046 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005047 .set_tx_power = brcmf_cfg80211_set_tx_power,
5048 .get_tx_power = brcmf_cfg80211_get_tx_power,
5049 .add_key = brcmf_cfg80211_add_key,
5050 .del_key = brcmf_cfg80211_del_key,
5051 .get_key = brcmf_cfg80211_get_key,
5052 .set_default_key = brcmf_cfg80211_config_default_key,
5053 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5054 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005055 .connect = brcmf_cfg80211_connect,
5056 .disconnect = brcmf_cfg80211_disconnect,
5057 .suspend = brcmf_cfg80211_suspend,
5058 .resume = brcmf_cfg80211_resume,
5059 .set_pmksa = brcmf_cfg80211_set_pmksa,
5060 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005061 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005062 .start_ap = brcmf_cfg80211_start_ap,
5063 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005064 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005065 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005066 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005067 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5068 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005069 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5070 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5071 .remain_on_channel = brcmf_p2p_remain_on_channel,
5072 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005073 .start_p2p_device = brcmf_p2p_start_device,
5074 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005075 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5076 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005077 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005078};
5079
Arend van Spriel3eacf862012-10-22 13:55:30 -07005080struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01005081 enum nl80211_iftype type,
5082 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005083{
Hante Meulemana44aa402014-12-03 21:05:33 +01005084 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005085 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005086 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005087
Arend van Spriel33a6b152013-02-08 15:53:39 +01005088 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005089 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005090 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5091 if (!vif)
5092 return ERR_PTR(-ENOMEM);
5093
5094 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005095 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005096
Arend van Spriel3eacf862012-10-22 13:55:30 -07005097 vif->pm_block = pm_block;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005098
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005099 brcmf_init_prof(&vif->profile);
5100
Hante Meulemana44aa402014-12-03 21:05:33 +01005101 if (type == NL80211_IFTYPE_AP) {
5102 mbss = false;
5103 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5104 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5105 mbss = true;
5106 break;
5107 }
5108 }
5109 vif->mbss = mbss;
5110 }
5111
Arend van Spriel3eacf862012-10-22 13:55:30 -07005112 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005113 return vif;
5114}
5115
Arend van Spriel427dec52014-01-06 12:40:47 +01005116void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005117{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005118 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005119 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005120}
5121
Arend van Spriel9df4d542014-01-06 12:40:49 +01005122void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5123{
5124 struct brcmf_cfg80211_vif *vif;
5125 struct brcmf_if *ifp;
5126
5127 ifp = netdev_priv(ndev);
5128 vif = ifp->vif;
5129
Arend van Spriel95ef1232015-08-26 22:15:04 +02005130 if (vif)
5131 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005132 free_netdev(ndev);
5133}
5134
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005135static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005136{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005137 u32 event = e->event_code;
5138 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005139
5140 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005141 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005142 return true;
5143 }
5144
5145 return false;
5146}
5147
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005148static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005149{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005150 u32 event = e->event_code;
5151 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005152
Hante Meuleman68ca3952014-02-25 20:30:26 +01005153 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5154 (event == BRCMF_E_DISASSOC_IND) ||
5155 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005156 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005157 return true;
5158 }
5159 return false;
5160}
5161
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005162static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005163 const struct brcmf_event_msg *e)
5164{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005165 u32 event = e->event_code;
5166 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005167
5168 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005169 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5170 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005171 return true;
5172 }
5173
5174 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005175 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005176 return true;
5177 }
5178
5179 return false;
5180}
5181
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005182static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005183{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005184 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005185
5186 kfree(conn_info->req_ie);
5187 conn_info->req_ie = NULL;
5188 conn_info->req_ie_len = 0;
5189 kfree(conn_info->resp_ie);
5190 conn_info->resp_ie = NULL;
5191 conn_info->resp_ie_len = 0;
5192}
5193
Hante Meuleman89286dc2013-02-08 15:53:46 +01005194static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5195 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005196{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005197 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005198 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005199 u32 req_len;
5200 u32 resp_len;
5201 s32 err = 0;
5202
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005203 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005204
Arend van Sprielac24be62012-10-22 10:36:23 -07005205 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5206 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005207 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005208 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005209 return err;
5210 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005211 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005212 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005213 req_len = le32_to_cpu(assoc_info->req_len);
5214 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005215 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005216 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005217 cfg->extra_buf,
5218 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005219 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005220 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005221 return err;
5222 }
5223 conn_info->req_ie_len = req_len;
5224 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005225 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005226 GFP_KERNEL);
5227 } else {
5228 conn_info->req_ie_len = 0;
5229 conn_info->req_ie = NULL;
5230 }
5231 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005232 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005233 cfg->extra_buf,
5234 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005235 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005236 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005237 return err;
5238 }
5239 conn_info->resp_ie_len = resp_len;
5240 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005241 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005242 GFP_KERNEL);
5243 } else {
5244 conn_info->resp_ie_len = 0;
5245 conn_info->resp_ie = NULL;
5246 }
Arend van Spriel16886732012-12-05 15:26:04 +01005247 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5248 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005249
5250 return err;
5251}
5252
5253static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005254brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005255 struct net_device *ndev,
5256 const struct brcmf_event_msg *e)
5257{
Arend van Sprielc1179032012-10-22 13:55:33 -07005258 struct brcmf_if *ifp = netdev_priv(ndev);
5259 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005260 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5261 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005262 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005264 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005265 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005266 u32 freq;
5267 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005268 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005269
Arend van Sprield96b8012012-12-05 15:26:02 +01005270 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005271
Hante Meuleman89286dc2013-02-08 15:53:46 +01005272 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005273 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005274 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005275
Franky Lina180b832012-10-10 11:13:09 -07005276 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5277 if (buf == NULL) {
5278 err = -ENOMEM;
5279 goto done;
5280 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005281
Franky Lina180b832012-10-10 11:13:09 -07005282 /* data sent to dongle has to be little endian */
5283 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005284 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005285 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005286
5287 if (err)
5288 goto done;
5289
5290 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005291 ch.chspec = le16_to_cpu(bi->chanspec);
5292 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293
Franky Lin83cf17a2013-04-11 13:28:50 +02005294 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005295 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005296 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005297 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005298
Franky Lin83cf17a2013-04-11 13:28:50 +02005299 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005300 notify_channel = ieee80211_get_channel(wiphy, freq);
5301
Franky Lina180b832012-10-10 11:13:09 -07005302done:
5303 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005304 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005305 conn_info->req_ie, conn_info->req_ie_len,
5306 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005307 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005308
Arend van Sprielc1179032012-10-22 13:55:33 -07005309 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005310 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005311 return err;
5312}
5313
5314static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005315brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005316 struct net_device *ndev, const struct brcmf_event_msg *e,
5317 bool completed)
5318{
Arend van Sprielc1179032012-10-22 13:55:33 -07005319 struct brcmf_if *ifp = netdev_priv(ndev);
5320 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005321 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005322
Arend van Sprield96b8012012-12-05 15:26:02 +01005323 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005324
Arend van Sprielc1179032012-10-22 13:55:33 -07005325 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5326 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005327 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005328 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005329 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005330 brcmf_update_bss_info(cfg, ifp);
5331 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5332 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005333 }
5334 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005335 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005336 conn_info->req_ie,
5337 conn_info->req_ie_len,
5338 conn_info->resp_ie,
5339 conn_info->resp_ie_len,
5340 completed ? WLAN_STATUS_SUCCESS :
5341 WLAN_STATUS_AUTH_TIMEOUT,
5342 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005343 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5344 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005345 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005346 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005347 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348}
5349
5350static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005351brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005352 struct net_device *ndev,
5353 const struct brcmf_event_msg *e, void *data)
5354{
Hante Meulemana44aa402014-12-03 21:05:33 +01005355 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman7ee29602013-02-06 18:40:43 +01005356 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005357 u32 event = e->event_code;
5358 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005359 struct station_info sinfo;
5360
Arend van Spriel16886732012-12-05 15:26:04 +01005361 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005362 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5363 ndev != cfg_to_ndev(cfg)) {
5364 brcmf_dbg(CONN, "AP mode link down\n");
5365 complete(&cfg->vif_disabled);
Hante Meulemana44aa402014-12-03 21:05:33 +01005366 if (ifp->vif->mbss)
Arend van Sprielee6e3a32015-08-26 22:14:55 +02005367 brcmf_remove_interface(ifp);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005368 return 0;
5369 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005370
Hante Meuleman1a873342012-09-27 14:17:54 +02005371 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005372 (reason == BRCMF_E_STATUS_SUCCESS)) {
5373 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005374 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005375 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005376 return -EINVAL;
5377 }
5378 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005379 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005380 generation++;
5381 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005382 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005383 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5384 (event == BRCMF_E_DEAUTH_IND) ||
5385 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005386 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005387 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005388 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005389}
5390
5391static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005392brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005393 const struct brcmf_event_msg *e, void *data)
5394{
Arend van Spriel19937322012-11-05 16:22:32 -08005395 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5396 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005397 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005398 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005399 s32 err = 0;
5400
Hante Meuleman8851cce2014-07-30 13:20:02 +02005401 if ((e->event_code == BRCMF_E_DEAUTH) ||
5402 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5403 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5404 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5405 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5406 }
5407
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005408 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005409 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005410 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005411 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005412 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005413 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005414 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005415 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005416 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005417 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5418 &ifp->vif->sme_state);
5419 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5420 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005421 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005422 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005423 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005424 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005425 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005426 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005427 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005428 brcmf_link_down(ifp->vif,
5429 brcmf_map_fw_linkdown_reason(e));
5430 brcmf_init_prof(ndev_to_prof(ndev));
5431 if (ndev != cfg_to_ndev(cfg))
5432 complete(&cfg->vif_disabled);
5433 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005435 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005436 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005437 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5438 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005439 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005440 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005441 }
5442
5443 return err;
5444}
5445
5446static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005447brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005448 const struct brcmf_event_msg *e, void *data)
5449{
Arend van Spriel19937322012-11-05 16:22:32 -08005450 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005451 u32 event = e->event_code;
5452 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005453
5454 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005455 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005456 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005457 else
Arend van Spriel19937322012-11-05 16:22:32 -08005458 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005459 }
5460
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005461 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005462}
5463
5464static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005465brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005466 const struct brcmf_event_msg *e, void *data)
5467{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005468 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005469 enum nl80211_key_type key_type;
5470
5471 if (flags & BRCMF_EVENT_MSG_GROUP)
5472 key_type = NL80211_KEYTYPE_GROUP;
5473 else
5474 key_type = NL80211_KEYTYPE_PAIRWISE;
5475
Arend van Spriel19937322012-11-05 16:22:32 -08005476 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005477 NULL, GFP_KERNEL);
5478
5479 return 0;
5480}
5481
Arend van Sprield3c0b632013-02-08 15:53:37 +01005482static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5483 const struct brcmf_event_msg *e, void *data)
5484{
5485 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5486 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5487 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5488 struct brcmf_cfg80211_vif *vif;
5489
Hante Meuleman37a869e2015-10-29 20:33:17 +01005490 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005491 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005492 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005493
Arend van Sprield3c0b632013-02-08 15:53:37 +01005494 mutex_lock(&event->vif_event_lock);
5495 event->action = ifevent->action;
5496 vif = event->vif;
5497
5498 switch (ifevent->action) {
5499 case BRCMF_E_IF_ADD:
5500 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005501 if (!cfg->vif_event.vif) {
5502 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005503 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005504 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005505
5506 ifp->vif = vif;
5507 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005508 if (ifp->ndev) {
5509 vif->wdev.netdev = ifp->ndev;
5510 ifp->ndev->ieee80211_ptr = &vif->wdev;
5511 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5512 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005513 mutex_unlock(&event->vif_event_lock);
5514 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005515 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005516
5517 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005518 mutex_unlock(&event->vif_event_lock);
5519 /* event may not be upon user request */
5520 if (brcmf_cfg80211_vif_event_armed(cfg))
5521 wake_up(&event->vif_wq);
5522 return 0;
5523
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005524 case BRCMF_E_IF_CHANGE:
5525 mutex_unlock(&event->vif_event_lock);
5526 wake_up(&event->vif_wq);
5527 return 0;
5528
Arend van Sprield3c0b632013-02-08 15:53:37 +01005529 default:
5530 mutex_unlock(&event->vif_event_lock);
5531 break;
5532 }
5533 return -EINVAL;
5534}
5535
Arend van Spriel5b435de2011-10-05 13:19:03 +02005536static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5537{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005538 conf->frag_threshold = (u32)-1;
5539 conf->rts_threshold = (u32)-1;
5540 conf->retry_short = (u32)-1;
5541 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005542}
5543
Arend van Spriel5c36b992012-11-14 18:46:05 -08005544static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005545{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005546 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5547 brcmf_notify_connect_status);
5548 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5549 brcmf_notify_connect_status);
5550 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5551 brcmf_notify_connect_status);
5552 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5553 brcmf_notify_connect_status);
5554 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5555 brcmf_notify_connect_status);
5556 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5557 brcmf_notify_connect_status);
5558 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5559 brcmf_notify_roaming_status);
5560 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5561 brcmf_notify_mic_status);
5562 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5563 brcmf_notify_connect_status);
5564 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5565 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005566 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5567 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005568 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005569 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005570 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5571 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005572 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5573 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005574 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5575 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005576 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5577 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005578}
5579
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005580static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005581{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005582 kfree(cfg->conf);
5583 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005584 kfree(cfg->extra_buf);
5585 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005586 kfree(cfg->wowl.nd);
5587 cfg->wowl.nd = NULL;
5588 kfree(cfg->wowl.nd_info);
5589 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005590 kfree(cfg->escan_info.escan_buf);
5591 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005592}
5593
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005594static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005595{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005596 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5597 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005598 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005599 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5600 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005601 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005602 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5603 if (!cfg->wowl.nd)
5604 goto init_priv_mem_out;
5605 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5606 sizeof(struct cfg80211_wowlan_nd_match *),
5607 GFP_KERNEL);
5608 if (!cfg->wowl.nd_info)
5609 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005610 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5611 if (!cfg->escan_info.escan_buf)
5612 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005613
5614 return 0;
5615
5616init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005617 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005618
5619 return -ENOMEM;
5620}
5621
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005622static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005623{
5624 s32 err = 0;
5625
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005626 cfg->scan_request = NULL;
5627 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005628 cfg->active_scan = true; /* we do active scan per default */
5629 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005630 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005631 if (err)
5632 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005633 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005634 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005635 brcmf_init_escan(cfg);
5636 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005637 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005638 return err;
5639}
5640
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005641static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005642{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005643 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005644 brcmf_abort_scanning(cfg);
5645 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005646}
5647
Arend van Sprield3c0b632013-02-08 15:53:37 +01005648static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5649{
5650 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005651 mutex_init(&event->vif_event_lock);
5652}
5653
Hante Meuleman1119e232015-11-25 11:32:42 +01005654static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005655{
Hante Meuleman1119e232015-11-25 11:32:42 +01005656 s32 err;
5657 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005658 __le32 roamtrigger[2];
5659 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005660
Hante Meuleman1119e232015-11-25 11:32:42 +01005661 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005662 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005663 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5664 else
5665 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5666 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5667 if (err) {
5668 brcmf_err("bcn_timeout error (%d)\n", err);
5669 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005670 }
5671
Hante Meuleman1119e232015-11-25 11:32:42 +01005672 /* Enable/Disable built-in roaming to allow supplicant to take care of
5673 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005674 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005675 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005676 ifp->drvr->settings->roamoff ? "Off" : "On");
5677 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5678 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005679 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005680 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005681 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005682 }
5683
Arend van Sprielf588bc02011-10-12 20:51:22 +02005684 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5685 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005686 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005687 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005688 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005689 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005690 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005691 }
5692
Arend van Sprielf588bc02011-10-12 20:51:22 +02005693 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5694 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005695 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005696 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005697 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005698 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005699 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005700 }
5701
Hante Meuleman1119e232015-11-25 11:32:42 +01005702roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005703 return err;
5704}
5705
5706static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005707brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005708{
5709 s32 err = 0;
5710
Arend van Sprielac24be62012-10-22 10:36:23 -07005711 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005712 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005713 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005714 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005715 goto dongle_scantime_out;
5716 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005717 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005718 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005719 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005720 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005721 goto dongle_scantime_out;
5722 }
5723
Arend van Sprielac24be62012-10-22 10:36:23 -07005724 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005725 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005726 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005727 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005728 goto dongle_scantime_out;
5729 }
5730
5731dongle_scantime_out:
5732 return err;
5733}
5734
Arend van Sprielb48d8912014-07-12 08:49:41 +02005735static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5736 struct brcmu_chan *ch)
5737{
5738 u32 ht40_flag;
5739
5740 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5741 if (ch->sb == BRCMU_CHAN_SB_U) {
5742 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5743 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5744 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5745 } else {
5746 /* It should be one of
5747 * IEEE80211_CHAN_NO_HT40 or
5748 * IEEE80211_CHAN_NO_HT40PLUS
5749 */
5750 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5751 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5752 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5753 }
5754}
5755
5756static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5757 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005758{
5759 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005760 struct ieee80211_supported_band *band;
5761 struct ieee80211_channel *channel;
5762 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005763 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005764 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005765 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005766 u8 *pbuf;
5767 u32 i, j;
5768 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005769 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005770 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005771
5772 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5773
5774 if (pbuf == NULL)
5775 return -ENOMEM;
5776
5777 list = (struct brcmf_chanspec_list *)pbuf;
5778
5779 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5780 BRCMF_DCMD_MEDLEN);
5781 if (err) {
5782 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005783 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005784 }
5785
Arend van Sprielb48d8912014-07-12 08:49:41 +02005786 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005787 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005788 if (band)
5789 for (i = 0; i < band->n_channels; i++)
5790 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005791 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005792 if (band)
5793 for (i = 0; i < band->n_channels; i++)
5794 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005795
5796 total = le32_to_cpu(list->count);
5797 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005798 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5799 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005800
Franky Lin83cf17a2013-04-11 13:28:50 +02005801 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005802 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005803 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005804 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005805 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005806 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005807 continue;
5808 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005809 if (!band)
5810 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005811 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005812 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005813 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005814 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005815 ch.bw == BRCMU_CHAN_BW_80)
5816 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005817
5818 channel = band->channels;
5819 index = band->n_channels;
5820 for (j = 0; j < band->n_channels; j++) {
5821 if (channel[j].hw_value == ch.chnum) {
5822 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005823 break;
5824 }
5825 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005826 channel[index].center_freq =
5827 ieee80211_channel_to_frequency(ch.chnum, band->band);
5828 channel[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005829
Arend van Sprielb48d8912014-07-12 08:49:41 +02005830 /* assuming the chanspecs order is HT20,
5831 * HT40 upper, HT40 lower, and VHT80.
5832 */
5833 if (ch.bw == BRCMU_CHAN_BW_80) {
5834 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5835 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5836 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5837 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005838 /* enable the channel and disable other bandwidths
5839 * for now as mentioned order assure they are enabled
5840 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005841 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005842 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5843 IEEE80211_CHAN_NO_80MHZ;
5844 ch.bw = BRCMU_CHAN_BW_20;
5845 cfg->d11inf.encchspec(&ch);
5846 chaninfo = ch.chspec;
5847 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5848 &chaninfo);
5849 if (!err) {
5850 if (chaninfo & WL_CHAN_RADAR)
5851 channel[index].flags |=
5852 (IEEE80211_CHAN_RADAR |
5853 IEEE80211_CHAN_NO_IR);
5854 if (chaninfo & WL_CHAN_PASSIVE)
5855 channel[index].flags |=
5856 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005857 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005858 }
5859 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005860
Arend van Sprielb48d8912014-07-12 08:49:41 +02005861fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005862 kfree(pbuf);
5863 return err;
5864}
5865
Arend van Sprielb48d8912014-07-12 08:49:41 +02005866static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005867{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005868 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5869 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005870 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005871 struct brcmf_chanspec_list *list;
5872 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005873 u32 val;
5874 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005875 struct brcmu_chan ch;
5876 u32 num_chan;
5877 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005878
5879 /* verify support for bw_cap command */
5880 val = WLC_BAND_5G;
5881 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5882
5883 if (!err) {
5884 /* only set 2G bandwidth using bw_cap command */
5885 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5886 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5887 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5888 sizeof(band_bwcap));
5889 } else {
5890 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5891 val = WLC_N_BW_40ALL;
5892 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5893 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005894
5895 if (!err) {
5896 /* update channel info in 2G band */
5897 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5898
5899 if (pbuf == NULL)
5900 return -ENOMEM;
5901
5902 ch.band = BRCMU_CHAN_BAND_2G;
5903 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005904 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005905 ch.chnum = 0;
5906 cfg->d11inf.encchspec(&ch);
5907
5908 /* pass encoded chanspec in query */
5909 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5910
5911 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5912 BRCMF_DCMD_MEDLEN);
5913 if (err) {
5914 brcmf_err("get chanspecs error (%d)\n", err);
5915 kfree(pbuf);
5916 return err;
5917 }
5918
Johannes Berg57fbcce2016-04-12 15:56:15 +02005919 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02005920 list = (struct brcmf_chanspec_list *)pbuf;
5921 num_chan = le32_to_cpu(list->count);
5922 for (i = 0; i < num_chan; i++) {
5923 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5924 cfg->d11inf.decchspec(&ch);
5925 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5926 continue;
5927 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5928 continue;
5929 for (j = 0; j < band->n_channels; j++) {
5930 if (band->channels[j].hw_value == ch.chnum)
5931 break;
5932 }
5933 if (WARN_ON(j == band->n_channels))
5934 continue;
5935
5936 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5937 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005938 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005939 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005940 return err;
5941}
5942
Arend van Spriel2375d972014-01-06 12:40:41 +01005943static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5944{
5945 u32 band, mimo_bwcap;
5946 int err;
5947
5948 band = WLC_BAND_2G;
5949 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5950 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005951 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01005952 band = WLC_BAND_5G;
5953 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5954 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005955 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01005956 return;
5957 }
5958 WARN_ON(1);
5959 return;
5960 }
5961 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5962 mimo_bwcap = 0;
5963 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5964 if (err)
5965 /* assume 20MHz if firmware does not give a clue */
5966 mimo_bwcap = WLC_N_BW_20ALL;
5967
5968 switch (mimo_bwcap) {
5969 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02005970 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01005971 /* fall-thru */
5972 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02005973 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01005974 /* fall-thru */
5975 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02005976 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5977 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01005978 break;
5979 default:
5980 brcmf_err("invalid mimo_bw_cap value\n");
5981 }
5982}
Hante Meulemand48200b2013-04-03 12:40:29 +02005983
Arend van Spriel18d6c532014-05-12 10:47:35 +02005984static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5985 u32 bw_cap[2], u32 nchain)
5986{
5987 band->ht_cap.ht_supported = true;
5988 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5989 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5990 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5991 }
5992 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5993 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5994 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5995 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5996 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5997 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5998}
5999
6000static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6001{
6002 u16 mcs_map;
6003 int i;
6004
6005 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6006 mcs_map = (mcs_map << 2) | supp;
6007
6008 return cpu_to_le16(mcs_map);
6009}
6010
6011static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006012 u32 bw_cap[2], u32 nchain, u32 txstreams,
6013 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006014{
6015 __le16 mcs_map;
6016
6017 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006018 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006019 return;
6020
6021 band->vht_cap.vht_supported = true;
6022 /* 80MHz is mandatory */
6023 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6024 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6025 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6026 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6027 }
6028 /* all support 256-QAM */
6029 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6030 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6031 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006032
6033 /* Beamforming support information */
6034 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6035 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6036 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6037 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6038 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6039 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6040 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6041 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6042
6043 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6044 band->vht_cap.cap |=
6045 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6046 band->vht_cap.cap |= ((txstreams - 1) <<
6047 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6048 band->vht_cap.cap |=
6049 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6050 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006051}
6052
Arend van Sprielb48d8912014-07-12 08:49:41 +02006053static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006054{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006055 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006056 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006057 u32 nmode = 0;
6058 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006059 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006060 u32 rxchain;
6061 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006062 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006063 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006064 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006065 u32 txstreams = 0;
6066 u32 txbf_bfe_cap = 0;
6067 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006068
Arend van Spriel18d6c532014-05-12 10:47:35 +02006069 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006070 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6071 if (err) {
6072 brcmf_err("nmode error (%d)\n", err);
6073 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006074 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006075 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006076 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006077 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6078 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006079
Daniel Kim4aca7a12014-02-25 20:30:36 +01006080 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6081 if (err) {
6082 brcmf_err("rxchain error (%d)\n", err);
6083 nchain = 1;
6084 } else {
6085 for (nchain = 0; rxchain; nchain++)
6086 rxchain = rxchain & (rxchain - 1);
6087 }
6088 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6089
Arend van Sprielb48d8912014-07-12 08:49:41 +02006090 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006091 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006092 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006093 return err;
6094 }
6095
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006096 if (vhtmode) {
6097 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6098 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6099 &txbf_bfe_cap);
6100 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6101 &txbf_bfr_cap);
6102 }
6103
Arend van Sprielb48d8912014-07-12 08:49:41 +02006104 wiphy = cfg_to_wiphy(cfg);
6105 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6106 band = wiphy->bands[i];
6107 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006108 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006109
Arend van Spriel18d6c532014-05-12 10:47:35 +02006110 if (nmode)
6111 brcmf_update_ht_cap(band, bw_cap, nchain);
6112 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006113 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6114 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006115 }
6116
Arend van Sprielb48d8912014-07-12 08:49:41 +02006117 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006118}
6119
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006120static const struct ieee80211_txrx_stypes
6121brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6122 [NL80211_IFTYPE_STATION] = {
6123 .tx = 0xffff,
6124 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6125 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6126 },
6127 [NL80211_IFTYPE_P2P_CLIENT] = {
6128 .tx = 0xffff,
6129 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6130 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6131 },
6132 [NL80211_IFTYPE_P2P_GO] = {
6133 .tx = 0xffff,
6134 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6135 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6136 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6137 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6138 BIT(IEEE80211_STYPE_AUTH >> 4) |
6139 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6140 BIT(IEEE80211_STYPE_ACTION >> 4)
6141 },
6142 [NL80211_IFTYPE_P2P_DEVICE] = {
6143 .tx = 0xffff,
6144 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6145 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6146 }
6147};
6148
Arend van Spriel0882dda2015-08-20 22:06:03 +02006149/**
6150 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6151 *
6152 * @wiphy: wiphy object.
6153 * @ifp: interface object needed for feat module api.
6154 *
6155 * The interface modes and combinations are determined dynamically here
6156 * based on firmware functionality.
6157 *
6158 * no p2p and no mbss:
6159 *
6160 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6161 *
6162 * no p2p and mbss:
6163 *
6164 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6165 * #AP <= 4, matching BI, channels = 1, 4 total
6166 *
6167 * p2p, no mchan, and mbss:
6168 *
6169 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6170 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6171 * #AP <= 4, matching BI, channels = 1, 4 total
6172 *
6173 * p2p, mchan, and mbss:
6174 *
6175 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6176 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6177 * #AP <= 4, matching BI, channels = 1, 4 total
6178 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006179static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6180{
6181 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006182 struct ieee80211_iface_limit *c0_limits = NULL;
6183 struct ieee80211_iface_limit *p2p_limits = NULL;
6184 struct ieee80211_iface_limit *mbss_limits = NULL;
6185 bool mbss, p2p;
6186 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006187
Arend van Spriel0882dda2015-08-20 22:06:03 +02006188 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6189 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6190
6191 n_combos = 1 + !!p2p + !!mbss;
6192 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006193 if (!combo)
6194 goto err;
6195
Arend van Spriel0882dda2015-08-20 22:06:03 +02006196 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6197 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006198 goto err;
6199
Arend van Spriel0882dda2015-08-20 22:06:03 +02006200 if (p2p) {
6201 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6202 if (!p2p_limits)
6203 goto err;
6204 }
6205
6206 if (mbss) {
6207 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6208 if (!mbss_limits)
6209 goto err;
6210 }
6211
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006212 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6213 BIT(NL80211_IFTYPE_ADHOC) |
6214 BIT(NL80211_IFTYPE_AP);
6215
Arend van Spriel0882dda2015-08-20 22:06:03 +02006216 c = 0;
6217 i = 0;
6218 combo[c].num_different_channels = 1;
6219 c0_limits[i].max = 1;
6220 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6221 if (p2p) {
6222 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6223 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006224 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6225 BIT(NL80211_IFTYPE_P2P_GO) |
6226 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006227 c0_limits[i].max = 1;
6228 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6229 c0_limits[i].max = 1;
6230 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6231 BIT(NL80211_IFTYPE_P2P_GO);
6232 } else {
6233 c0_limits[i].max = 1;
6234 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006235 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006236 combo[c].max_interfaces = i;
6237 combo[c].n_limits = i;
6238 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006239
Arend van Spriel0882dda2015-08-20 22:06:03 +02006240 if (p2p) {
6241 c++;
6242 i = 0;
6243 combo[c].num_different_channels = 1;
6244 p2p_limits[i].max = 1;
6245 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6246 p2p_limits[i].max = 1;
6247 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6248 p2p_limits[i].max = 1;
6249 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6250 p2p_limits[i].max = 1;
6251 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6252 combo[c].max_interfaces = i;
6253 combo[c].n_limits = i;
6254 combo[c].limits = p2p_limits;
6255 }
6256
6257 if (mbss) {
6258 c++;
6259 combo[c].beacon_int_infra_match = true;
6260 combo[c].num_different_channels = 1;
6261 mbss_limits[0].max = 4;
6262 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
6263 combo[c].max_interfaces = 4;
6264 combo[c].n_limits = 1;
6265 combo[c].limits = mbss_limits;
6266 }
6267 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006268 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006269 return 0;
6270
6271err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006272 kfree(c0_limits);
6273 kfree(p2p_limits);
6274 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006275 kfree(combo);
6276 return -ENOMEM;
6277}
6278
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006279static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6280{
6281 /* scheduled scan settings */
6282 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6283 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6284 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6285 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6286}
6287
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006288#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006289static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006290 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006291 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6292 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6293 .pattern_min_len = 1,
6294 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006295};
6296#endif
6297
Hante Meuleman3021ad92016-01-05 11:05:45 +01006298static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006299{
6300#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006301 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006302
6303 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006304 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6305 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6306 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006307 }
6308 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006309 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6310 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6311 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6312 }
6313
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006314 wiphy->wowlan = &brcmf_wowlan_support;
6315#endif
6316}
6317
Arend van Sprielb48d8912014-07-12 08:49:41 +02006318static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006319{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006320 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006321 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006322 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006323 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006324 __le32 bandlist[3];
6325 u32 n_bands;
6326 int err, i;
6327
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006328 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6329 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006330 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006331
6332 err = brcmf_setup_ifmodes(wiphy, ifp);
6333 if (err)
6334 return err;
6335
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006336 for (i = 0, combo = wiphy->iface_combinations;
6337 i < wiphy->n_iface_combinations; i++, combo++) {
6338 max_interfaces = max(max_interfaces, combo->max_interfaces);
6339 }
6340
6341 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6342 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006343 u8 *addr = drvr->addresses[i].addr;
6344
6345 memcpy(addr, drvr->mac, ETH_ALEN);
6346 if (i) {
6347 addr[0] |= BIT(1);
6348 addr[ETH_ALEN - 1] ^= i;
6349 }
6350 }
6351 wiphy->addresses = drvr->addresses;
6352 wiphy->n_addresses = i;
6353
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006354 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006355 wiphy->cipher_suites = brcmf_cipher_suites;
6356 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6357 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6358 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006359 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6360 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6361 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6362
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006363 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6364 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006365 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6366 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6367 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006368 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006369 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6370 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6371 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006372 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6373 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006374
6375 /* vendor commands/events support */
6376 wiphy->vendor_commands = brcmf_vendor_cmds;
6377 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6378
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006379 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006380 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006381 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6382 sizeof(bandlist));
6383 if (err) {
6384 brcmf_err("could not obtain band info: err=%d\n", err);
6385 return err;
6386 }
6387 /* first entry in bandlist is number of bands */
6388 n_bands = le32_to_cpu(bandlist[0]);
6389 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6390 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6391 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6392 GFP_KERNEL);
6393 if (!band)
6394 return -ENOMEM;
6395
6396 band->channels = kmemdup(&__wl_2ghz_channels,
6397 sizeof(__wl_2ghz_channels),
6398 GFP_KERNEL);
6399 if (!band->channels) {
6400 kfree(band);
6401 return -ENOMEM;
6402 }
6403
6404 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006405 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006406 }
6407 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6408 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6409 GFP_KERNEL);
6410 if (!band)
6411 return -ENOMEM;
6412
6413 band->channels = kmemdup(&__wl_5ghz_channels,
6414 sizeof(__wl_5ghz_channels),
6415 GFP_KERNEL);
6416 if (!band->channels) {
6417 kfree(band);
6418 return -ENOMEM;
6419 }
6420
6421 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006422 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006423 }
6424 }
6425 err = brcmf_setup_wiphybands(wiphy);
6426 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006427}
6428
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006429static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006430{
6431 struct net_device *ndev;
6432 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006433 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006434 s32 power_mode;
6435 s32 err = 0;
6436
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006437 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006438 return err;
6439
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006440 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006441 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006442 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006443
Hante Meuleman40a23292013-01-02 15:22:51 +01006444 /* make sure RF is ready for work */
6445 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6446
Hante Meuleman1678ba82015-12-10 13:43:00 +01006447 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006448
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006449 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006450 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006451 if (err)
6452 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006453 brcmf_dbg(INFO, "power save set to %s\n",
6454 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006455
Hante Meuleman1119e232015-11-25 11:32:42 +01006456 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006457 if (err)
6458 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006459 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6460 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006461 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006462 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006463
Franky Lin52f22fb2016-02-17 11:26:55 +01006464 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006465
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006466 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006467default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006468
6469 return err;
6470
6471}
6472
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006473static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006474{
Arend van Sprielc1179032012-10-22 13:55:33 -07006475 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006476
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006477 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006478}
6479
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006480static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006481{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006482 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006483
Arend van Spriel5b435de2011-10-05 13:19:03 +02006484 /*
6485 * While going down, if associated with AP disassociate
6486 * from AP to save power
6487 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006488 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006489 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006490
6491 /* Make sure WPA_Supplicant receives all the event
6492 generated due to DISASSOC call to the fw to keep
6493 the state fw and WPA_Supplicant state consistent
6494 */
6495 brcmf_delay(500);
6496 }
6497
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006498 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006499 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006500
Arend van Spriel5b435de2011-10-05 13:19:03 +02006501 return 0;
6502}
6503
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006504s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006505{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006506 struct brcmf_if *ifp = netdev_priv(ndev);
6507 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006508 s32 err = 0;
6509
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006510 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006511 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006512 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006513
6514 return err;
6515}
6516
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006517s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006518{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006519 struct brcmf_if *ifp = netdev_priv(ndev);
6520 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006521 s32 err = 0;
6522
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006523 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006524 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006525 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006526
6527 return err;
6528}
6529
Arend van Spriela7965fb2013-04-11 17:08:37 +02006530enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6531{
6532 struct wireless_dev *wdev = &ifp->vif->wdev;
6533
6534 return wdev->iftype;
6535}
6536
Hante Meulemanbfe81972014-10-28 14:56:16 +01006537bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6538 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006539{
6540 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006541
6542 list_for_each_entry(vif, &cfg->vif_list, list) {
6543 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006544 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006545 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006546 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006547}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006548
6549static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6550 u8 action)
6551{
6552 u8 evt_action;
6553
6554 mutex_lock(&event->vif_event_lock);
6555 evt_action = event->action;
6556 mutex_unlock(&event->vif_event_lock);
6557 return evt_action == action;
6558}
6559
6560void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6561 struct brcmf_cfg80211_vif *vif)
6562{
6563 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6564
6565 mutex_lock(&event->vif_event_lock);
6566 event->vif = vif;
6567 event->action = 0;
6568 mutex_unlock(&event->vif_event_lock);
6569}
6570
6571bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6572{
6573 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6574 bool armed;
6575
6576 mutex_lock(&event->vif_event_lock);
6577 armed = event->vif != NULL;
6578 mutex_unlock(&event->vif_event_lock);
6579
6580 return armed;
6581}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006582
6583int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6584 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006585{
6586 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6587
6588 return wait_event_timeout(event->vif_wq,
6589 vif_event_equals(event, action), timeout);
6590}
6591
Hante Meuleman73345fd2016-02-17 11:26:53 +01006592static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6593 struct brcmf_fil_country_le *ccreq)
6594{
Hante Meuleman4d792892016-02-17 11:27:07 +01006595 struct brcmfmac_pd_cc *country_codes;
6596 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006597 s32 found_index;
6598 int i;
6599
6600 country_codes = drvr->settings->country_codes;
6601 if (!country_codes) {
6602 brcmf_dbg(TRACE, "No country codes configured for device\n");
6603 return -EINVAL;
6604 }
6605
6606 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6607 (alpha2[1] == ccreq->country_abbrev[1])) {
6608 brcmf_dbg(TRACE, "Country code already set\n");
6609 return -EAGAIN;
6610 }
6611
6612 found_index = -1;
6613 for (i = 0; i < country_codes->table_size; i++) {
6614 cc = &country_codes->table[i];
6615 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6616 found_index = i;
6617 if ((cc->iso3166[0] == alpha2[0]) &&
6618 (cc->iso3166[1] == alpha2[1])) {
6619 found_index = i;
6620 break;
6621 }
6622 }
6623 if (found_index == -1) {
6624 brcmf_dbg(TRACE, "No country code match found\n");
6625 return -EINVAL;
6626 }
6627 memset(ccreq, 0, sizeof(*ccreq));
6628 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6629 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6630 BRCMF_COUNTRY_BUF_SZ);
6631 ccreq->country_abbrev[0] = alpha2[0];
6632 ccreq->country_abbrev[1] = alpha2[1];
6633 ccreq->country_abbrev[2] = 0;
6634
6635 return 0;
6636}
6637
Arend van Spriel63db1a42014-12-21 12:43:51 +01006638static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6639 struct regulatory_request *req)
6640{
6641 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6642 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6643 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006644 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006645 int i;
6646
Arend van Spriel63db1a42014-12-21 12:43:51 +01006647 /* ignore non-ISO3166 country codes */
6648 for (i = 0; i < sizeof(req->alpha2); i++)
6649 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006650 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6651 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006652 return;
6653 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006654
6655 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6656 req->alpha2[0], req->alpha2[1]);
6657
6658 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6659 if (err) {
6660 brcmf_err("Country code iovar returned err = %d\n", err);
6661 return;
6662 }
6663
6664 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6665 if (err)
6666 return;
6667
6668 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6669 if (err) {
6670 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006671 return;
6672 }
6673 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006674}
6675
Arend van Sprielb48d8912014-07-12 08:49:41 +02006676static void brcmf_free_wiphy(struct wiphy *wiphy)
6677{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006678 int i;
6679
Arend van Spriel58de92d2015-04-14 20:10:24 +02006680 if (!wiphy)
6681 return;
6682
Arend van Spriel0882dda2015-08-20 22:06:03 +02006683 if (wiphy->iface_combinations) {
6684 for (i = 0; i < wiphy->n_iface_combinations; i++)
6685 kfree(wiphy->iface_combinations[i].limits);
6686 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006687 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006688 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6689 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6690 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006691 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006692 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6693 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6694 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006695 }
6696 wiphy_free(wiphy);
6697}
6698
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006699struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006700 struct device *busdev,
6701 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006702{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006703 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006704 struct brcmf_cfg80211_info *cfg;
6705 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006706 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006707 struct brcmf_cfg80211_vif *vif;
6708 struct brcmf_if *ifp;
6709 s32 err = 0;
6710 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006711 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006712
6713 if (!ndev) {
6714 brcmf_err("ndev is invalid\n");
6715 return NULL;
6716 }
6717
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006718 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
6719 if (!ops)
6720 return NULL;
6721
6722 memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006723 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006724#ifdef CONFIG_PM
6725 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6726 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6727#endif
6728 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006729 if (!wiphy) {
6730 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006731 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006732 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006733 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006734 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006735
6736 cfg = wiphy_priv(wiphy);
6737 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006738 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006739 cfg->pub = drvr;
6740 init_vif_event(&cfg->vif_event);
6741 INIT_LIST_HEAD(&cfg->vif_list);
6742
6743 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006744 if (IS_ERR(vif))
6745 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006746
6747 vif->ifp = ifp;
6748 vif->wdev.netdev = ndev;
6749 ndev->ieee80211_ptr = &vif->wdev;
6750 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6751
6752 err = wl_init_priv(cfg);
6753 if (err) {
6754 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006755 brcmf_free_vif(vif);
6756 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006757 }
6758 ifp->vif = vif;
6759
Arend van Sprielb48d8912014-07-12 08:49:41 +02006760 /* determine d11 io type before wiphy setup */
6761 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006762 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006763 brcmf_err("Failed to get D11 version (%d)\n", err);
6764 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006765 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006766 cfg->d11inf.io_type = (u8)io_type;
6767 brcmu_d11_attach(&cfg->d11inf);
6768
6769 err = brcmf_setup_wiphy(wiphy, ifp);
6770 if (err < 0)
6771 goto priv_out;
6772
6773 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006774 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006775 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6776 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6777
6778 /* firmware defaults to 40MHz disabled in 2G band. We signal
6779 * cfg80211 here that we do and have it decide we can enable
6780 * it. But first check if device does support 2G operation.
6781 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006782 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6783 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006784 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6785 }
6786 err = wiphy_register(wiphy);
6787 if (err < 0) {
6788 brcmf_err("Could not register wiphy device (%d)\n", err);
6789 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006790 }
6791
6792 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6793 * setup 40MHz in 2GHz band and enable OBSS scanning.
6794 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006795 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6796 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006797 if (!err)
6798 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6799 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006800 else
6801 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006802 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006803 /* p2p might require that "if-events" get processed by fweh. So
6804 * activate the already registered event handlers now and activate
6805 * the rest when initialization has completed. drvr->config needs to
6806 * be assigned before activating events.
6807 */
6808 drvr->config = cfg;
6809 err = brcmf_fweh_activate_events(ifp);
6810 if (err) {
6811 brcmf_err("FWEH activation failed (%d)\n", err);
6812 goto wiphy_unreg_out;
6813 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006814
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006815 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006816 if (err) {
6817 brcmf_err("P2P initilisation failed (%d)\n", err);
6818 goto wiphy_unreg_out;
6819 }
6820 err = brcmf_btcoex_attach(cfg);
6821 if (err) {
6822 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6823 brcmf_p2p_detach(&cfg->p2p);
6824 goto wiphy_unreg_out;
6825 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006826
Hante Meulemana7b82d42015-12-10 13:43:04 +01006827 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6828 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6829 if (err) {
6830 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6831 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6832 } else {
6833 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6834 brcmf_notify_tdls_peer_event);
6835 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006836 }
6837
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006838 /* (re-) activate FWEH event handling */
6839 err = brcmf_fweh_activate_events(ifp);
6840 if (err) {
6841 brcmf_err("FWEH activation failed (%d)\n", err);
6842 goto wiphy_unreg_out;
6843 }
6844
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006845 /* Fill in some of the advertised nl80211 supported features */
6846 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6847 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6848#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006849 if (wiphy->wowlan &&
6850 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006851 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6852#endif
6853 }
6854
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006855 return cfg;
6856
Arend van Sprielb48d8912014-07-12 08:49:41 +02006857wiphy_unreg_out:
6858 wiphy_unregister(cfg->wiphy);
6859priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006860 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006861 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006862 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006863wiphy_out:
6864 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006865 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006866 return NULL;
6867}
6868
6869void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6870{
6871 if (!cfg)
6872 return;
6873
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006874 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006875 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006876 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006877 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006878 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006879}