blob: afe2b202040ac46af5b09cbea24480f1b1776959 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Hante Meuleman68ca3952014-02-25 20:30:26 +010021#include <linux/module.h>
Franky Lin1bacb042014-06-21 12:11:16 +020022#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020024#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025
26#include <brcmu_utils.h>
27#include <defs.h>
28#include <brcmu_wifi.h>
Hante Meuleman122d3d02014-10-28 14:56:18 +010029#include "core.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010030#include "debug.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020031#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010032#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010033#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020034#include "btcoex.h"
Hante Meulemanbfe81972014-10-28 14:56:16 +010035#include "cfg80211.h"
Arend van Sprielc08437b2014-07-12 08:49:39 +020036#include "feature.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070037#include "fwil.h"
Hante Meuleman8851cce2014-07-30 13:20:02 +020038#include "proto.h"
Franky Lin1bacb042014-06-21 12:11:16 +020039#include "vendor.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010040#include "bus.h"
Hante Meuleman6b89dcb2014-12-21 12:43:52 +010041#include "common.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
Arend van Spriele5806072012-09-19 22:21:08 +020043#define BRCMF_SCAN_IE_LEN_MAX 2048
44#define BRCMF_PNO_VERSION 2
45#define BRCMF_PNO_TIME 30
46#define BRCMF_PNO_REPEAT 4
47#define BRCMF_PNO_FREQ_EXPO_MAX 3
48#define BRCMF_PNO_MAX_PFN_COUNT 16
49#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
50#define BRCMF_PNO_HIDDEN_BIT 2
51#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
52#define BRCMF_PNO_SCAN_COMPLETE 1
53#define BRCMF_PNO_SCAN_INCOMPLETE 0
54
Hante Meuleman1a873342012-09-27 14:17:54 +020055#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
56#define WPA_OUI_TYPE 1
57#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
58#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010059#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020060
61#define VS_IE_FIXED_HDR_LEN 6
62#define WPA_IE_VERSION_LEN 2
63#define WPA_IE_MIN_OUI_LEN 4
64#define WPA_IE_SUITE_COUNT_LEN 2
65
66#define WPA_CIPHER_NONE 0 /* None */
67#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
68#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
69#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
70#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
71
72#define RSN_AKM_NONE 0 /* None (IBSS) */
73#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
74#define RSN_AKM_PSK 2 /* Pre-shared Key */
Hante Meuleman240d61a2016-02-17 11:27:10 +010075#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
76#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
Hante Meuleman1a873342012-09-27 14:17:54 +020077#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
Hante Meuleman240d61a2016-02-17 11:27:10 +010078#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
79#define RSN_CAP_MFPR_MASK BIT(6)
80#define RSN_CAP_MFPC_MASK BIT(7)
81#define RSN_PMKID_COUNT_LEN 2
Hante Meuleman1a873342012-09-27 14:17:54 +020082
83#define VNDR_IE_CMD_LEN 4 /* length of the set command
84 * string :"add", "del" (+ NUL)
85 */
86#define VNDR_IE_COUNT_OFFSET 4
87#define VNDR_IE_PKTFLAG_OFFSET 8
88#define VNDR_IE_VSIE_OFFSET 12
89#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010090#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020091
92#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
93#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020094
Hante Meuleman89286dc2013-02-08 15:53:46 +010095#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
96#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
97#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
98
Hante Meuleman1678ba82015-12-10 13:43:00 +010099#define BRCMF_SCAN_CHANNEL_TIME 40
100#define BRCMF_SCAN_UNASSOC_TIME 40
101#define BRCMF_SCAN_PASSIVE_TIME 120
102
Hante Meuleman3021ad92016-01-05 11:05:45 +0100103#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
104
Arend van Spriel5b435de2011-10-05 13:19:03 +0200105#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
106 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
107
Arend van Sprielce81e312012-10-22 13:55:37 -0700108static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200109{
Arend van Sprielc1179032012-10-22 13:55:33 -0700110 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100111 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
112 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200113 return false;
114 }
115 return true;
116}
117
Arend van Spriel5b435de2011-10-05 13:19:03 +0200118#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
119#define RATETAB_ENT(_rateid, _flags) \
120 { \
121 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
122 .hw_value = (_rateid), \
123 .flags = (_flags), \
124 }
125
126static struct ieee80211_rate __wl_rates[] = {
127 RATETAB_ENT(BRCM_RATE_1M, 0),
128 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
129 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
130 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_6M, 0),
132 RATETAB_ENT(BRCM_RATE_9M, 0),
133 RATETAB_ENT(BRCM_RATE_12M, 0),
134 RATETAB_ENT(BRCM_RATE_18M, 0),
135 RATETAB_ENT(BRCM_RATE_24M, 0),
136 RATETAB_ENT(BRCM_RATE_36M, 0),
137 RATETAB_ENT(BRCM_RATE_48M, 0),
138 RATETAB_ENT(BRCM_RATE_54M, 0),
139};
140
Arend van Spriel5b435de2011-10-05 13:19:03 +0200141#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200142#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
143#define wl_a_rates (__wl_rates + 4)
144#define wl_a_rates_size (wl_g_rates_size - 4)
145
146#define CHAN2G(_channel, _freq) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200147 .band = NL80211_BAND_2GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200148 .center_freq = (_freq), \
149 .hw_value = (_channel), \
150 .flags = IEEE80211_CHAN_DISABLED, \
151 .max_antenna_gain = 0, \
152 .max_power = 30, \
153}
154
155#define CHAN5G(_channel) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200156 .band = NL80211_BAND_5GHZ, \
Arend van Spriel58de92d2015-04-14 20:10:24 +0200157 .center_freq = 5000 + (5 * (_channel)), \
158 .hw_value = (_channel), \
159 .flags = IEEE80211_CHAN_DISABLED, \
160 .max_antenna_gain = 0, \
161 .max_power = 30, \
162}
163
164static struct ieee80211_channel __wl_2ghz_channels[] = {
165 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
166 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
167 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
168 CHAN2G(13, 2472), CHAN2G(14, 2484)
169};
170
171static struct ieee80211_channel __wl_5ghz_channels[] = {
172 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
173 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
174 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
175 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
176 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
177 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
178};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200179
Arend van Sprielb48d8912014-07-12 08:49:41 +0200180/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200181 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200182 */
183static const struct ieee80211_supported_band __wl_band_2ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200184 .band = NL80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200185 .bitrates = wl_g_rates,
186 .n_bitrates = wl_g_rates_size,
187};
188
Arend van Spriel58de92d2015-04-14 20:10:24 +0200189static const struct ieee80211_supported_band __wl_band_5ghz = {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200190 .band = NL80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200191 .bitrates = wl_a_rates,
192 .n_bitrates = wl_a_rates_size,
193};
194
Hante Meulemand48200b2013-04-03 12:40:29 +0200195/* This is to override regulatory domains defined in cfg80211 module (reg.c)
196 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200197 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
198 * With respect to these flags, wpa_supplicant doesn't * start p2p
199 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200200 * domain are to be done here.
201 */
202static const struct ieee80211_regdomain brcmf_regdom = {
203 .n_reg_rules = 4,
204 .alpha2 = "99",
205 .reg_rules = {
206 /* IEEE 802.11b/g, channels 1..11 */
207 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
208 /* If any */
209 /* IEEE 802.11 channel 14 - Only JP enables
210 * this and for 802.11b only
211 */
212 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
213 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200214 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200215 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200216 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200217};
218
Hante Meuleman240d61a2016-02-17 11:27:10 +0100219/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
220 * are supported. A pointer to this array and the number of entries is passed
221 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
222 * So the cipher suite AES_CMAC has to be the last one in the array, and when
223 * device does not support MFP then the number of suites will be decreased by 1
224 */
225static const u32 brcmf_cipher_suites[] = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200226 WLAN_CIPHER_SUITE_WEP40,
227 WLAN_CIPHER_SUITE_WEP104,
228 WLAN_CIPHER_SUITE_TKIP,
229 WLAN_CIPHER_SUITE_CCMP,
Hante Meuleman240d61a2016-02-17 11:27:10 +0100230 /* Keep as last entry: */
231 WLAN_CIPHER_SUITE_AES_CMAC
Arend van Spriel5b435de2011-10-05 13:19:03 +0200232};
233
Hante Meuleman1a873342012-09-27 14:17:54 +0200234/* Vendor specific ie. id = 221, oui and type defines exact ie */
235struct brcmf_vs_tlv {
236 u8 id;
237 u8 len;
238 u8 oui[3];
239 u8 oui_type;
240};
241
242struct parsed_vndr_ie_info {
243 u8 *ie_ptr;
244 u32 ie_len; /* total length including id & length field */
245 struct brcmf_vs_tlv vndrie;
246};
247
248struct parsed_vndr_ies {
249 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100250 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200251};
252
Arend van Spriel7705ba62016-04-17 16:44:58 +0200253static u8 nl80211_band_to_fwil(enum nl80211_band band)
254{
255 switch (band) {
256 case NL80211_BAND_2GHZ:
257 return WLC_BAND_2G;
258 case NL80211_BAND_5GHZ:
259 return WLC_BAND_5G;
260 default:
261 WARN_ON(1);
262 break;
263 }
264 return 0;
265}
266
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200267static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
268 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200269{
270 struct brcmu_chan ch_inf;
271 s32 primary_offset;
272
273 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
274 ch->chan->center_freq, ch->center_freq1, ch->width);
275 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100276 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200277 switch (ch->width) {
278 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100279 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200280 ch_inf.bw = BRCMU_CHAN_BW_20;
281 WARN_ON(primary_offset != 0);
282 break;
283 case NL80211_CHAN_WIDTH_40:
284 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100285 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200286 ch_inf.sb = BRCMU_CHAN_SB_U;
287 else
288 ch_inf.sb = BRCMU_CHAN_SB_L;
289 break;
290 case NL80211_CHAN_WIDTH_80:
291 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100292 if (primary_offset == -30)
293 ch_inf.sb = BRCMU_CHAN_SB_LL;
294 else if (primary_offset == -10)
295 ch_inf.sb = BRCMU_CHAN_SB_LU;
296 else if (primary_offset == 10)
297 ch_inf.sb = BRCMU_CHAN_SB_UL;
298 else
299 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200300 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100301 case NL80211_CHAN_WIDTH_80P80:
302 case NL80211_CHAN_WIDTH_160:
303 case NL80211_CHAN_WIDTH_5:
304 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200305 default:
306 WARN_ON_ONCE(1);
307 }
308 switch (ch->chan->band) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200309 case NL80211_BAND_2GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200310 ch_inf.band = BRCMU_CHAN_BAND_2G;
311 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200312 case NL80211_BAND_5GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200313 ch_inf.band = BRCMU_CHAN_BAND_5G;
314 break;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200315 case NL80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200316 default:
317 WARN_ON_ONCE(1);
318 }
319 d11inf->encchspec(&ch_inf);
320
321 return ch_inf.chspec;
322}
323
Franky Lin83cf17a2013-04-11 13:28:50 +0200324u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
325 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700326{
Franky Lin83cf17a2013-04-11 13:28:50 +0200327 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700328
Franky Lin83cf17a2013-04-11 13:28:50 +0200329 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
330 ch_inf.bw = BRCMU_CHAN_BW_20;
331 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700332
Franky Lin83cf17a2013-04-11 13:28:50 +0200333 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700334}
335
Hante Meuleman89286dc2013-02-08 15:53:46 +0100336/* Traverse a string of 1-byte tag/1-byte length/variable-length value
337 * triples, returning a pointer to the substring whose first element
338 * matches tag
339 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100340const struct brcmf_tlv *
341brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100342{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100343 const struct brcmf_tlv *elt = buf;
344 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100345
346 /* find tagged parameter */
347 while (totlen >= TLV_HDR_LEN) {
348 int len = elt->len;
349
350 /* validate remaining totlen */
351 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
352 return elt;
353
354 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
355 totlen -= (len + TLV_HDR_LEN);
356 }
357
358 return NULL;
359}
360
361/* Is any of the tlvs the expected entry? If
362 * not update the tlvs buffer pointer/length.
363 */
364static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100365brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
366 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100367{
368 /* If the contents match the OUI and the type */
369 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
370 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
371 type == ie[TLV_BODY_OFF + oui_len]) {
372 return true;
373 }
374
375 if (tlvs == NULL)
376 return false;
377 /* point to the next ie */
378 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
379 /* calculate the length of the rest of the buffer */
380 *tlvs_len -= (int)(ie - *tlvs);
381 /* update the pointer to the start of the buffer */
382 *tlvs = ie;
383
384 return false;
385}
386
387static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100388brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100389{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100390 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100391
392 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100393 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100394 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
395 return (struct brcmf_vs_tlv *)ie;
396 }
397 return NULL;
398}
399
400static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100401brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100402{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100403 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100404
405 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
406 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
407 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
408 return (struct brcmf_vs_tlv *)ie;
409 }
410 return NULL;
411}
412
Arend van Spriel39504a22015-08-20 22:06:05 +0200413static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
414 struct brcmf_cfg80211_vif *vif,
415 enum nl80211_iftype new_type)
416{
417 int iftype_num[NUM_NL80211_IFTYPES];
418 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100419 bool check_combos = false;
420 int ret = 0;
Arend van Spriel39504a22015-08-20 22:06:05 +0200421
422 memset(&iftype_num[0], 0, sizeof(iftype_num));
423 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100424 if (pos == vif) {
Arend van Spriel39504a22015-08-20 22:06:05 +0200425 iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100426 } else {
427 /* concurrent interfaces so need check combinations */
428 check_combos = true;
Arend van Spriel39504a22015-08-20 22:06:05 +0200429 iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100430 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200431
Arend van Spriel353c46a2015-12-10 13:43:06 +0100432 if (check_combos)
433 ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
434
435 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200436}
437
438static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
439 enum nl80211_iftype new_type)
440{
441 int iftype_num[NUM_NL80211_IFTYPES];
442 struct brcmf_cfg80211_vif *pos;
443
444 memset(&iftype_num[0], 0, sizeof(iftype_num));
445 list_for_each_entry(pos, &cfg->vif_list, list)
446 iftype_num[pos->wdev.iftype]++;
447
448 iftype_num[new_type]++;
449 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
450}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100451
Arend van Spriel5b435de2011-10-05 13:19:03 +0200452static void convert_key_from_CPU(struct brcmf_wsec_key *key,
453 struct brcmf_wsec_key_le *key_le)
454{
455 key_le->index = cpu_to_le32(key->index);
456 key_le->len = cpu_to_le32(key->len);
457 key_le->algo = cpu_to_le32(key->algo);
458 key_le->flags = cpu_to_le32(key->flags);
459 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
460 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
461 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
462 memcpy(key_le->data, key->data, sizeof(key->data));
463 memcpy(key_le->ea, key->ea, sizeof(key->ea));
464}
465
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200466static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100467send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200468{
469 int err;
470 struct brcmf_wsec_key_le key_le;
471
472 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200473
Hante Meuleman118eb302014-12-21 12:43:49 +0100474 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700475
Hante Meuleman118eb302014-12-21 12:43:49 +0100476 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700477 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200478
Arend van Spriel5b435de2011-10-05 13:19:03 +0200479 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100480 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200481 return err;
482}
483
Hante Meulemanb3657452013-05-27 21:09:53 +0200484static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100485brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200486{
487 s32 err;
488 u32 mode;
489
490 if (enable)
491 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
492 else
493 mode = 0;
494
495 /* Try to set and enable ARP offload feature, this may fail, then it */
496 /* is simply not supported and err 0 will be returned */
497 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
498 if (err) {
499 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
500 mode, err);
501 err = 0;
502 } else {
503 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
504 if (err) {
505 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
506 enable, err);
507 err = 0;
508 } else
509 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
510 enable, mode);
511 }
512
Franky Lin52f22fb2016-02-17 11:26:55 +0100513 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
514 if (err) {
515 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
516 enable, err);
517 err = 0;
518 } else
519 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
520 enable, mode);
521
Hante Meulemanb3657452013-05-27 21:09:53 +0200522 return err;
523}
524
Hante Meuleman8851cce2014-07-30 13:20:02 +0200525static void
526brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
527{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200528 struct brcmf_cfg80211_vif *vif;
529 struct brcmf_if *ifp;
530
531 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
532 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200533
534 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
535 (wdev->iftype == NL80211_IFTYPE_AP) ||
536 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
537 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
538 ADDR_DIRECT);
539 else
540 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
541 ADDR_INDIRECT);
542}
543
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200544static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
545{
546 int bsscfgidx;
547
548 for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) {
549 /* bsscfgidx 1 is reserved for legacy P2P */
550 if (bsscfgidx == 1)
551 continue;
552 if (!drvr->iflist[bsscfgidx])
553 return bsscfgidx;
554 }
555
556 return -ENOMEM;
557}
558
Hante Meulemana44aa402014-12-03 21:05:33 +0100559static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
560{
561 struct brcmf_mbss_ssid_le mbss_ssid_le;
562 int bsscfgidx;
563 int err;
564
565 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
Rafał Miłeckid02fb8f2016-05-26 01:44:27 +0200566 bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr);
Hante Meulemana44aa402014-12-03 21:05:33 +0100567 if (bsscfgidx < 0)
568 return bsscfgidx;
569
570 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
571 mbss_ssid_le.SSID_len = cpu_to_le32(5);
572 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
573
574 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
575 sizeof(mbss_ssid_le));
576 if (err < 0)
577 brcmf_err("setting ssid failed %d\n", err);
578
579 return err;
580}
581
582/**
583 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
584 *
585 * @wiphy: wiphy device of new interface.
586 * @name: name of the new interface.
587 * @flags: not used.
588 * @params: contains mac address for AP device.
589 */
590static
591struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
592 u32 *flags, struct vif_params *params)
593{
594 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
595 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
596 struct brcmf_cfg80211_vif *vif;
597 int err;
598
599 if (brcmf_cfg80211_vif_event_armed(cfg))
600 return ERR_PTR(-EBUSY);
601
602 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
603
Rafał Miłecki26072332016-06-06 23:03:55 +0200604 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100605 if (IS_ERR(vif))
606 return (struct wireless_dev *)vif;
607
608 brcmf_cfg80211_arm_vif_event(cfg, vif);
609
610 err = brcmf_cfg80211_request_ap_if(ifp);
611 if (err) {
612 brcmf_cfg80211_arm_vif_event(cfg, NULL);
613 goto fail;
614 }
615
616 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100617 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
618 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100619 brcmf_cfg80211_arm_vif_event(cfg, NULL);
620 if (!err) {
621 brcmf_err("timeout occurred\n");
622 err = -EIO;
623 goto fail;
624 }
625
626 /* interface created in firmware */
627 ifp = vif->ifp;
628 if (!ifp) {
629 brcmf_err("no if pointer provided\n");
630 err = -ENOENT;
631 goto fail;
632 }
633
634 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
635 err = brcmf_net_attach(ifp, true);
636 if (err) {
637 brcmf_err("Registering netdevice failed\n");
638 goto fail;
639 }
640
641 return &ifp->vif->wdev;
642
643fail:
644 brcmf_free_vif(vif);
645 return ERR_PTR(err);
646}
647
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100648static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
649{
650 enum nl80211_iftype iftype;
651
652 iftype = vif->wdev.iftype;
653 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
654}
655
656static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
657{
658 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
659}
660
Arend van Spriel9f440b72013-02-08 15:53:36 +0100661static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
662 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100663 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100664 enum nl80211_iftype type,
665 u32 *flags,
666 struct vif_params *params)
667{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200668 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200669 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200670
Arend van Spriel9f440b72013-02-08 15:53:36 +0100671 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200672 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
673 if (err) {
674 brcmf_err("iface validation failed: err=%d\n", err);
675 return ERR_PTR(err);
676 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100677 switch (type) {
678 case NL80211_IFTYPE_ADHOC:
679 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100680 case NL80211_IFTYPE_AP_VLAN:
681 case NL80211_IFTYPE_WDS:
682 case NL80211_IFTYPE_MONITOR:
683 case NL80211_IFTYPE_MESH_POINT:
684 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100685 case NL80211_IFTYPE_AP:
686 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200687 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100688 case NL80211_IFTYPE_P2P_CLIENT:
689 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200690 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100691 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200692 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100693 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100694 default:
695 return ERR_PTR(-EINVAL);
696 }
Rafał Miłecki0cd33c22016-05-27 10:54:28 +0200697
698 if (IS_ERR(wdev))
699 brcmf_err("add iface %s type %d failed: err=%d\n",
700 name, type, (int)PTR_ERR(wdev));
701 else
702 brcmf_cfg80211_update_proto_addr_mode(wdev);
703
704 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100705}
706
Daniel Kim5e787f72014-06-21 12:11:18 +0200707static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
708{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200709 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200710 brcmf_set_mpc(ifp, mpc);
711}
712
Arend van Sprielf96aa072013-04-05 10:57:48 +0200713void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100714{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100715 s32 err = 0;
716
717 if (check_vif_up(ifp->vif)) {
718 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
719 if (err) {
720 brcmf_err("fail to set mpc\n");
721 return;
722 }
723 brcmf_dbg(INFO, "MPC : %d\n", mpc);
724 }
725}
726
Arend van Spriela0f472a2013-04-05 10:57:49 +0200727s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
728 struct brcmf_if *ifp, bool aborted,
729 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100730{
731 struct brcmf_scan_params_le params_le;
732 struct cfg80211_scan_request *scan_request;
733 s32 err = 0;
734
735 brcmf_dbg(SCAN, "Enter\n");
736
737 /* clear scan request, because the FW abort can cause a second call */
738 /* to this functon and might cause a double cfg80211_scan_done */
739 scan_request = cfg->scan_request;
740 cfg->scan_request = NULL;
741
742 if (timer_pending(&cfg->escan_timeout))
743 del_timer_sync(&cfg->escan_timeout);
744
745 if (fw_abort) {
746 /* Do a scan abort to stop the driver's scan engine */
747 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
748 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800749 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100750 params_le.bss_type = DOT11_BSSTYPE_ANY;
751 params_le.scan_type = 0;
752 params_le.channel_num = cpu_to_le32(1);
753 params_le.nprobes = cpu_to_le32(1);
754 params_le.active_time = cpu_to_le32(-1);
755 params_le.passive_time = cpu_to_le32(-1);
756 params_le.home_time = cpu_to_le32(-1);
757 /* Scan is aborted by setting channel_list[0] to -1 */
758 params_le.channel_list[0] = cpu_to_le16(-1);
759 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200760 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100761 &params_le, sizeof(params_le));
762 if (err)
763 brcmf_err("Scan abort failed\n");
764 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200765
Daniel Kim5e787f72014-06-21 12:11:18 +0200766 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200767
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100768 /*
769 * e-scan can be initiated by scheduled scan
770 * which takes precedence.
771 */
772 if (cfg->sched_escan) {
773 brcmf_dbg(SCAN, "scheduled scan completed\n");
774 cfg->sched_escan = false;
775 if (!aborted)
776 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100777 } else if (scan_request) {
Avraham Stern1d762502016-07-05 17:10:13 +0300778 struct cfg80211_scan_info info = {
779 .aborted = aborted,
780 };
781
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100782 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
783 aborted ? "Aborted" : "Done");
Avraham Stern1d762502016-07-05 17:10:13 +0300784 cfg80211_scan_done(scan_request, &info);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100785 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100786 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
787 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100788
789 return err;
790}
791
Arend van Spriel9f440b72013-02-08 15:53:36 +0100792static
793int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
794{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100795 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
796 struct net_device *ndev = wdev->netdev;
797
798 /* vif event pending in firmware */
799 if (brcmf_cfg80211_vif_event_armed(cfg))
800 return -EBUSY;
801
802 if (ndev) {
803 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200804 cfg->escan_info.ifp == netdev_priv(ndev))
805 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
806 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100807
808 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
809 }
810
Arend van Spriel9f440b72013-02-08 15:53:36 +0100811 switch (wdev->iftype) {
812 case NL80211_IFTYPE_ADHOC:
813 case NL80211_IFTYPE_STATION:
814 case NL80211_IFTYPE_AP:
815 case NL80211_IFTYPE_AP_VLAN:
816 case NL80211_IFTYPE_WDS:
817 case NL80211_IFTYPE_MONITOR:
818 case NL80211_IFTYPE_MESH_POINT:
819 return -EOPNOTSUPP;
820 case NL80211_IFTYPE_P2P_CLIENT:
821 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200822 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100823 return brcmf_p2p_del_vif(wiphy, wdev);
824 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100825 default:
826 return -EINVAL;
827 }
828 return -EOPNOTSUPP;
829}
830
Arend van Spriel5b435de2011-10-05 13:19:03 +0200831static s32
832brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
833 enum nl80211_iftype type, u32 *flags,
834 struct vif_params *params)
835{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100836 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700837 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100838 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200839 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200840 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200841 s32 err = 0;
842
Hante Meuleman37a869e2015-10-29 20:33:17 +0100843 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
844 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200845
846 /* WAR: There are a number of p2p interface related problems which
847 * need to be handled initially (before doing the validate).
848 * wpa_supplicant tends to do iface changes on p2p device/client/go
849 * which are not always possible/allowed. However we need to return
850 * OK otherwise the wpa_supplicant wont start. The situation differs
851 * on configuration and setup (p2pon=1 module param). The first check
852 * is to see if the request is a change to station for p2p iface.
853 */
854 if ((type == NL80211_IFTYPE_STATION) &&
855 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
856 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
857 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
858 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
859 /* Now depending on whether module param p2pon=1 was used the
860 * response needs to be either 0 or EOPNOTSUPP. The reason is
861 * that if p2pon=1 is used, but a newer supplicant is used then
862 * we should return an error, as this combination wont work.
863 * In other situations 0 is returned and supplicant will start
864 * normally. It will give a trace in cfg80211, but it is the
865 * only way to get it working. Unfortunately this will result
866 * in situation where we wont support new supplicant in
867 * combination with module param p2pon=1, but that is the way
868 * it is. If the user tries this then unloading of driver might
869 * fail/lock.
870 */
871 if (cfg->p2p.p2pdev_dynamically)
872 return -EOPNOTSUPP;
873 else
874 return 0;
875 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200876 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
877 if (err) {
878 brcmf_err("iface validation failed: err=%d\n", err);
879 return err;
880 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200881 switch (type) {
882 case NL80211_IFTYPE_MONITOR:
883 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100884 brcmf_err("type (%d) : currently we do not support this type\n",
885 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200886 return -EOPNOTSUPP;
887 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200888 infra = 0;
889 break;
890 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200891 infra = 1;
892 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200893 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100894 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200895 ap = 1;
896 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200897 default:
898 err = -EINVAL;
899 goto done;
900 }
901
Hante Meuleman1a873342012-09-27 14:17:54 +0200902 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100903 if (type == NL80211_IFTYPE_P2P_GO) {
904 brcmf_dbg(INFO, "IF Type = P2P GO\n");
905 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
906 }
907 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100908 brcmf_dbg(INFO, "IF Type = AP\n");
909 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200910 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100911 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200912 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100913 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200914 err = -EAGAIN;
915 goto done;
916 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100917 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100918 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200919 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200920 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200921
Hante Meuleman8851cce2014-07-30 13:20:02 +0200922 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
923
Arend van Spriel5b435de2011-10-05 13:19:03 +0200924done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100925 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200926
927 return err;
928}
929
Franky Lin83cf17a2013-04-11 13:28:50 +0200930static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
931 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200932 struct cfg80211_scan_request *request)
933{
934 u32 n_ssids;
935 u32 n_channels;
936 s32 i;
937 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200938 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200939 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200940 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200941
Joe Perches93803b32015-03-02 19:54:49 -0800942 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200943 params_le->bss_type = DOT11_BSSTYPE_ANY;
944 params_le->scan_type = 0;
945 params_le->channel_num = 0;
946 params_le->nprobes = cpu_to_le32(-1);
947 params_le->active_time = cpu_to_le32(-1);
948 params_le->passive_time = cpu_to_le32(-1);
949 params_le->home_time = cpu_to_le32(-1);
950 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
951
952 /* if request is null exit so it will be all channel broadcast scan */
953 if (!request)
954 return;
955
956 n_ssids = request->n_ssids;
957 n_channels = request->n_channels;
958 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100959 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
960 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200961 if (n_channels > 0) {
962 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200963 chanspec = channel_to_chanspec(&cfg->d11inf,
964 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100965 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
966 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200967 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200968 }
969 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100970 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200971 }
972 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100973 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200974 if (n_ssids > 0) {
975 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
976 n_channels * sizeof(u16);
977 offset = roundup(offset, sizeof(u32));
978 ptr = (char *)params_le + offset;
979 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200980 memset(&ssid_le, 0, sizeof(ssid_le));
981 ssid_le.SSID_len =
982 cpu_to_le32(request->ssids[i].ssid_len);
983 memcpy(ssid_le.SSID, request->ssids[i].ssid,
984 request->ssids[i].ssid_len);
985 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100986 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200987 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100988 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
989 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200990 memcpy(ptr, &ssid_le, sizeof(ssid_le));
991 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200992 }
993 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100994 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200995 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100996 brcmf_dbg(SCAN, "SSID %s len=%d\n",
997 params_le->ssid_le.SSID,
998 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200999 params_le->ssid_le.SSID_len =
1000 cpu_to_le32(request->ssids->ssid_len);
1001 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
1002 request->ssids->ssid_len);
1003 }
1004 }
1005 /* Adding mask to channel numbers */
1006 params_le->channel_num =
1007 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
1008 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
1009}
1010
1011static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001012brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +01001013 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001014{
1015 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
1016 offsetof(struct brcmf_escan_params_le, params_le);
1017 struct brcmf_escan_params_le *params;
1018 s32 err = 0;
1019
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001020 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001021
1022 if (request != NULL) {
1023 /* Allocate space for populating ssids in struct */
1024 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
1025
1026 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001027 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +02001028 }
1029
1030 params = kzalloc(params_size, GFP_KERNEL);
1031 if (!params) {
1032 err = -ENOMEM;
1033 goto exit;
1034 }
1035 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +02001036 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001037 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +01001038 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +02001039 params->sync_id = cpu_to_le16(0x1234);
1040
Arend van Spriela0f472a2013-04-05 10:57:49 +02001041 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +02001042 if (err) {
1043 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001044 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001045 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001046 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001047 }
1048
1049 kfree(params);
1050exit:
1051 return err;
1052}
1053
1054static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001055brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001056 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001057{
1058 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001059 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001060 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001061 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001062
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001063 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001064 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001065 escan->wiphy = wiphy;
1066 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001067 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001068 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001069 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001070 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001071 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001072 return err;
1073 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001074 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001075 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001076 results->version = 0;
1077 results->count = 0;
1078 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1079
Hante Meulemanc4958102015-11-25 11:32:41 +01001080 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001081 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001082 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001083 return err;
1084}
1085
1086static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001087brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001088 struct cfg80211_scan_request *request,
1089 struct cfg80211_ssid *this_ssid)
1090{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001091 struct brcmf_if *ifp = vif->ifp;
1092 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001093 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001094 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001095 bool escan_req;
1096 bool spec_scan;
1097 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001098 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001099 u32 SSID_len;
1100
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001101 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001102
Arend van Sprielc1179032012-10-22 13:55:33 -07001103 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001104 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001105 return -EAGAIN;
1106 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001107 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001108 brcmf_err("Scanning being aborted: status (%lu)\n",
1109 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001110 return -EAGAIN;
1111 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001112 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1113 brcmf_err("Scanning suppressed: status (%lu)\n",
1114 cfg->scan_status);
1115 return -EAGAIN;
1116 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001117 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001118 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001119 return -EAGAIN;
1120 }
1121
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001122 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001123 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1124 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001125
Hante Meulemane756af52012-09-11 21:18:52 +02001126 escan_req = false;
1127 if (request) {
1128 /* scan bss */
1129 ssids = request->ssids;
1130 escan_req = true;
1131 } else {
1132 /* scan in ibss */
1133 /* we don't do escan in ibss */
1134 ssids = this_ssid;
1135 }
1136
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001137 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001138 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001139 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001140 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001141 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001142 if (err)
1143 goto scan_out;
1144
Arend van Spriela0f472a2013-04-05 10:57:49 +02001145 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001146 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001147 goto scan_out;
1148 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001149 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1150 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001151 memset(&ssid_le, 0, sizeof(ssid_le));
1152 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1153 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001154 spec_scan = false;
1155 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001156 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1157 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001158 spec_scan = true;
1159 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001160 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001161
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001162 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001163 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001164 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001165 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001166 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001167 goto scan_out;
1168 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001169 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001170 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1171 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001172 if (err) {
1173 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001174 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001175 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001176 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001177 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001178
Daniel Kim5e787f72014-06-21 12:11:18 +02001179 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001180 goto scan_out;
1181 }
1182 }
1183
Hante Meuleman661fa952015-02-06 18:36:47 +01001184 /* Arm scan timeout timer */
1185 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001186 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001187
Hante Meulemane756af52012-09-11 21:18:52 +02001188 return 0;
1189
1190scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001191 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001192 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001193 return err;
1194}
1195
Arend van Spriel5b435de2011-10-05 13:19:03 +02001196static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001197brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001198{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001199 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001200 s32 err = 0;
1201
Arend van Sprield96b8012012-12-05 15:26:02 +01001202 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001203 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1204 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001205 return -EIO;
1206
Arend van Spriela0f472a2013-04-05 10:57:49 +02001207 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001208
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001210 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211
Arend van Sprield96b8012012-12-05 15:26:02 +01001212 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001213 return err;
1214}
1215
1216static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1217{
1218 s32 err = 0;
1219
Arend van Sprielac24be62012-10-22 10:36:23 -07001220 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1221 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001223 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001224
1225 return err;
1226}
1227
1228static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1229{
1230 s32 err = 0;
1231
Arend van Sprielac24be62012-10-22 10:36:23 -07001232 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1233 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001234 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001235 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001236
1237 return err;
1238}
1239
1240static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1241{
1242 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001243 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001244
Arend van Sprielac24be62012-10-22 10:36:23 -07001245 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001246 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001247 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001248 return err;
1249 }
1250 return err;
1251}
1252
1253static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1254{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001255 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1256 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001257 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001258 s32 err = 0;
1259
Arend van Sprield96b8012012-12-05 15:26:02 +01001260 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001261 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262 return -EIO;
1263
1264 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001265 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1266 cfg->conf->rts_threshold = wiphy->rts_threshold;
1267 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001268 if (!err)
1269 goto done;
1270 }
1271 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001272 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1273 cfg->conf->frag_threshold = wiphy->frag_threshold;
1274 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 if (!err)
1276 goto done;
1277 }
1278 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001279 && (cfg->conf->retry_long != wiphy->retry_long)) {
1280 cfg->conf->retry_long = wiphy->retry_long;
1281 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001282 if (!err)
1283 goto done;
1284 }
1285 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001286 && (cfg->conf->retry_short != wiphy->retry_short)) {
1287 cfg->conf->retry_short = wiphy->retry_short;
1288 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001289 if (!err)
1290 goto done;
1291 }
1292
1293done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001294 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295 return err;
1296}
1297
Arend van Spriel5b435de2011-10-05 13:19:03 +02001298static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1299{
1300 memset(prof, 0, sizeof(*prof));
1301}
1302
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001303static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1304{
1305 u16 reason;
1306
1307 switch (e->event_code) {
1308 case BRCMF_E_DEAUTH:
1309 case BRCMF_E_DEAUTH_IND:
1310 case BRCMF_E_DISASSOC_IND:
1311 reason = e->reason;
1312 break;
1313 case BRCMF_E_LINK:
1314 default:
1315 reason = 0;
1316 break;
1317 }
1318 return reason;
1319}
1320
1321static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001322{
Piotr Haber61730d42013-04-23 12:53:12 +02001323 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324 s32 err = 0;
1325
Arend van Sprield96b8012012-12-05 15:26:02 +01001326 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001327
Hante Meulemanb0a79082015-12-10 13:43:07 +01001328 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001329 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001330 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001331 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001332 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001333 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001334 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001335 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1336 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1337 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1338 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001339 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001340 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001341 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1342 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001343 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001344}
1345
1346static s32
1347brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1348 struct cfg80211_ibss_params *params)
1349{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001350 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001351 struct brcmf_if *ifp = netdev_priv(ndev);
1352 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353 struct brcmf_join_params join_params;
1354 size_t join_params_size = 0;
1355 s32 err = 0;
1356 s32 wsec = 0;
1357 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001358 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001359 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001360
Arend van Sprield96b8012012-12-05 15:26:02 +01001361 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001362 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001363 return -EIO;
1364
1365 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001366 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001367 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001368 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001369 return -EOPNOTSUPP;
1370 }
1371
Arend van Sprielc1179032012-10-22 13:55:33 -07001372 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001373
1374 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001375 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001376 else
Arend van Spriel16886732012-12-05 15:26:04 +01001377 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001378
Johannes Berg683b6d32012-11-08 21:25:48 +01001379 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001380 brcmf_dbg(CONN, "channel: %d\n",
1381 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001382 else
Arend van Spriel16886732012-12-05 15:26:04 +01001383 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001384
1385 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001386 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387 else
Arend van Spriel16886732012-12-05 15:26:04 +01001388 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001389
1390 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001391 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001392 else
Arend van Spriel16886732012-12-05 15:26:04 +01001393 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001394
1395 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001396 brcmf_dbg(CONN, "beacon interval: %d\n",
1397 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001398 else
Arend van Spriel16886732012-12-05 15:26:04 +01001399 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001400
1401 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001402 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001403 else
Arend van Spriel16886732012-12-05 15:26:04 +01001404 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001405
1406 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001407 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 else
Arend van Spriel16886732012-12-05 15:26:04 +01001409 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410
1411 /* Configure Privacy for starter */
1412 if (params->privacy)
1413 wsec |= WEP_ENABLED;
1414
Arend van Sprielc1179032012-10-22 13:55:33 -07001415 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001416 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001417 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418 goto done;
1419 }
1420
1421 /* Configure Beacon Interval for starter */
1422 if (params->beacon_interval)
1423 bcnprd = params->beacon_interval;
1424 else
1425 bcnprd = 100;
1426
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001427 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001428 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001429 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430 goto done;
1431 }
1432
1433 /* Configure required join parameter */
1434 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1435
1436 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001437 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1438 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1439 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001441
1442 /* BSSID */
1443 if (params->bssid) {
1444 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001445 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001446 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001447 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001448 eth_broadcast_addr(join_params.params_le.bssid);
1449 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001450 }
1451
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001453 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001454 u32 target_channel;
1455
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001456 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001457 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001458 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001459 if (params->channel_fixed) {
1460 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001461 chanspec = chandef_to_chanspec(&cfg->d11inf,
1462 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001463 join_params.params_le.chanspec_list[0] =
1464 cpu_to_le16(chanspec);
1465 join_params.params_le.chanspec_num = cpu_to_le32(1);
1466 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467 }
1468
1469 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001470 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001471 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001472 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001474 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001475 goto done;
1476 }
1477 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001478 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001480 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001481
1482
Arend van Sprielc1179032012-10-22 13:55:33 -07001483 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001484 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001485 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001486 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487 goto done;
1488 }
1489
1490done:
1491 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001492 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001493 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001494 return err;
1495}
1496
1497static s32
1498brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1499{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001500 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501
Arend van Sprield96b8012012-12-05 15:26:02 +01001502 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001503 if (!check_vif_up(ifp->vif)) {
1504 /* When driver is being unloaded, it can end up here. If an
1505 * error is returned then later on a debug trace in the wireless
1506 * core module will be printed. To avoid this 0 is returned.
1507 */
1508 return 0;
1509 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001511 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001512 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001513
Arend van Sprield96b8012012-12-05 15:26:02 +01001514 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001515
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001516 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001517}
1518
1519static s32 brcmf_set_wpa_version(struct net_device *ndev,
1520 struct cfg80211_connect_params *sme)
1521{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001522 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001523 struct brcmf_cfg80211_security *sec;
1524 s32 val = 0;
1525 s32 err = 0;
1526
1527 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1528 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1529 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1530 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1531 else
1532 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001533 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001534 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001535 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001536 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537 return err;
1538 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001539 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540 sec->wpa_versions = sme->crypto.wpa_versions;
1541 return err;
1542}
1543
1544static s32 brcmf_set_auth_type(struct net_device *ndev,
1545 struct cfg80211_connect_params *sme)
1546{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001547 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001548 struct brcmf_cfg80211_security *sec;
1549 s32 val = 0;
1550 s32 err = 0;
1551
1552 switch (sme->auth_type) {
1553 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1554 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001555 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001556 break;
1557 case NL80211_AUTHTYPE_SHARED_KEY:
1558 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001559 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001560 break;
1561 case NL80211_AUTHTYPE_AUTOMATIC:
1562 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001563 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001564 break;
1565 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001566 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001567 default:
1568 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001569 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001570 break;
1571 }
1572
Hante Meuleman89286dc2013-02-08 15:53:46 +01001573 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001574 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001575 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001576 return err;
1577 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001578 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001579 sec->auth_type = sme->auth_type;
1580 return err;
1581}
1582
1583static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001584brcmf_set_wsec_mode(struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01001585 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001587 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001588 struct brcmf_cfg80211_security *sec;
1589 s32 pval = 0;
1590 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001591 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001592 s32 err = 0;
1593
1594 if (sme->crypto.n_ciphers_pairwise) {
1595 switch (sme->crypto.ciphers_pairwise[0]) {
1596 case WLAN_CIPHER_SUITE_WEP40:
1597 case WLAN_CIPHER_SUITE_WEP104:
1598 pval = WEP_ENABLED;
1599 break;
1600 case WLAN_CIPHER_SUITE_TKIP:
1601 pval = TKIP_ENABLED;
1602 break;
1603 case WLAN_CIPHER_SUITE_CCMP:
1604 pval = AES_ENABLED;
1605 break;
1606 case WLAN_CIPHER_SUITE_AES_CMAC:
1607 pval = AES_ENABLED;
1608 break;
1609 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001610 brcmf_err("invalid cipher pairwise (%d)\n",
1611 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612 return -EINVAL;
1613 }
1614 }
1615 if (sme->crypto.cipher_group) {
1616 switch (sme->crypto.cipher_group) {
1617 case WLAN_CIPHER_SUITE_WEP40:
1618 case WLAN_CIPHER_SUITE_WEP104:
1619 gval = WEP_ENABLED;
1620 break;
1621 case WLAN_CIPHER_SUITE_TKIP:
1622 gval = TKIP_ENABLED;
1623 break;
1624 case WLAN_CIPHER_SUITE_CCMP:
1625 gval = AES_ENABLED;
1626 break;
1627 case WLAN_CIPHER_SUITE_AES_CMAC:
1628 gval = AES_ENABLED;
1629 break;
1630 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001631 brcmf_err("invalid cipher group (%d)\n",
1632 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001633 return -EINVAL;
1634 }
1635 }
1636
Arend van Spriel16886732012-12-05 15:26:04 +01001637 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001638 /* In case of privacy, but no security and WPS then simulate */
1639 /* setting AES. WPS-2.0 allows no security */
1640 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1641 sme->privacy)
1642 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001643
Hante Meuleman240d61a2016-02-17 11:27:10 +01001644 wsec = pval | gval;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001645 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001647 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001648 return err;
1649 }
1650
Arend van Spriel06bb1232012-09-27 14:17:56 +02001651 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001652 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1653 sec->cipher_group = sme->crypto.cipher_group;
1654
1655 return err;
1656}
1657
1658static s32
1659brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1660{
Hante Meuleman240d61a2016-02-17 11:27:10 +01001661 struct brcmf_if *ifp = netdev_priv(ndev);
1662 s32 val;
1663 s32 err;
1664 const struct brcmf_tlv *rsn_ie;
1665 const u8 *ie;
1666 u32 ie_len;
1667 u32 offset;
1668 u16 rsn_cap;
1669 u32 mfp;
1670 u16 count;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001671
Hante Meuleman240d61a2016-02-17 11:27:10 +01001672 if (!sme->crypto.n_akm_suites)
1673 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001674
Hante Meuleman240d61a2016-02-17 11:27:10 +01001675 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
1676 if (err) {
1677 brcmf_err("could not get wpa_auth (%d)\n", err);
1678 return err;
1679 }
1680 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1681 switch (sme->crypto.akm_suites[0]) {
1682 case WLAN_AKM_SUITE_8021X:
1683 val = WPA_AUTH_UNSPECIFIED;
1684 break;
1685 case WLAN_AKM_SUITE_PSK:
1686 val = WPA_AUTH_PSK;
1687 break;
1688 default:
1689 brcmf_err("invalid cipher group (%d)\n",
1690 sme->crypto.cipher_group);
1691 return -EINVAL;
1692 }
1693 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1694 switch (sme->crypto.akm_suites[0]) {
1695 case WLAN_AKM_SUITE_8021X:
1696 val = WPA2_AUTH_UNSPECIFIED;
1697 break;
1698 case WLAN_AKM_SUITE_8021X_SHA256:
1699 val = WPA2_AUTH_1X_SHA256;
1700 break;
1701 case WLAN_AKM_SUITE_PSK_SHA256:
1702 val = WPA2_AUTH_PSK_SHA256;
1703 break;
1704 case WLAN_AKM_SUITE_PSK:
1705 val = WPA2_AUTH_PSK;
1706 break;
1707 default:
1708 brcmf_err("invalid cipher group (%d)\n",
1709 sme->crypto.cipher_group);
1710 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001711 }
1712 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01001713
1714 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
1715 goto skip_mfp_config;
1716 /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
1717 * IE will not be verified, just a quick search for MFP config
1718 */
1719 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
1720 WLAN_EID_RSN);
1721 if (!rsn_ie)
1722 goto skip_mfp_config;
1723 ie = (const u8 *)rsn_ie;
1724 ie_len = rsn_ie->len + TLV_HDR_LEN;
1725 /* Skip unicast suite */
1726 offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
1727 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1728 goto skip_mfp_config;
1729 /* Skip multicast suite */
1730 count = ie[offset] + (ie[offset + 1] << 8);
1731 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1732 if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
1733 goto skip_mfp_config;
1734 /* Skip auth key management suite(s) */
1735 count = ie[offset] + (ie[offset + 1] << 8);
1736 offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
1737 if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
1738 goto skip_mfp_config;
1739 /* Ready to read capabilities */
1740 mfp = BRCMF_MFP_NONE;
1741 rsn_cap = ie[offset] + (ie[offset + 1] << 8);
1742 if (rsn_cap & RSN_CAP_MFPR_MASK)
1743 mfp = BRCMF_MFP_REQUIRED;
1744 else if (rsn_cap & RSN_CAP_MFPC_MASK)
1745 mfp = BRCMF_MFP_CAPABLE;
1746 brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
1747
1748skip_mfp_config:
1749 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1750 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1751 if (err) {
1752 brcmf_err("could not set wpa_auth (%d)\n", err);
1753 return err;
1754 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001755
1756 return err;
1757}
1758
1759static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001760brcmf_set_sharedkey(struct net_device *ndev,
1761 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001762{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001763 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001764 struct brcmf_cfg80211_security *sec;
1765 struct brcmf_wsec_key key;
1766 s32 val;
1767 s32 err = 0;
1768
Arend van Spriel16886732012-12-05 15:26:04 +01001769 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770
Roland Vossena718e2f2011-10-12 20:51:24 +02001771 if (sme->key_len == 0)
1772 return 0;
1773
Arend van Spriel06bb1232012-09-27 14:17:56 +02001774 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001775 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1776 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001777
1778 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1779 return 0;
1780
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001781 if (!(sec->cipher_pairwise &
1782 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1783 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001784
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001785 memset(&key, 0, sizeof(key));
1786 key.len = (u32) sme->key_len;
1787 key.index = (u32) sme->key_idx;
1788 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001789 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001790 return -EINVAL;
1791 }
1792 memcpy(key.data, sme->key, key.len);
1793 key.flags = BRCMF_PRIMARY_KEY;
1794 switch (sec->cipher_pairwise) {
1795 case WLAN_CIPHER_SUITE_WEP40:
1796 key.algo = CRYPTO_ALGO_WEP1;
1797 break;
1798 case WLAN_CIPHER_SUITE_WEP104:
1799 key.algo = CRYPTO_ALGO_WEP128;
1800 break;
1801 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001802 brcmf_err("Invalid algorithm (%d)\n",
1803 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001804 return -EINVAL;
1805 }
1806 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001807 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1808 key.len, key.index, key.algo);
1809 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001810 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001811 if (err)
1812 return err;
1813
1814 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001815 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001816 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001817 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001818 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001819 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001820 }
1821 return err;
1822}
1823
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001824static
1825enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1826 enum nl80211_auth_type type)
1827{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001828 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1829 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1830 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1831 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001832 }
1833 return type;
1834}
1835
Arend van Spriel7705ba62016-04-17 16:44:58 +02001836static void brcmf_set_join_pref(struct brcmf_if *ifp,
1837 struct cfg80211_bss_selection *bss_select)
1838{
1839 struct brcmf_join_pref_params join_pref_params[2];
1840 enum nl80211_band band;
1841 int err, i = 0;
1842
1843 join_pref_params[i].len = 2;
1844 join_pref_params[i].rssi_gain = 0;
1845
1846 if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
1847 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
1848
1849 switch (bss_select->behaviour) {
1850 case __NL80211_BSS_SELECT_ATTR_INVALID:
1851 brcmf_c_set_joinpref_default(ifp);
1852 return;
1853 case NL80211_BSS_SELECT_ATTR_BAND_PREF:
1854 join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
1855 band = bss_select->param.band_pref;
1856 join_pref_params[i].band = nl80211_band_to_fwil(band);
1857 i++;
1858 break;
1859 case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
1860 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
1861 band = bss_select->param.adjust.band;
1862 join_pref_params[i].band = nl80211_band_to_fwil(band);
1863 join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
1864 i++;
1865 break;
1866 case NL80211_BSS_SELECT_ATTR_RSSI:
1867 default:
1868 break;
1869 }
1870 join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
1871 join_pref_params[i].len = 2;
1872 join_pref_params[i].rssi_gain = 0;
1873 join_pref_params[i].band = 0;
1874 err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
1875 sizeof(join_pref_params));
1876 if (err)
1877 brcmf_err("Set join_pref error (%d)\n", err);
1878}
1879
Arend van Spriel5b435de2011-10-05 13:19:03 +02001880static s32
1881brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001882 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001883{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001884 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001885 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001886 struct ieee80211_channel *chan = sme->channel;
1887 struct brcmf_join_params join_params;
1888 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001889 const struct brcmf_tlv *rsn_ie;
1890 const struct brcmf_vs_tlv *wpa_ie;
1891 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001892 u32 ie_len;
1893 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001894 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001895 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001896 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001897
Arend van Sprield96b8012012-12-05 15:26:02 +01001898 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001899 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900 return -EIO;
1901
1902 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001903 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001904 return -EOPNOTSUPP;
1905 }
1906
Hante Meuleman89286dc2013-02-08 15:53:46 +01001907 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1908 /* A normal (non P2P) connection request setup. */
1909 ie = NULL;
1910 ie_len = 0;
1911 /* find the WPA_IE */
1912 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1913 if (wpa_ie) {
1914 ie = wpa_ie;
1915 ie_len = wpa_ie->len + TLV_HDR_LEN;
1916 } else {
1917 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001918 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1919 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001920 WLAN_EID_RSN);
1921 if (rsn_ie) {
1922 ie = rsn_ie;
1923 ie_len = rsn_ie->len + TLV_HDR_LEN;
1924 }
1925 }
1926 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1927 }
1928
1929 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1930 sme->ie, sme->ie_len);
1931 if (err)
1932 brcmf_err("Set Assoc REQ IE Failed\n");
1933 else
1934 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1935
Arend van Sprielc1179032012-10-22 13:55:33 -07001936 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001937
1938 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001939 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001940 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001941 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001942 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1943 cfg->channel, chan->center_freq, chanspec);
1944 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001945 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001946 chanspec = 0;
1947 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001948
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001949 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950
1951 err = brcmf_set_wpa_version(ndev, sme);
1952 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001953 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001954 goto done;
1955 }
1956
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001957 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001958 err = brcmf_set_auth_type(ndev, sme);
1959 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001960 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001961 goto done;
1962 }
1963
Hante Meuleman240d61a2016-02-17 11:27:10 +01001964 err = brcmf_set_wsec_mode(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001966 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001967 goto done;
1968 }
1969
1970 err = brcmf_set_key_mgmt(ndev, sme);
1971 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001972 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001973 goto done;
1974 }
1975
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001976 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001977 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001978 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001979 goto done;
1980 }
1981
Hante Meuleman89286dc2013-02-08 15:53:46 +01001982 /* Join with specific BSSID and cached SSID
1983 * If SSID is zero join based on BSSID only
1984 */
1985 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1986 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1987 if (cfg->channel)
1988 join_params_size += sizeof(u16);
1989 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1990 if (ext_join_params == NULL) {
1991 err = -ENOMEM;
1992 goto done;
1993 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001994 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1995 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1996 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1997 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1998 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1999 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002000
Hante Meuleman89286dc2013-02-08 15:53:46 +01002001 /* Set up join scan parameters */
2002 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01002003 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
2004
2005 if (sme->bssid)
2006 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
2007 else
Joe Perches93803b32015-03-02 19:54:49 -08002008 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002009
2010 if (cfg->channel) {
2011 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
2012
2013 ext_join_params->assoc_le.chanspec_list[0] =
2014 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01002015 /* Increase dwell time to receive probe response or detect
2016 * beacon from target AP at a noisy air only during connect
2017 * command.
2018 */
2019 ext_join_params->scan_le.active_time =
2020 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
2021 ext_join_params->scan_le.passive_time =
2022 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
2023 /* To sync with presence period of VSDB GO send probe request
2024 * more frequently. Probe request will be stopped when it gets
2025 * probe response from target AP/GO.
2026 */
2027 ext_join_params->scan_le.nprobes =
2028 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
2029 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
2030 } else {
2031 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
2032 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
2033 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01002034 }
2035
Arend van Spriel7705ba62016-04-17 16:44:58 +02002036 brcmf_set_join_pref(ifp, &sme->bss_select);
2037
Hante Meuleman89286dc2013-02-08 15:53:46 +01002038 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
2039 join_params_size);
2040 kfree(ext_join_params);
2041 if (!err)
2042 /* This is it. join command worked, we are done */
2043 goto done;
2044
2045 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046 memset(&join_params, 0, sizeof(join_params));
2047 join_params_size = sizeof(join_params.ssid_le);
2048
Hante Meulemane9a6ca82015-11-25 11:32:37 +01002049 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
2050 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002051
Hante Meuleman89286dc2013-02-08 15:53:46 +01002052 if (sme->bssid)
2053 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
2054 else
Joe Perches93803b32015-03-02 19:54:49 -08002055 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056
Hante Meuleman17012612013-02-06 18:40:44 +01002057 if (cfg->channel) {
2058 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
2059 join_params.params_le.chanspec_num = cpu_to_le32(1);
2060 join_params_size += sizeof(join_params.params_le);
2061 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002062 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002063 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01002065 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066
2067done:
2068 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07002069 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01002070 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002071 return err;
2072}
2073
2074static s32
2075brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2076 u16 reason_code)
2077{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002078 struct brcmf_if *ifp = netdev_priv(ndev);
2079 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 struct brcmf_scb_val_le scbval;
2081 s32 err = 0;
2082
Arend van Sprield96b8012012-12-05 15:26:02 +01002083 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07002084 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002085 return -EIO;
2086
Arend van Sprielc1179032012-10-22 13:55:33 -07002087 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01002088 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02002089 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002090
Arend van Spriel06bb1232012-09-27 14:17:56 +02002091 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002092 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07002093 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07002094 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002096 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002097
Arend van Sprield96b8012012-12-05 15:26:02 +01002098 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002099 return err;
2100}
2101
2102static s32
Johannes Bergc8442112012-10-24 10:17:18 +02002103brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05002104 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002106 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002107 struct net_device *ndev = cfg_to_ndev(cfg);
2108 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002109 s32 err;
2110 s32 disable;
2111 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002113 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07002114 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 return -EIO;
2116
2117 switch (type) {
2118 case NL80211_TX_POWER_AUTOMATIC:
2119 break;
2120 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02002121 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002122 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002123 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002124 err = -EINVAL;
2125 goto done;
2126 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002127 qdbm = MBM_TO_DBM(4 * mbm);
2128 if (qdbm > 127)
2129 qdbm = 127;
2130 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002132 default:
2133 brcmf_err("Unsupported type %d\n", type);
2134 err = -EINVAL;
2135 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136 }
2137 /* Make sure radio is off or on as far as software is concerned */
2138 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002139 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002140 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002141 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002143 err = brcmf_fil_iovar_int_set(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("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002146
2147done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002148 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 return err;
2150}
2151
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002152static s32
2153brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2154 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002156 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002157 struct net_device *ndev = cfg_to_ndev(cfg);
2158 struct brcmf_if *ifp = netdev_priv(ndev);
2159 s32 qdbm = 0;
2160 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002161
Arend van Sprield96b8012012-12-05 15:26:02 +01002162 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002163 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 return -EIO;
2165
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002166 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002168 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 goto done;
2170 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002171 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002172
2173done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002174 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002175 return err;
2176}
2177
2178static s32
2179brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002180 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002182 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002183 u32 index;
2184 u32 wsec;
2185 s32 err = 0;
2186
Arend van Sprield96b8012012-12-05 15:26:02 +01002187 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002188 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002189 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002190 return -EIO;
2191
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002192 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002193 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002194 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195 goto done;
2196 }
2197
2198 if (wsec & WEP_ENABLED) {
2199 /* Just select a new current key */
2200 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002201 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002202 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002203 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002204 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002205 }
2206done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002207 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002208 return err;
2209}
2210
2211static s32
Hante Meuleman219e0f72016-02-17 11:27:09 +01002212brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2213 u8 key_idx, bool pairwise, const u8 *mac_addr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002214{
Hante Meuleman992f6062013-04-02 21:06:17 +02002215 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman240d61a2016-02-17 11:27:10 +01002216 struct brcmf_wsec_key *key;
2217 s32 err;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002218
2219 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman240d61a2016-02-17 11:27:10 +01002220 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2221
Hante Meuleman219e0f72016-02-17 11:27:09 +01002222 if (!check_vif_up(ifp->vif))
2223 return -EIO;
2224
2225 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2226 /* we ignore this key index in this case */
2227 return -EINVAL;
2228 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229
Hante Meuleman240d61a2016-02-17 11:27:10 +01002230 key = &ifp->vif->profile.key[key_idx];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002231
Hante Meuleman240d61a2016-02-17 11:27:10 +01002232 if (key->algo == CRYPTO_ALGO_OFF) {
2233 brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
2234 return -EINVAL;
2235 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236
Hante Meuleman240d61a2016-02-17 11:27:10 +01002237 memset(key, 0, sizeof(*key));
2238 key->index = (u32)key_idx;
2239 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002240
Hante Meuleman240d61a2016-02-17 11:27:10 +01002241 /* Clear the key/index */
2242 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002243
Hante Meuleman219e0f72016-02-17 11:27:09 +01002244 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 return err;
2246}
2247
2248static s32
2249brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002250 u8 key_idx, bool pairwise, const u8 *mac_addr,
2251 struct key_params *params)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002252{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002253 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002254 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002255 s32 val;
2256 s32 wsec;
Hante Meuleman219e0f72016-02-17 11:27:09 +01002257 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002258 u8 keybuf[8];
Hante Meuleman219e0f72016-02-17 11:27:09 +01002259 bool ext_key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Arend van Sprield96b8012012-12-05 15:26:02 +01002261 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002262 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002263 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002264 return -EIO;
2265
Hante Meuleman118eb302014-12-21 12:43:49 +01002266 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2267 /* we ignore this key index in this case */
2268 brcmf_err("invalid key index (%d)\n", key_idx);
2269 return -EINVAL;
2270 }
2271
Hante Meuleman219e0f72016-02-17 11:27:09 +01002272 if (params->key_len == 0)
2273 return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
2274 mac_addr);
2275
2276 if (params->key_len > sizeof(key->data)) {
2277 brcmf_err("Too long key length (%u)\n", params->key_len);
2278 return -EINVAL;
2279 }
2280
2281 ext_key = false;
2282 if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2283 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2284 brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
2285 ext_key = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002286 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002287
Hante Meuleman118eb302014-12-21 12:43:49 +01002288 key = &ifp->vif->profile.key[key_idx];
2289 memset(key, 0, sizeof(*key));
Hante Meuleman219e0f72016-02-17 11:27:09 +01002290 if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
2291 memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
Hante Meuleman118eb302014-12-21 12:43:49 +01002292 key->len = params->key_len;
2293 key->index = key_idx;
Hante Meuleman118eb302014-12-21 12:43:49 +01002294 memcpy(key->data, params->key, key->len);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002295 if (!ext_key)
2296 key->flags = BRCMF_PRIMARY_KEY;
Hante Meuleman118eb302014-12-21 12:43:49 +01002297
Arend van Spriel5b435de2011-10-05 13:19:03 +02002298 switch (params->cipher) {
2299 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002300 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002301 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002302 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002303 break;
2304 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002305 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002306 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002307 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002308 break;
2309 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002310 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002311 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002312 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2313 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2314 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002315 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002316 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002317 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002318 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002319 break;
2320 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002321 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002322 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002323 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324 break;
2325 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002326 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002327 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002328 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002329 break;
2330 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002331 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332 err = -EINVAL;
2333 goto done;
2334 }
2335
Hante Meuleman118eb302014-12-21 12:43:49 +01002336 err = send_key_to_dongle(ifp, key);
Hante Meuleman219e0f72016-02-17 11:27:09 +01002337 if (ext_key || err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002338 goto done;
2339
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002340 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002341 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002342 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002343 goto done;
2344 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002345 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002346 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002347 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002348 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002349 goto done;
2350 }
2351
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002353 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002354 return err;
2355}
2356
2357static s32
Hante Meuleman240d61a2016-02-17 11:27:10 +01002358brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
2359 bool pairwise, const u8 *mac_addr, void *cookie,
2360 void (*callback)(void *cookie,
2361 struct key_params *params))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002362{
2363 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002364 struct brcmf_if *ifp = netdev_priv(ndev);
2365 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 struct brcmf_cfg80211_security *sec;
2367 s32 wsec;
2368 s32 err = 0;
2369
Arend van Sprield96b8012012-12-05 15:26:02 +01002370 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002371 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002372 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373 return -EIO;
2374
2375 memset(&params, 0, sizeof(params));
2376
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002377 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002379 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002380 /* Ignore this error, may happen during DISASSOC */
2381 err = -EAGAIN;
2382 goto done;
2383 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002384 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002385 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2387 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002388 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002389 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2390 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002391 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002392 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002393 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002395 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002396 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002397 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002398 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002399 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002400 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002401 err = -EINVAL;
2402 goto done;
2403 }
2404 callback(cookie, &params);
2405
2406done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002407 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002408 return err;
2409}
2410
2411static s32
2412brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
Hante Meuleman240d61a2016-02-17 11:27:10 +01002413 struct net_device *ndev, u8 key_idx)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002414{
Hante Meuleman240d61a2016-02-17 11:27:10 +01002415 struct brcmf_if *ifp = netdev_priv(ndev);
2416
2417 brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
2418
2419 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
2420 return 0;
2421
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002422 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002423
2424 return -EOPNOTSUPP;
2425}
2426
Hante Meuleman118eb302014-12-21 12:43:49 +01002427static void
2428brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2429{
2430 s32 err;
2431 u8 key_idx;
2432 struct brcmf_wsec_key *key;
2433 s32 wsec;
2434
2435 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2436 key = &ifp->vif->profile.key[key_idx];
2437 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2438 (key->algo == CRYPTO_ALGO_WEP128))
2439 break;
2440 }
2441 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2442 return;
2443
2444 err = send_key_to_dongle(ifp, key);
2445 if (err) {
2446 brcmf_err("Setting WEP key failed (%d)\n", err);
2447 return;
2448 }
2449 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2450 if (err) {
2451 brcmf_err("get wsec error (%d)\n", err);
2452 return;
2453 }
2454 wsec |= WEP_ENABLED;
2455 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2456 if (err)
2457 brcmf_err("set wsec error (%d)\n", err);
2458}
2459
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002460static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2461{
2462 struct nl80211_sta_flag_update *sfu;
2463
2464 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2465 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2466 sfu = &si->sta_flags;
2467 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2468 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2469 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2470 BIT(NL80211_STA_FLAG_AUTHORIZED);
2471 if (fw_sta_flags & BRCMF_STA_WME)
2472 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2473 if (fw_sta_flags & BRCMF_STA_AUTHE)
2474 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2475 if (fw_sta_flags & BRCMF_STA_ASSOC)
2476 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2477 if (fw_sta_flags & BRCMF_STA_AUTHO)
2478 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2479}
2480
2481static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2482{
2483 struct {
2484 __le32 len;
2485 struct brcmf_bss_info_le bss_le;
2486 } *buf;
2487 u16 capability;
2488 int err;
2489
2490 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2491 if (!buf)
2492 return;
2493
2494 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2495 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2496 WL_BSS_INFO_MAX);
2497 if (err) {
2498 brcmf_err("Failed to get bss info (%d)\n", err);
2499 return;
2500 }
2501 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2502 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2503 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2504 capability = le16_to_cpu(buf->bss_le.capability);
2505 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2506 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2507 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2508 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2509 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2510 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2511}
2512
Arend van Spriel5b435de2011-10-05 13:19:03 +02002513static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002514brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2515 struct station_info *sinfo)
2516{
2517 struct brcmf_scb_val_le scbval;
2518 struct brcmf_pktcnt_le pktcnt;
2519 s32 err;
2520 u32 rate;
2521 u32 rssi;
2522
2523 /* Get the current tx rate */
2524 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2525 if (err < 0) {
2526 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2527 return err;
2528 }
2529 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2530 sinfo->txrate.legacy = rate * 5;
2531
2532 memset(&scbval, 0, sizeof(scbval));
2533 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2534 sizeof(scbval));
2535 if (err) {
2536 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2537 return err;
2538 }
2539 rssi = le32_to_cpu(scbval.val);
2540 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2541 sinfo->signal = rssi;
2542
2543 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2544 sizeof(pktcnt));
2545 if (err) {
2546 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2547 return err;
2548 }
2549 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2550 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2551 BIT(NL80211_STA_INFO_TX_PACKETS) |
2552 BIT(NL80211_STA_INFO_TX_FAILED);
2553 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2554 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2555 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2556 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2557
2558 return 0;
2559}
2560
2561static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002562brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002563 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002564{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002565 struct brcmf_if *ifp = netdev_priv(ndev);
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002566 struct brcmf_scb_val_le scb_val;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002567 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002568 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002569 u32 sta_flags;
2570 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002571 s32 total_rssi;
2572 s32 count_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002573 int rssi;
Hante Meulemancae355d2015-10-08 20:33:17 +02002574 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002575
Arend van Sprield96b8012012-12-05 15:26:02 +01002576 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002577 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002578 return -EIO;
2579
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002580 if (brcmf_is_ibssmode(ifp->vif))
2581 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2582
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002583 memset(&sta_info_le, 0, sizeof(sta_info_le));
2584 memcpy(&sta_info_le, mac, ETH_ALEN);
2585 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2586 &sta_info_le,
2587 sizeof(sta_info_le));
2588 is_tdls_peer = !err;
2589 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002590 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002591 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002592 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002593 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002594 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002595 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002596 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002597 }
2598 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2599 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2600 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2601 sta_flags = le32_to_cpu(sta_info_le.flags);
2602 brcmf_convert_sta_flags(sta_flags, sinfo);
2603 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2604 if (is_tdls_peer)
2605 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2606 else
2607 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2608 if (sta_flags & BRCMF_STA_ASSOC) {
2609 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2610 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2611 brcmf_fill_bss_param(ifp, sinfo);
2612 }
2613 if (sta_flags & BRCMF_STA_SCBSTATS) {
2614 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2615 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2616 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2617 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2618 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2619 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2620 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2621 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2622 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002623 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002624 sinfo->txrate.legacy =
2625 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002626 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002627 if (sinfo->rx_packets) {
2628 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002629 sinfo->rxrate.legacy =
2630 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002631 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002632 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2633 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2634 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2635 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2636 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2637 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002638 total_rssi = 0;
2639 count_rssi = 0;
2640 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2641 if (sta_info_le.rssi[i]) {
2642 sinfo->chain_signal_avg[count_rssi] =
2643 sta_info_le.rssi[i];
2644 sinfo->chain_signal[count_rssi] =
2645 sta_info_le.rssi[i];
2646 total_rssi += sta_info_le.rssi[i];
2647 count_rssi++;
2648 }
2649 }
2650 if (count_rssi) {
2651 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2652 sinfo->chains = count_rssi;
2653
2654 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2655 total_rssi /= count_rssi;
2656 sinfo->signal = total_rssi;
Jaap Jan Meijer94abd772016-05-12 18:25:08 +02002657 } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2658 &ifp->vif->sme_state)) {
2659 memset(&scb_val, 0, sizeof(scb_val));
2660 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2661 &scb_val, sizeof(scb_val));
2662 if (err) {
2663 brcmf_err("Could not get rssi (%d)\n", err);
2664 goto done;
2665 } else {
2666 rssi = le32_to_cpu(scb_val.val);
2667 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2668 sinfo->signal = rssi;
2669 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
2670 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002671 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002672 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002673done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002674 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002675 return err;
2676}
2677
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002678static int
2679brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2680 int idx, u8 *mac, struct station_info *sinfo)
2681{
2682 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2683 struct brcmf_if *ifp = netdev_priv(ndev);
2684 s32 err;
2685
2686 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2687
2688 if (idx == 0) {
2689 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2690 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2691 &cfg->assoclist,
2692 sizeof(cfg->assoclist));
2693 if (err) {
2694 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2695 err);
2696 cfg->assoclist.count = 0;
2697 return -EOPNOTSUPP;
2698 }
2699 }
2700 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2701 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2702 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2703 }
2704 return -ENOENT;
2705}
2706
Arend van Spriel5b435de2011-10-05 13:19:03 +02002707static s32
2708brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2709 bool enabled, s32 timeout)
2710{
2711 s32 pm;
2712 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002713 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002714 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002715
Arend van Sprield96b8012012-12-05 15:26:02 +01002716 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002717
2718 /*
2719 * Powersave enable/disable request is coming from the
2720 * cfg80211 even before the interface is up. In that
2721 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002722 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002723 * FW later while initializing the dongle
2724 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002725 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002726 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002727
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002728 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002729 goto done;
2730 }
2731
2732 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002733 /* Do not enable the power save after assoc if it is a p2p interface */
2734 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2735 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2736 pm = PM_OFF;
2737 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002738 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739
Arend van Sprielc1179032012-10-22 13:55:33 -07002740 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002741 if (err) {
2742 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002743 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002744 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002745 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002746 }
2747done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002748 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002749 return err;
2750}
2751
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002752static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002753 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002754{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002755 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756 struct ieee80211_channel *notify_channel;
2757 struct cfg80211_bss *bss;
2758 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002759 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002760 u16 channel;
2761 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002762 u16 notify_capability;
2763 u16 notify_interval;
2764 u8 *notify_ie;
2765 size_t notify_ielen;
2766 s32 notify_signal;
2767
2768 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002769 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002770 return 0;
2771 }
2772
Franky Lin83cf17a2013-04-11 13:28:50 +02002773 if (!bi->ctl_ch) {
2774 ch.chspec = le16_to_cpu(bi->chanspec);
2775 cfg->d11inf.decchspec(&ch);
Rafał Miłecki4712d882016-05-20 13:38:57 +02002776 bi->ctl_ch = ch.control_ch_num;
Franky Lin83cf17a2013-04-11 13:28:50 +02002777 }
2778 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002779
2780 if (channel <= CH_MAX_2G_CHANNEL)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002781 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002782 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002783 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002784
2785 freq = ieee80211_channel_to_frequency(channel, band->band);
2786 notify_channel = ieee80211_get_channel(wiphy, freq);
2787
Arend van Spriel5b435de2011-10-05 13:19:03 +02002788 notify_capability = le16_to_cpu(bi->capability);
2789 notify_interval = le16_to_cpu(bi->beacon_period);
2790 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2791 notify_ielen = le32_to_cpu(bi->ie_length);
2792 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2793
Arend van Spriel16886732012-12-05 15:26:04 +01002794 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2795 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2796 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2797 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2798 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002799
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002800 bss = cfg80211_inform_bss(wiphy, notify_channel,
2801 CFG80211_BSS_FTYPE_UNKNOWN,
2802 (const u8 *)bi->BSSID,
2803 0, notify_capability,
2804 notify_interval, notify_ie,
2805 notify_ielen, notify_signal,
2806 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807
Franky Line78946e2011-11-10 20:30:34 +01002808 if (!bss)
2809 return -ENOMEM;
2810
Johannes Berg5b112d32013-02-01 01:49:58 +01002811 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002812
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002813 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002814}
2815
Roland Vossen6f09be02011-10-18 14:03:02 +02002816static struct brcmf_bss_info_le *
2817next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2818{
2819 if (bss == NULL)
2820 return list->bss_info_le;
2821 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2822 le32_to_cpu(bss->length));
2823}
2824
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002825static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002826{
2827 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002828 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002829 s32 err = 0;
2830 int i;
2831
Hante Meulemanef8596e2014-09-30 10:23:13 +02002832 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002833 if (bss_list->count != 0 &&
2834 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002835 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2836 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837 return -EOPNOTSUPP;
2838 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002839 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002840 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002841 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002842 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002843 if (err)
2844 break;
2845 }
2846 return err;
2847}
2848
Hante Meulemanb0a79082015-12-10 13:43:07 +01002849static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2850 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002852 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002853 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002854 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002855 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002856 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002857 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002858 u8 *buf = NULL;
2859 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861 u16 notify_capability;
2862 u16 notify_interval;
2863 u8 *notify_ie;
2864 size_t notify_ielen;
2865 s32 notify_signal;
2866
Arend van Sprield96b8012012-12-05 15:26:02 +01002867 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002868
2869 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2870 if (buf == NULL) {
2871 err = -ENOMEM;
2872 goto CleanUp;
2873 }
2874
2875 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2876
Arend van Sprielac24be62012-10-22 10:36:23 -07002877 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2878 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002879 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002880 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 goto CleanUp;
2882 }
2883
Roland Vossend34bf642011-10-18 14:03:01 +02002884 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885
Franky Lin83cf17a2013-04-11 13:28:50 +02002886 ch.chspec = le16_to_cpu(bi->chanspec);
2887 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002888
Franky Lin83cf17a2013-04-11 13:28:50 +02002889 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02002890 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02002892 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002893
Rafał Miłecki4712d882016-05-20 13:38:57 +02002894 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002895 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002896 notify_channel = ieee80211_get_channel(wiphy, freq);
2897
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898 notify_capability = le16_to_cpu(bi->capability);
2899 notify_interval = le16_to_cpu(bi->beacon_period);
2900 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2901 notify_ielen = le32_to_cpu(bi->ie_length);
2902 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2903
Rafał Miłecki4712d882016-05-20 13:38:57 +02002904 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002905 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2906 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2907 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002908
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002909 bss = cfg80211_inform_bss(wiphy, notify_channel,
2910 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2911 notify_capability, notify_interval,
2912 notify_ie, notify_ielen, notify_signal,
2913 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002914
Franky Line78946e2011-11-10 20:30:34 +01002915 if (!bss) {
2916 err = -ENOMEM;
2917 goto CleanUp;
2918 }
2919
Johannes Berg5b112d32013-02-01 01:49:58 +01002920 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002921
Arend van Spriel5b435de2011-10-05 13:19:03 +02002922CleanUp:
2923
2924 kfree(buf);
2925
Arend van Sprield96b8012012-12-05 15:26:02 +01002926 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002927
2928 return err;
2929}
2930
Hante Meuleman89286dc2013-02-08 15:53:46 +01002931static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2932 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002933{
Roland Vossend34bf642011-10-18 14:03:01 +02002934 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002935 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002936 u16 beacon_interval;
2937 u8 dtim_period;
2938 size_t ie_len;
2939 u8 *ie;
2940 s32 err = 0;
2941
Arend van Sprield96b8012012-12-05 15:26:02 +01002942 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002943 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002944 return err;
2945
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002946 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002947 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002948 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002949 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002950 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002951 goto update_bss_info_out;
2952 }
2953
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002954 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2955 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002956 if (err)
2957 goto update_bss_info_out;
2958
2959 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2960 ie_len = le32_to_cpu(bi->ie_length);
2961 beacon_interval = le16_to_cpu(bi->beacon_period);
2962
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002963 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002964 if (tim)
2965 dtim_period = tim->data[1];
2966 else {
2967 /*
2968 * active scan was done so we could not get dtim
2969 * information out of probe response.
2970 * so we speficially query dtim information to dongle.
2971 */
2972 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002973 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002974 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002975 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002976 goto update_bss_info_out;
2977 }
2978 dtim_period = (u8)var;
2979 }
2980
Arend van Spriel5b435de2011-10-05 13:19:03 +02002981update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002982 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002983 return err;
2984}
2985
Hante Meuleman18e2f612013-02-08 15:53:49 +01002986void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002987{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002988 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002989
Arend van Sprielc1179032012-10-22 13:55:33 -07002990 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002991 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002992 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002993 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002994 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002995 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2996 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002997}
2998
Hante Meulemane756af52012-09-11 21:18:52 +02002999static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
3000{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003001 struct brcmf_cfg80211_info *cfg =
3002 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02003003 escan_timeout_work);
3004
Hante Meulemanef8596e2014-09-30 10:23:13 +02003005 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02003006 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02003007}
3008
3009static void brcmf_escan_timeout(unsigned long data)
3010{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003011 struct brcmf_cfg80211_info *cfg =
3012 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02003013
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003014 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003015 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08003016 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02003017 }
3018}
3019
3020static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02003021brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
3022 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02003023 struct brcmf_bss_info_le *bss_info_le)
3024{
Franky Lin83cf17a2013-04-11 13:28:50 +02003025 struct brcmu_chan ch_bss, ch_bss_info_le;
3026
3027 ch_bss.chspec = le16_to_cpu(bss->chanspec);
3028 cfg->d11inf.decchspec(&ch_bss);
3029 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
3030 cfg->d11inf.decchspec(&ch_bss_info_le);
3031
Hante Meulemane756af52012-09-11 21:18:52 +02003032 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02003033 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02003034 bss_info_le->SSID_len == bss->SSID_len &&
3035 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003036 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
3037 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02003038 s16 bss_rssi = le16_to_cpu(bss->RSSI);
3039 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
3040
Hante Meulemane756af52012-09-11 21:18:52 +02003041 /* preserve max RSSI if the measurements are
3042 * both on-channel or both off-channel
3043 */
Arend van Spriel029591f2012-09-19 22:21:06 +02003044 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02003045 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003046 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
3047 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02003048 /* preserve the on-channel rssi measurement
3049 * if the new measurement is off channel
3050 */
3051 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01003052 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02003053 }
3054 return 1;
3055 }
3056 return 0;
3057}
3058
3059static s32
Arend van Spriel19937322012-11-05 16:22:32 -08003060brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02003061 const struct brcmf_event_msg *e, void *data)
3062{
Arend van Spriel19937322012-11-05 16:22:32 -08003063 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02003064 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02003065 struct brcmf_escan_result_le *escan_result_le;
3066 struct brcmf_bss_info_le *bss_info_le;
3067 struct brcmf_bss_info_le *bss = NULL;
3068 u32 bi_length;
3069 struct brcmf_scan_results *list;
3070 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003071 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02003072
Arend van Spriel5c36b992012-11-14 18:46:05 -08003073 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02003074
Arend van Spriela0f472a2013-04-05 10:57:49 +02003075 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01003076 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02003077 return -EPERM;
3078 }
3079
3080 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003081 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003082 escan_result_le = (struct brcmf_escan_result_le *) data;
3083 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003084 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003085 goto exit;
3086 }
Hante Meulemane756af52012-09-11 21:18:52 +02003087 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003088 brcmf_err("Invalid bss_count %d: ignoring\n",
3089 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003090 goto exit;
3091 }
3092 bss_info_le = &escan_result_le->bss_info_le;
3093
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003094 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3095 goto exit;
3096
3097 if (!cfg->scan_request) {
3098 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3099 goto exit;
3100 }
3101
Hante Meulemane756af52012-09-11 21:18:52 +02003102 bi_length = le32_to_cpu(bss_info_le->length);
3103 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3104 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003105 brcmf_err("Invalid bss_info length %d: ignoring\n",
3106 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003107 goto exit;
3108 }
3109
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003110 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003111 BIT(NL80211_IFTYPE_ADHOC))) {
3112 if (le16_to_cpu(bss_info_le->capability) &
3113 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003114 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003115 goto exit;
3116 }
3117 }
3118
3119 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003120 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003121 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003122 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003123 goto exit;
3124 }
3125
3126 for (i = 0; i < list->count; i++) {
3127 bss = bss ? (struct brcmf_bss_info_le *)
3128 ((unsigned char *)bss +
3129 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003130 if (brcmf_compare_update_same_bss(cfg, bss,
3131 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003132 goto exit;
3133 }
Hante Meulemand5367332016-02-17 11:26:51 +01003134 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3135 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003136 list->version = le32_to_cpu(bss_info_le->version);
3137 list->buflen += bi_length;
3138 list->count++;
3139 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003140 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003141 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3142 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003143 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003144 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003145 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003146 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003147 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003148 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3149 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003150 }
3151exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003152 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003153}
3154
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003155static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003156{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003157 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3158 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003159 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3160 /* Init scan_timeout timer */
3161 init_timer(&cfg->escan_timeout);
3162 cfg->escan_timeout.data = (unsigned long) cfg;
3163 cfg->escan_timeout.function = brcmf_escan_timeout;
3164 INIT_WORK(&cfg->escan_timeout_work,
3165 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003166}
3167
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003168/* PFN result doesn't have all the info which are required by the supplicant
3169 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3170 * via wl_inform_single_bss in the required format. Escan does require the
3171 * scan request in the form of cfg80211_scan_request. For timebeing, create
3172 * cfg80211_scan_request one out of the received PNO event.
3173 */
3174static s32
3175brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3176 const struct brcmf_event_msg *e, void *data)
3177{
3178 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3179 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3180 struct cfg80211_scan_request *request = NULL;
3181 struct cfg80211_ssid *ssid = NULL;
3182 struct ieee80211_channel *channel = NULL;
3183 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3184 int err = 0;
3185 int channel_req = 0;
3186 int band = 0;
3187 struct brcmf_pno_scanresults_le *pfn_result;
3188 u32 result_count;
3189 u32 status;
3190
3191 brcmf_dbg(SCAN, "Enter\n");
3192
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003193 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3194 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3195 return 0;
3196 }
3197
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003198 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3199 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3200 return 0;
3201 }
3202
3203 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3204 result_count = le32_to_cpu(pfn_result->count);
3205 status = le32_to_cpu(pfn_result->status);
3206
3207 /* PFN event is limited to fit 512 bytes so we may get
3208 * multiple NET_FOUND events. For now place a warning here.
3209 */
3210 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3211 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3212 if (result_count > 0) {
3213 int i;
3214
3215 request = kzalloc(sizeof(*request), GFP_KERNEL);
3216 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3217 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3218 if (!request || !ssid || !channel) {
3219 err = -ENOMEM;
3220 goto out_err;
3221 }
3222
3223 request->wiphy = wiphy;
3224 data += sizeof(struct brcmf_pno_scanresults_le);
3225 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3226
3227 for (i = 0; i < result_count; i++) {
3228 netinfo = &netinfo_start[i];
3229 if (!netinfo) {
3230 brcmf_err("Invalid netinfo ptr. index: %d\n",
3231 i);
3232 err = -EINVAL;
3233 goto out_err;
3234 }
3235
3236 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3237 netinfo->SSID, netinfo->channel);
3238 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3239 ssid[i].ssid_len = netinfo->SSID_len;
3240 request->n_ssids++;
3241
3242 channel_req = netinfo->channel;
3243 if (channel_req <= CH_MAX_2G_CHANNEL)
3244 band = NL80211_BAND_2GHZ;
3245 else
3246 band = NL80211_BAND_5GHZ;
3247 channel[i].center_freq =
3248 ieee80211_channel_to_frequency(channel_req,
3249 band);
3250 channel[i].band = band;
3251 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3252 request->channels[i] = &channel[i];
3253 request->n_channels++;
3254 }
3255
3256 /* assign parsed ssid array */
3257 if (request->n_ssids)
3258 request->ssids = &ssid[0];
3259
3260 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3261 /* Abort any on-going scan */
3262 brcmf_abort_scanning(cfg);
3263 }
3264
3265 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3266 cfg->escan_info.run = brcmf_run_escan;
3267 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3268 if (err) {
3269 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3270 goto out_err;
3271 }
3272 cfg->sched_escan = true;
3273 cfg->scan_request = request;
3274 } else {
3275 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3276 goto out_err;
3277 }
3278
3279 kfree(ssid);
3280 kfree(channel);
3281 kfree(request);
3282 return 0;
3283
3284out_err:
3285 kfree(ssid);
3286 kfree(channel);
3287 kfree(request);
3288 cfg80211_sched_scan_stopped(wiphy);
3289 return err;
3290}
3291
3292static int brcmf_dev_pno_clean(struct net_device *ndev)
3293{
3294 int ret;
3295
3296 /* Disable pfn */
3297 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3298 if (ret == 0) {
3299 /* clear pfn */
3300 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3301 NULL, 0);
3302 }
3303 if (ret < 0)
3304 brcmf_err("failed code %d\n", ret);
3305
3306 return ret;
3307}
3308
3309static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3310 struct cfg80211_sched_scan_request *request)
3311{
3312 struct brcmf_pno_param_le pfn_param;
3313 struct brcmf_pno_macaddr_le pfn_mac;
3314 s32 err;
3315 u8 *mac_mask;
3316 int i;
3317
3318 memset(&pfn_param, 0, sizeof(pfn_param));
3319 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3320
3321 /* set extra pno params */
3322 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3323 pfn_param.repeat = BRCMF_PNO_REPEAT;
3324 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3325
3326 /* set up pno scan fr */
3327 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3328
3329 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3330 sizeof(pfn_param));
3331 if (err) {
3332 brcmf_err("pfn_set failed, err=%d\n", err);
3333 return err;
3334 }
3335
3336 /* Find out if mac randomization should be turned on */
3337 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3338 return 0;
3339
3340 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3341 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3342
3343 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3344 mac_mask = request->mac_addr_mask;
3345 for (i = 0; i < ETH_ALEN; i++) {
3346 pfn_mac.mac[i] &= mac_mask[i];
3347 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3348 }
3349 /* Clear multi bit */
3350 pfn_mac.mac[0] &= 0xFE;
3351 /* Set locally administered */
3352 pfn_mac.mac[0] |= 0x02;
3353
3354 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3355 sizeof(pfn_mac));
3356 if (err)
3357 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3358
3359 return err;
3360}
3361
3362static int
3363brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3364 struct net_device *ndev,
3365 struct cfg80211_sched_scan_request *request)
3366{
3367 struct brcmf_if *ifp = netdev_priv(ndev);
3368 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3369 struct brcmf_pno_net_param_le pfn;
3370 int i;
3371 int ret = 0;
3372
3373 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3374 request->n_match_sets, request->n_ssids);
3375 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3376 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3377 return -EAGAIN;
3378 }
3379 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3380 brcmf_err("Scanning suppressed: status (%lu)\n",
3381 cfg->scan_status);
3382 return -EAGAIN;
3383 }
3384
3385 if (!request->n_ssids || !request->n_match_sets) {
3386 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3387 request->n_ssids);
3388 return -EINVAL;
3389 }
3390
3391 if (request->n_ssids > 0) {
3392 for (i = 0; i < request->n_ssids; i++) {
3393 /* Active scan req for ssids */
3394 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3395 request->ssids[i].ssid);
3396
3397 /* match_set ssids is a supert set of n_ssid list,
3398 * so we need not add these set separately.
3399 */
3400 }
3401 }
3402
3403 if (request->n_match_sets > 0) {
3404 /* clean up everything */
3405 ret = brcmf_dev_pno_clean(ndev);
3406 if (ret < 0) {
3407 brcmf_err("failed error=%d\n", ret);
3408 return ret;
3409 }
3410
3411 /* configure pno */
3412 if (brcmf_dev_pno_config(ifp, request))
3413 return -EINVAL;
3414
3415 /* configure each match set */
3416 for (i = 0; i < request->n_match_sets; i++) {
3417 struct cfg80211_ssid *ssid;
3418 u32 ssid_len;
3419
3420 ssid = &request->match_sets[i].ssid;
3421 ssid_len = ssid->ssid_len;
3422
3423 if (!ssid_len) {
3424 brcmf_err("skip broadcast ssid\n");
3425 continue;
3426 }
3427 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3428 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3429 pfn.wsec = cpu_to_le32(0);
3430 pfn.infra = cpu_to_le32(1);
3431 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3432 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3433 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3434 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3435 sizeof(pfn));
3436 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3437 ret == 0 ? "set" : "failed", ssid->ssid);
3438 }
3439 /* Enable the PNO */
3440 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3441 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3442 return -EINVAL;
3443 }
3444 } else {
3445 return -EINVAL;
3446 }
3447
3448 return 0;
3449}
3450
3451static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3452 struct net_device *ndev)
3453{
3454 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3455
3456 brcmf_dbg(SCAN, "enter\n");
3457 brcmf_dev_pno_clean(ndev);
3458 if (cfg->sched_escan)
3459 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3460 return 0;
3461}
3462
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003463static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003464{
3465 if (ms < 1000 / HZ) {
3466 cond_resched();
3467 mdelay(ms);
3468 } else {
3469 msleep(ms);
3470 }
3471}
3472
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003473static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3474 u8 *pattern, u32 patternsize, u8 *mask,
3475 u32 packet_offset)
3476{
3477 struct brcmf_fil_wowl_pattern_le *filter;
3478 u32 masksize;
3479 u32 patternoffset;
3480 u8 *buf;
3481 u32 bufsize;
3482 s32 ret;
3483
3484 masksize = (patternsize + 7) / 8;
3485 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3486
3487 bufsize = sizeof(*filter) + patternsize + masksize;
3488 buf = kzalloc(bufsize, GFP_KERNEL);
3489 if (!buf)
3490 return -ENOMEM;
3491 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3492
3493 memcpy(filter->cmd, cmd, 4);
3494 filter->masksize = cpu_to_le32(masksize);
3495 filter->offset = cpu_to_le32(packet_offset);
3496 filter->patternoffset = cpu_to_le32(patternoffset);
3497 filter->patternsize = cpu_to_le32(patternsize);
3498 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3499
3500 if ((mask) && (masksize))
3501 memcpy(buf + sizeof(*filter), mask, masksize);
3502 if ((pattern) && (patternsize))
3503 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3504
3505 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3506
3507 kfree(buf);
3508 return ret;
3509}
3510
Hante Meuleman3021ad92016-01-05 11:05:45 +01003511static s32
3512brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3513 void *data)
3514{
3515 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3516 struct brcmf_pno_scanresults_le *pfn_result;
3517 struct brcmf_pno_net_info_le *netinfo;
3518
3519 brcmf_dbg(SCAN, "Enter\n");
3520
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003521 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3522 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3523 return 0;
3524 }
3525
Hante Meuleman3021ad92016-01-05 11:05:45 +01003526 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3527
3528 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3529 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3530 return 0;
3531 }
3532
3533 if (le32_to_cpu(pfn_result->count) < 1) {
3534 brcmf_err("Invalid result count, expected 1 (%d)\n",
3535 le32_to_cpu(pfn_result->count));
3536 return -EINVAL;
3537 }
3538
3539 data += sizeof(struct brcmf_pno_scanresults_le);
3540 netinfo = (struct brcmf_pno_net_info_le *)data;
3541 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3542 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3543 cfg->wowl.nd->n_channels = 1;
3544 cfg->wowl.nd->channels[0] =
3545 ieee80211_channel_to_frequency(netinfo->channel,
3546 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3547 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3548 cfg->wowl.nd_info->n_matches = 1;
3549 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3550
3551 /* Inform (the resume task) that the net detect information was recvd */
3552 cfg->wowl.nd_data_completed = true;
3553 wake_up(&cfg->wowl.nd_data_wait);
3554
3555 return 0;
3556}
3557
Hante Meulemanaeb64222015-10-29 20:33:19 +01003558#ifdef CONFIG_PM
3559
3560static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3561{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003562 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003563 struct brcmf_wowl_wakeind_le wake_ind_le;
3564 struct cfg80211_wowlan_wakeup wakeup_data;
3565 struct cfg80211_wowlan_wakeup *wakeup;
3566 u32 wakeind;
3567 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003568 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003569
3570 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3571 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003572 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003573 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3574 return;
3575 }
3576
3577 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3578 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003579 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3580 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003581 wakeup = &wakeup_data;
3582 memset(&wakeup_data, 0, sizeof(wakeup_data));
3583 wakeup_data.pattern_idx = -1;
3584
3585 if (wakeind & BRCMF_WOWL_MAGIC) {
3586 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3587 wakeup_data.magic_pkt = true;
3588 }
3589 if (wakeind & BRCMF_WOWL_DIS) {
3590 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3591 wakeup_data.disconnect = true;
3592 }
3593 if (wakeind & BRCMF_WOWL_BCN) {
3594 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3595 wakeup_data.disconnect = true;
3596 }
3597 if (wakeind & BRCMF_WOWL_RETR) {
3598 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3599 wakeup_data.disconnect = true;
3600 }
3601 if (wakeind & BRCMF_WOWL_NET) {
3602 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3603 /* For now always map to pattern 0, no API to get
3604 * correct information available at the moment.
3605 */
3606 wakeup_data.pattern_idx = 0;
3607 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003608 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3609 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3610 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3611 cfg->wowl.nd_data_completed,
3612 BRCMF_ND_INFO_TIMEOUT);
3613 if (!timeout)
3614 brcmf_err("No result for wowl net detect\n");
3615 else
3616 wakeup_data.net_detect = cfg->wowl.nd_info;
3617 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003618 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3619 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3620 wakeup_data.gtk_rekey_failure = true;
3621 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003622 } else {
3623 wakeup = NULL;
3624 }
3625 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3626}
3627
3628#else
3629
3630static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3631{
3632}
3633
3634#endif /* CONFIG_PM */
3635
Arend van Spriel5b435de2011-10-05 13:19:03 +02003636static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3637{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003638 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3639 struct net_device *ndev = cfg_to_ndev(cfg);
3640 struct brcmf_if *ifp = netdev_priv(ndev);
3641
Arend van Sprield96b8012012-12-05 15:26:02 +01003642 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003643
Hante Meuleman3021ad92016-01-05 11:05:45 +01003644 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003645 brcmf_report_wowl_wakeind(wiphy, ifp);
3646 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3647 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003648 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3649 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003650 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003651 cfg->wowl.pre_pmmode);
3652 cfg->wowl.active = false;
3653 if (cfg->wowl.nd_enabled) {
3654 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3655 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3656 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3657 brcmf_notify_sched_scan_results);
3658 cfg->wowl.nd_enabled = false;
3659 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003660 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003661 return 0;
3662}
3663
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003664static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3665 struct brcmf_if *ifp,
3666 struct cfg80211_wowlan *wowl)
3667{
3668 u32 wowl_config;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003669 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003670
3671 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3672
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003673 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3674 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003675 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003676 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3677
3678 wowl_config = 0;
3679 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003680 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003681 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003682 wowl_config |= BRCMF_WOWL_MAGIC;
3683 if ((wowl->patterns) && (wowl->n_patterns)) {
3684 wowl_config |= BRCMF_WOWL_NET;
3685 for (i = 0; i < wowl->n_patterns; i++) {
3686 brcmf_config_wowl_pattern(ifp, "add",
3687 (u8 *)wowl->patterns[i].pattern,
3688 wowl->patterns[i].pattern_len,
3689 (u8 *)wowl->patterns[i].mask,
3690 wowl->patterns[i].pkt_offset);
3691 }
3692 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003693 if (wowl->nd_config) {
3694 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3695 wowl->nd_config);
3696 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3697
3698 cfg->wowl.nd_data_completed = false;
3699 cfg->wowl.nd_enabled = true;
3700 /* Now reroute the event for PFN to the wowl function. */
3701 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3702 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3703 brcmf_wowl_nd_results);
3704 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003705 if (wowl->gtk_rekey_failure)
3706 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003707 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3708 wowl_config |= BRCMF_WOWL_UNASSOC;
3709
Hante Meuleman28b285a2016-04-11 11:35:22 +02003710 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear",
3711 sizeof(struct brcmf_wowl_wakeind_le));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003712 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3713 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3714 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003715 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003716}
3717
Arend van Spriel5b435de2011-10-05 13:19:03 +02003718static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003719 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003720{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003721 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3722 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003723 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003724 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003725
Arend van Sprield96b8012012-12-05 15:26:02 +01003726 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003727
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003728 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003729 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003730 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003731 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003732 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003733
Hante Meuleman3021ad92016-01-05 11:05:45 +01003734 /* Stop scheduled scan */
3735 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3736 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3737
Arend van Spriel7d641072012-10-22 13:55:39 -07003738 /* end any scanning */
3739 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003740 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003741
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003742 if (wowl == NULL) {
3743 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3744 list_for_each_entry(vif, &cfg->vif_list, list) {
3745 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3746 continue;
3747 /* While going to suspend if associated with AP
3748 * disassociate from AP to save power while system is
3749 * in suspended state
3750 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003751 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003752 /* Make sure WPA_Supplicant receives all the event
3753 * generated due to DISASSOC call to the fw to keep
3754 * the state fw and WPA_Supplicant state consistent
3755 */
3756 brcmf_delay(500);
3757 }
3758 /* Configure MPC */
3759 brcmf_set_mpc(ifp, 1);
3760
3761 } else {
3762 /* Configure WOWL paramaters */
3763 brcmf_configure_wowl(cfg, ifp, wowl);
3764 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003765
Arend van Spriel7d641072012-10-22 13:55:39 -07003766exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003767 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003768 /* clear any scanning activity */
3769 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003770 return 0;
3771}
3772
3773static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003774brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003775{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003776 struct brcmf_pmk_list_le *pmk_list;
3777 int i;
3778 u32 npmk;
3779 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780
Hante Meuleman6c404f32015-12-10 13:43:03 +01003781 pmk_list = &cfg->pmk_list;
3782 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003783
Hante Meuleman6c404f32015-12-10 13:43:03 +01003784 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3785 for (i = 0; i < npmk; i++)
3786 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003787
Hante Meuleman6c404f32015-12-10 13:43:03 +01003788 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3789 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003790
3791 return err;
3792}
3793
3794static s32
3795brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3796 struct cfg80211_pmksa *pmksa)
3797{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003798 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003799 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003800 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3801 s32 err;
3802 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003803
Arend van Sprield96b8012012-12-05 15:26:02 +01003804 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003805 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003806 return -EIO;
3807
Hante Meuleman6c404f32015-12-10 13:43:03 +01003808 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3809 for (i = 0; i < npmk; i++)
3810 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003811 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003812 if (i < BRCMF_MAXPMKID) {
3813 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3814 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3815 if (i == npmk) {
3816 npmk++;
3817 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003818 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003819 } else {
3820 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3821 return -EINVAL;
3822 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003823
Hante Meuleman6c404f32015-12-10 13:43:03 +01003824 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3825 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3826 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3827 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3828 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829
Hante Meuleman6c404f32015-12-10 13:43:03 +01003830 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003831
Arend van Sprield96b8012012-12-05 15:26:02 +01003832 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003833 return err;
3834}
3835
3836static s32
3837brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003838 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003839{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003840 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003841 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003842 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3843 s32 err;
3844 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003845
Arend van Sprield96b8012012-12-05 15:26:02 +01003846 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003847 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003848 return -EIO;
3849
Hante Meuleman6c404f32015-12-10 13:43:03 +01003850 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003851
Hante Meuleman6c404f32015-12-10 13:43:03 +01003852 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3853 for (i = 0; i < npmk; i++)
3854 if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003855 break;
3856
Hante Meuleman6c404f32015-12-10 13:43:03 +01003857 if ((npmk > 0) && (i < npmk)) {
3858 for (; i < (npmk - 1); i++) {
3859 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3860 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003861 WLAN_PMKID_LEN);
3862 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003863 memset(&pmk[i], 0, sizeof(*pmk));
3864 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3865 } else {
3866 brcmf_err("Cache entry not found\n");
3867 return -EINVAL;
3868 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003869
Hante Meuleman6c404f32015-12-10 13:43:03 +01003870 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003871
Arend van Sprield96b8012012-12-05 15:26:02 +01003872 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003873 return err;
3874
3875}
3876
3877static s32
3878brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3879{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003880 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003881 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003882 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003883
Arend van Sprield96b8012012-12-05 15:26:02 +01003884 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003885 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003886 return -EIO;
3887
Hante Meuleman6c404f32015-12-10 13:43:03 +01003888 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3889 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003890
Arend van Sprield96b8012012-12-05 15:26:02 +01003891 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003892 return err;
3893
3894}
3895
Hante Meuleman1f170112013-02-06 18:40:38 +01003896static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003897{
3898 s32 err;
3899
3900 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003901 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003902 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003903 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003904 return err;
3905 }
3906 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003907 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003908 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003909 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003910 return err;
3911 }
3912 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003913 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003914 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003915 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003916 return err;
3917 }
3918
3919 return 0;
3920}
3921
3922static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3923{
3924 if (is_rsn_ie)
3925 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3926
3927 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3928}
3929
3930static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003931brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003932 const struct brcmf_vs_tlv *wpa_ie,
3933 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003934{
3935 u32 auth = 0; /* d11 open authentication */
3936 u16 count;
3937 s32 err = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003938 s32 len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003939 u32 i;
3940 u32 wsec;
3941 u32 pval = 0;
3942 u32 gval = 0;
3943 u32 wpa_auth = 0;
3944 u32 offset;
3945 u8 *data;
3946 u16 rsn_cap;
3947 u32 wme_bss_disable;
Hante Meuleman240d61a2016-02-17 11:27:10 +01003948 u32 mfp;
Hante Meuleman1a873342012-09-27 14:17:54 +02003949
Arend van Sprield96b8012012-12-05 15:26:02 +01003950 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003951 if (wpa_ie == NULL)
3952 goto exit;
3953
3954 len = wpa_ie->len + TLV_HDR_LEN;
3955 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003956 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003957 if (!is_rsn_ie)
3958 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003959 else
3960 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003961
3962 /* check for multicast cipher suite */
3963 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3964 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003965 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003966 goto exit;
3967 }
3968
3969 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3970 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003971 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003972 goto exit;
3973 }
3974 offset += TLV_OUI_LEN;
3975
3976 /* pick up multicast cipher */
3977 switch (data[offset]) {
3978 case WPA_CIPHER_NONE:
3979 gval = 0;
3980 break;
3981 case WPA_CIPHER_WEP_40:
3982 case WPA_CIPHER_WEP_104:
3983 gval = WEP_ENABLED;
3984 break;
3985 case WPA_CIPHER_TKIP:
3986 gval = TKIP_ENABLED;
3987 break;
3988 case WPA_CIPHER_AES_CCM:
3989 gval = AES_ENABLED;
3990 break;
3991 default:
3992 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003993 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003994 goto exit;
3995 }
3996
3997 offset++;
3998 /* walk thru unicast cipher list and pick up what we recognize */
3999 count = data[offset] + (data[offset + 1] << 8);
4000 offset += WPA_IE_SUITE_COUNT_LEN;
4001 /* Check for unicast suite(s) */
4002 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4003 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004004 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004005 goto exit;
4006 }
4007 for (i = 0; i < count; i++) {
4008 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4009 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004010 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004011 goto exit;
4012 }
4013 offset += TLV_OUI_LEN;
4014 switch (data[offset]) {
4015 case WPA_CIPHER_NONE:
4016 break;
4017 case WPA_CIPHER_WEP_40:
4018 case WPA_CIPHER_WEP_104:
4019 pval |= WEP_ENABLED;
4020 break;
4021 case WPA_CIPHER_TKIP:
4022 pval |= TKIP_ENABLED;
4023 break;
4024 case WPA_CIPHER_AES_CCM:
4025 pval |= AES_ENABLED;
4026 break;
4027 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004028 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004029 }
4030 offset++;
4031 }
4032 /* walk thru auth management suite list and pick up what we recognize */
4033 count = data[offset] + (data[offset + 1] << 8);
4034 offset += WPA_IE_SUITE_COUNT_LEN;
4035 /* Check for auth key management suite(s) */
4036 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
4037 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004038 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004039 goto exit;
4040 }
4041 for (i = 0; i < count; i++) {
4042 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
4043 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004044 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004045 goto exit;
4046 }
4047 offset += TLV_OUI_LEN;
4048 switch (data[offset]) {
4049 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01004050 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004051 wpa_auth |= WPA_AUTH_NONE;
4052 break;
4053 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01004054 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004055 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
4056 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
4057 break;
4058 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01004059 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004060 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
4061 (wpa_auth |= WPA_AUTH_PSK);
4062 break;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004063 case RSN_AKM_SHA256_PSK:
4064 brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
4065 wpa_auth |= WPA2_AUTH_PSK_SHA256;
4066 break;
4067 case RSN_AKM_SHA256_1X:
4068 brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
4069 wpa_auth |= WPA2_AUTH_1X_SHA256;
4070 break;
Hante Meuleman1a873342012-09-27 14:17:54 +02004071 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01004072 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004073 }
4074 offset++;
4075 }
4076
Hante Meuleman240d61a2016-02-17 11:27:10 +01004077 mfp = BRCMF_MFP_NONE;
Hante Meuleman1a873342012-09-27 14:17:54 +02004078 if (is_rsn_ie) {
4079 wme_bss_disable = 1;
4080 if ((offset + RSN_CAP_LEN) <= len) {
4081 rsn_cap = data[offset] + (data[offset + 1] << 8);
4082 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
4083 wme_bss_disable = 0;
Hante Meuleman240d61a2016-02-17 11:27:10 +01004084 if (rsn_cap & RSN_CAP_MFPR_MASK) {
4085 brcmf_dbg(TRACE, "MFP Required\n");
4086 mfp = BRCMF_MFP_REQUIRED;
4087 /* Firmware only supports mfp required in
4088 * combination with WPA2_AUTH_PSK_SHA256 or
4089 * WPA2_AUTH_1X_SHA256.
4090 */
4091 if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
4092 WPA2_AUTH_1X_SHA256))) {
4093 err = -EINVAL;
4094 goto exit;
4095 }
4096 /* Firmware has requirement that WPA2_AUTH_PSK/
4097 * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
4098 * is to be included in the rsn ie.
4099 */
4100 if (wpa_auth & WPA2_AUTH_PSK_SHA256)
4101 wpa_auth |= WPA2_AUTH_PSK;
4102 else if (wpa_auth & WPA2_AUTH_1X_SHA256)
4103 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
4104 } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
4105 brcmf_dbg(TRACE, "MFP Capable\n");
4106 mfp = BRCMF_MFP_CAPABLE;
4107 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004108 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004109 offset += RSN_CAP_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02004110 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07004111 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004112 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02004113 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004114 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004115 goto exit;
4116 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004117
4118 /* Skip PMKID cnt as it is know to be 0 for AP. */
4119 offset += RSN_PMKID_COUNT_LEN;
4120
4121 /* See if there is BIP wpa suite left for MFP */
4122 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
4123 ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
4124 err = brcmf_fil_bsscfg_data_set(ifp, "bip",
4125 &data[offset],
4126 WPA_IE_MIN_OUI_LEN);
4127 if (err < 0) {
4128 brcmf_err("bip error %d\n", err);
4129 goto exit;
4130 }
4131 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004132 }
4133 /* FOR WPS , set SES_OW_ENABLED */
4134 wsec = (pval | gval | SES_OW_ENABLED);
4135
4136 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004137 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004138 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004139 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004140 goto exit;
4141 }
4142 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004143 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004144 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004145 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004146 goto exit;
4147 }
Hante Meuleman240d61a2016-02-17 11:27:10 +01004148 /* Configure MFP, this needs to go after wsec otherwise the wsec command
4149 * will overwrite the values set by MFP
4150 */
4151 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
4152 err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
4153 if (err < 0) {
4154 brcmf_err("mfp error %d\n", err);
4155 goto exit;
4156 }
4157 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004158 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004159 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004160 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004161 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004162 goto exit;
4163 }
4164
4165exit:
4166 return err;
4167}
4168
4169static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004170brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004171 struct parsed_vndr_ies *vndr_ies)
4172{
Hante Meuleman1a873342012-09-27 14:17:54 +02004173 struct brcmf_vs_tlv *vndrie;
4174 struct brcmf_tlv *ie;
4175 struct parsed_vndr_ie_info *parsed_info;
4176 s32 remaining_len;
4177
4178 remaining_len = (s32)vndr_ie_len;
4179 memset(vndr_ies, 0, sizeof(*vndr_ies));
4180
4181 ie = (struct brcmf_tlv *)vndr_ie_buf;
4182 while (ie) {
4183 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4184 goto next;
4185 vndrie = (struct brcmf_vs_tlv *)ie;
4186 /* len should be bigger than OUI length + one */
4187 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004188 brcmf_err("invalid vndr ie. length is too small %d\n",
4189 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004190 goto next;
4191 }
4192 /* if wpa or wme ie, do not add ie */
4193 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4194 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4195 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004196 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004197 goto next;
4198 }
4199
4200 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4201
4202 /* save vndr ie information */
4203 parsed_info->ie_ptr = (char *)vndrie;
4204 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4205 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4206
4207 vndr_ies->count++;
4208
Arend van Sprield96b8012012-12-05 15:26:02 +01004209 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4210 parsed_info->vndrie.oui[0],
4211 parsed_info->vndrie.oui[1],
4212 parsed_info->vndrie.oui[2],
4213 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004214
Arend van Spriel9f440b72013-02-08 15:53:36 +01004215 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004216 break;
4217next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004218 remaining_len -= (ie->len + TLV_HDR_LEN);
4219 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004220 ie = NULL;
4221 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004222 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4223 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004224 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004225 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004226}
4227
4228static u32
4229brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4230{
4231
Hante Meuleman1a873342012-09-27 14:17:54 +02004232 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4233 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4234
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304235 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004236
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304237 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004238
4239 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4240
4241 return ie_len + VNDR_IE_HDR_SIZE;
4242}
4243
Arend van Spriel1332e262012-11-05 16:22:18 -08004244s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4245 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004246{
Arend van Spriel1332e262012-11-05 16:22:18 -08004247 struct brcmf_if *ifp;
4248 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004249 s32 err = 0;
4250 u8 *iovar_ie_buf;
4251 u8 *curr_ie_buf;
4252 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004253 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004254 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004255 u32 del_add_ie_buf_len = 0;
4256 u32 total_ie_buf_len = 0;
4257 u32 parsed_ie_buf_len = 0;
4258 struct parsed_vndr_ies old_vndr_ies;
4259 struct parsed_vndr_ies new_vndr_ies;
4260 struct parsed_vndr_ie_info *vndrie_info;
4261 s32 i;
4262 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004263 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004264
Arend van Spriel1332e262012-11-05 16:22:18 -08004265 if (!vif)
4266 return -ENODEV;
4267 ifp = vif->ifp;
4268 saved_ie = &vif->saved_ie;
4269
Hante Meuleman37a869e2015-10-29 20:33:17 +01004270 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4271 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004272 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4273 if (!iovar_ie_buf)
4274 return -ENOMEM;
4275 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004276 switch (pktflag) {
4277 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4278 mgmt_ie_buf = saved_ie->probe_req_ie;
4279 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4280 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4281 break;
4282 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4283 mgmt_ie_buf = saved_ie->probe_res_ie;
4284 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4285 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4286 break;
4287 case BRCMF_VNDR_IE_BEACON_FLAG:
4288 mgmt_ie_buf = saved_ie->beacon_ie;
4289 mgmt_ie_len = &saved_ie->beacon_ie_len;
4290 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4291 break;
4292 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4293 mgmt_ie_buf = saved_ie->assoc_req_ie;
4294 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4295 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4296 break;
4297 default:
4298 err = -EPERM;
4299 brcmf_err("not suitable type\n");
4300 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004301 }
4302
4303 if (vndr_ie_len > mgmt_ie_buf_len) {
4304 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004305 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004306 goto exit;
4307 }
4308
4309 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4310 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4311 ptr = curr_ie_buf;
4312 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4313 for (i = 0; i < new_vndr_ies.count; i++) {
4314 vndrie_info = &new_vndr_ies.ie_info[i];
4315 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4316 vndrie_info->ie_len);
4317 parsed_ie_buf_len += vndrie_info->ie_len;
4318 }
4319 }
4320
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004321 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004322 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4323 (memcmp(mgmt_ie_buf, curr_ie_buf,
4324 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004325 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004326 goto exit;
4327 }
4328
4329 /* parse old vndr_ie */
4330 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4331
4332 /* make a command to delete old ie */
4333 for (i = 0; i < old_vndr_ies.count; i++) {
4334 vndrie_info = &old_vndr_ies.ie_info[i];
4335
Arend van Sprield96b8012012-12-05 15:26:02 +01004336 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4337 vndrie_info->vndrie.id,
4338 vndrie_info->vndrie.len,
4339 vndrie_info->vndrie.oui[0],
4340 vndrie_info->vndrie.oui[1],
4341 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004342
4343 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4344 vndrie_info->ie_ptr,
4345 vndrie_info->ie_len,
4346 "del");
4347 curr_ie_buf += del_add_ie_buf_len;
4348 total_ie_buf_len += del_add_ie_buf_len;
4349 }
4350 }
4351
4352 *mgmt_ie_len = 0;
4353 /* Add if there is any extra IE */
4354 if (mgmt_ie_buf && parsed_ie_buf_len) {
4355 ptr = mgmt_ie_buf;
4356
4357 remained_buf_len = mgmt_ie_buf_len;
4358
4359 /* make a command to add new ie */
4360 for (i = 0; i < new_vndr_ies.count; i++) {
4361 vndrie_info = &new_vndr_ies.ie_info[i];
4362
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004363 /* verify remained buf size before copy data */
4364 if (remained_buf_len < (vndrie_info->vndrie.len +
4365 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004366 brcmf_err("no space in mgmt_ie_buf: len left %d",
4367 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004368 break;
4369 }
4370 remained_buf_len -= (vndrie_info->ie_len +
4371 VNDR_IE_VSIE_OFFSET);
4372
Arend van Sprield96b8012012-12-05 15:26:02 +01004373 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4374 vndrie_info->vndrie.id,
4375 vndrie_info->vndrie.len,
4376 vndrie_info->vndrie.oui[0],
4377 vndrie_info->vndrie.oui[1],
4378 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004379
4380 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4381 vndrie_info->ie_ptr,
4382 vndrie_info->ie_len,
4383 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004384
4385 /* save the parsed IE in wl struct */
4386 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4387 vndrie_info->ie_len);
4388 *mgmt_ie_len += vndrie_info->ie_len;
4389
4390 curr_ie_buf += del_add_ie_buf_len;
4391 total_ie_buf_len += del_add_ie_buf_len;
4392 }
4393 }
4394 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004395 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004396 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004397 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004398 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004399 }
4400
4401exit:
4402 kfree(iovar_ie_buf);
4403 return err;
4404}
4405
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004406s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4407{
4408 s32 pktflags[] = {
4409 BRCMF_VNDR_IE_PRBREQ_FLAG,
4410 BRCMF_VNDR_IE_PRBRSP_FLAG,
4411 BRCMF_VNDR_IE_BEACON_FLAG
4412 };
4413 int i;
4414
4415 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4416 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4417
4418 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4419 return 0;
4420}
4421
Hante Meuleman1a873342012-09-27 14:17:54 +02004422static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004423brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4424 struct cfg80211_beacon_data *beacon)
4425{
4426 s32 err;
4427
4428 /* Set Beacon IEs to FW */
4429 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4430 beacon->tail, beacon->tail_len);
4431 if (err) {
4432 brcmf_err("Set Beacon IE Failed\n");
4433 return err;
4434 }
4435 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4436
4437 /* Set Probe Response IEs to FW */
4438 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4439 beacon->proberesp_ies,
4440 beacon->proberesp_ies_len);
4441 if (err)
4442 brcmf_err("Set Probe Resp IE Failed\n");
4443 else
4444 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4445
4446 return err;
4447}
4448
4449static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004450brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4451 struct cfg80211_ap_settings *settings)
4452{
4453 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004454 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004455 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004456 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004457 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004458 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004459 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004460 const struct brcmf_tlv *rsn_ie;
4461 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004462 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004463 enum nl80211_iftype dev_role;
4464 struct brcmf_fil_bss_enable_le bss_enable;
Rafał Miłecki8707e082016-05-27 21:07:19 +02004465 u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
Hante Meulemana44aa402014-12-03 21:05:33 +01004466 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004467 int is_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004468
Arend van Spriel06c01582014-05-12 10:47:37 +02004469 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4470 settings->chandef.chan->hw_value,
4471 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004472 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004473 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4474 settings->ssid, settings->ssid_len, settings->auth_type,
4475 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004476 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004477 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004478
Arend van Spriel98027762014-12-21 12:43:53 +01004479 /* store current 11d setting */
4480 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4481 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4482 settings->beacon.tail_len,
4483 WLAN_EID_COUNTRY);
4484 is_11d = country_ie ? 1 : 0;
4485
Hante Meuleman1a873342012-09-27 14:17:54 +02004486 memset(&ssid_le, 0, sizeof(ssid_le));
4487 if (settings->ssid == NULL || settings->ssid_len == 0) {
4488 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4489 ssid_ie = brcmf_parse_tlvs(
4490 (u8 *)&settings->beacon.head[ie_offset],
4491 settings->beacon.head_len - ie_offset,
4492 WLAN_EID_SSID);
4493 if (!ssid_ie)
4494 return -EINVAL;
4495
4496 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4497 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004498 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004499 } else {
4500 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4501 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4502 }
4503
Hante Meulemana44aa402014-12-03 21:05:33 +01004504 if (!mbss) {
4505 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004506 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004507 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004508
4509 /* find the RSN_IE */
4510 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4511 settings->beacon.tail_len, WLAN_EID_RSN);
4512
4513 /* find the WPA_IE */
4514 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4515 settings->beacon.tail_len);
4516
Hante Meuleman1a873342012-09-27 14:17:54 +02004517 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004518 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004519 if (wpa_ie != NULL) {
4520 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004521 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004522 if (err < 0)
4523 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004524 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004525 struct brcmf_vs_tlv *tmp_ie;
4526
4527 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4528
Hante Meuleman1a873342012-09-27 14:17:54 +02004529 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004530 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004531 if (err < 0)
4532 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004533 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004534 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004535 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004536 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004537 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004538
Hante Meulemana0f07952013-02-08 15:53:47 +01004539 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004540
Rafał Miłecki8707e082016-05-27 21:07:19 +02004541 /* Parameters shared by all radio interfaces */
Hante Meulemana44aa402014-12-03 21:05:33 +01004542 if (!mbss) {
Arend van Spriel98027762014-12-21 12:43:53 +01004543 if (is_11d != ifp->vif->is_11d) {
4544 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4545 is_11d);
4546 if (err < 0) {
4547 brcmf_err("Regulatory Set Error, %d\n", err);
4548 goto exit;
4549 }
4550 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004551 if (settings->beacon_interval) {
4552 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4553 settings->beacon_interval);
4554 if (err < 0) {
4555 brcmf_err("Beacon Interval Set Error, %d\n",
4556 err);
4557 goto exit;
4558 }
4559 }
4560 if (settings->dtim_period) {
4561 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4562 settings->dtim_period);
4563 if (err < 0) {
4564 brcmf_err("DTIM Interval Set Error, %d\n", err);
4565 goto exit;
4566 }
4567 }
4568
Hante Meuleman8abffd82015-10-29 20:33:16 +01004569 if ((dev_role == NL80211_IFTYPE_AP) &&
4570 ((ifp->ifidx == 0) ||
4571 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004572 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4573 if (err < 0) {
4574 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4575 goto exit;
4576 }
4577 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4578 }
4579
4580 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004581 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004582 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004583 goto exit;
4584 }
Arend van Spriel98027762014-12-21 12:43:53 +01004585 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4586 /* Multiple-BSS should use same 11d configuration */
4587 err = -EINVAL;
4588 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004589 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004590
4591 /* Interface specific setup */
Hante Meulemana0f07952013-02-08 15:53:47 +01004592 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004593 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4594 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4595
Hante Meulemana0f07952013-02-08 15:53:47 +01004596 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4597 if (err < 0) {
4598 brcmf_err("setting AP mode failed %d\n", err);
4599 goto exit;
4600 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004601 if (!mbss) {
4602 /* Firmware 10.x requires setting channel after enabling
4603 * AP and before bringing interface up.
4604 */
4605 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4606 if (err < 0) {
4607 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4608 chanspec, err);
4609 goto exit;
4610 }
4611 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004612 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4613 if (err < 0) {
4614 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4615 goto exit;
4616 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004617 /* On DOWN the firmware removes the WEP keys, reconfigure
4618 * them if they were set.
4619 */
4620 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004621
4622 memset(&join_params, 0, sizeof(join_params));
4623 /* join parameters starts with ssid */
4624 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4625 /* create softap */
4626 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4627 &join_params, sizeof(join_params));
4628 if (err < 0) {
4629 brcmf_err("SET SSID error (%d)\n", err);
4630 goto exit;
4631 }
4632 brcmf_dbg(TRACE, "AP mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004633 } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
4634 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
4635 if (err < 0) {
4636 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4637 chanspec, err);
4638 goto exit;
4639 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004640 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4641 sizeof(ssid_le));
4642 if (err < 0) {
4643 brcmf_err("setting ssid failed %d\n", err);
4644 goto exit;
4645 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004646 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004647 bss_enable.enable = cpu_to_le32(1);
4648 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4649 sizeof(bss_enable));
4650 if (err < 0) {
4651 brcmf_err("bss_enable config failed %d\n", err);
4652 goto exit;
4653 }
4654
4655 brcmf_dbg(TRACE, "GO mode configuration complete\n");
Rafał Miłecki8707e082016-05-27 21:07:19 +02004656 } else {
4657 WARN_ON(1);
Hante Meulemana0f07952013-02-08 15:53:47 +01004658 }
Rafał Miłecki8707e082016-05-27 21:07:19 +02004659
Arend van Sprielc1179032012-10-22 13:55:33 -07004660 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004661 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004662
4663exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004664 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004665 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004666 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004667 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004668 return err;
4669}
4670
4671static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4672{
Arend van Sprielc1179032012-10-22 13:55:33 -07004673 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004674 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004675 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004676 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004677
Arend van Sprield96b8012012-12-05 15:26:02 +01004678 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004679
Hante Meuleman426d0a52013-02-08 15:53:53 +01004680 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004681 /* Due to most likely deauths outstanding we sleep */
4682 /* first to make sure they get processed by fw. */
4683 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004684
Hante Meulemana44aa402014-12-03 21:05:33 +01004685 if (ifp->vif->mbss) {
4686 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4687 return err;
4688 }
4689
Hante Meuleman5c33a942013-04-02 21:06:18 +02004690 memset(&join_params, 0, sizeof(join_params));
4691 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4692 &join_params, sizeof(join_params));
4693 if (err < 0)
4694 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004695 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004696 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004697 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004698 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4699 if (err < 0)
4700 brcmf_err("setting AP mode failed %d\n", err);
4701 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4702 if (err < 0)
4703 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004704 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4705 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Arend van Spriel98027762014-12-21 12:43:53 +01004706 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4707 ifp->vif->is_11d);
4708 if (err < 0)
4709 brcmf_err("restoring REGULATORY setting failed %d\n",
4710 err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004711 /* Bring device back up so it can be used again */
4712 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4713 if (err < 0)
4714 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004715 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004716 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004717 bss_enable.enable = cpu_to_le32(0);
4718 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4719 sizeof(bss_enable));
4720 if (err < 0)
4721 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004722 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004723 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004724 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004725 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004726 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004727
Hante Meuleman1a873342012-09-27 14:17:54 +02004728 return err;
4729}
4730
Hante Meulemana0f07952013-02-08 15:53:47 +01004731static s32
4732brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4733 struct cfg80211_beacon_data *info)
4734{
Hante Meulemana0f07952013-02-08 15:53:47 +01004735 struct brcmf_if *ifp = netdev_priv(ndev);
4736 s32 err;
4737
4738 brcmf_dbg(TRACE, "Enter\n");
4739
Hante Meulemana0f07952013-02-08 15:53:47 +01004740 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4741
4742 return err;
4743}
4744
Hante Meuleman1a873342012-09-27 14:17:54 +02004745static int
4746brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004747 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004748{
Hante Meulemana0f07952013-02-08 15:53:47 +01004749 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004750 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004751 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004752 s32 err;
4753
Jouni Malinen89c771e2014-10-10 20:52:40 +03004754 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004755 return -EFAULT;
4756
Jouni Malinen89c771e2014-10-10 20:52:40 +03004757 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004758
Hante Meulemana0f07952013-02-08 15:53:47 +01004759 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4760 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004761 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004762 return -EIO;
4763
Jouni Malinen89c771e2014-10-10 20:52:40 +03004764 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004765 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004766 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004767 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004768 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004769 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004770
Arend van Sprield96b8012012-12-05 15:26:02 +01004771 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004772 return err;
4773}
4774
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004775static int
4776brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4777 const u8 *mac, struct station_parameters *params)
4778{
4779 struct brcmf_if *ifp = netdev_priv(ndev);
4780 s32 err;
4781
4782 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4783 params->sta_flags_mask, params->sta_flags_set);
4784
4785 /* Ignore all 00 MAC */
4786 if (is_zero_ether_addr(mac))
4787 return 0;
4788
4789 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4790 return 0;
4791
4792 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4793 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4794 (void *)mac, ETH_ALEN);
4795 else
4796 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4797 (void *)mac, ETH_ALEN);
4798 if (err < 0)
4799 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4800
4801 return err;
4802}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004803
4804static void
4805brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4806 struct wireless_dev *wdev,
4807 u16 frame_type, bool reg)
4808{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004809 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004810 u16 mgmt_type;
4811
4812 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4813
4814 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004815 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004816 if (reg)
4817 vif->mgmt_rx_reg |= BIT(mgmt_type);
4818 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004819 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004820}
4821
4822
4823static int
4824brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004825 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004826{
4827 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004828 struct ieee80211_channel *chan = params->chan;
4829 const u8 *buf = params->buf;
4830 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004831 const struct ieee80211_mgmt *mgmt;
4832 struct brcmf_cfg80211_vif *vif;
4833 s32 err = 0;
4834 s32 ie_offset;
4835 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004836 struct brcmf_fil_action_frame_le *action_frame;
4837 struct brcmf_fil_af_params_le *af_params;
4838 bool ack;
4839 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004840 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004841
4842 brcmf_dbg(TRACE, "Enter\n");
4843
4844 *cookie = 0;
4845
4846 mgmt = (const struct ieee80211_mgmt *)buf;
4847
Hante Meulemana0f07952013-02-08 15:53:47 +01004848 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4849 brcmf_err("Driver only allows MGMT packet type\n");
4850 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004851 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004852
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004853 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4854
Hante Meulemana0f07952013-02-08 15:53:47 +01004855 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4856 /* Right now the only reason to get a probe response */
4857 /* is for p2p listen response or for p2p GO from */
4858 /* wpa_supplicant. Unfortunately the probe is send */
4859 /* on primary ndev, while dongle wants it on the p2p */
4860 /* vif. Since this is only reason for a probe */
4861 /* response to be sent, the vif is taken from cfg. */
4862 /* If ever desired to send proberesp for non p2p */
4863 /* response then data should be checked for */
4864 /* "DIRECT-". Note in future supplicant will take */
4865 /* dedicated p2p wdev to do this and then this 'hack'*/
4866 /* is not needed anymore. */
4867 ie_offset = DOT11_MGMT_HDR_LEN +
4868 DOT11_BCN_PRB_FIXED_LEN;
4869 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004870 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4871 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4872 err = brcmf_vif_set_mgmt_ie(vif,
4873 BRCMF_VNDR_IE_PRBRSP_FLAG,
4874 &buf[ie_offset],
4875 ie_len);
4876 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4877 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004878 } else if (ieee80211_is_action(mgmt->frame_control)) {
4879 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4880 if (af_params == NULL) {
4881 brcmf_err("unable to allocate frame\n");
4882 err = -ENOMEM;
4883 goto exit;
4884 }
4885 action_frame = &af_params->action_frame;
4886 /* Add the packet Id */
4887 action_frame->packet_id = cpu_to_le32(*cookie);
4888 /* Add BSSID */
4889 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4890 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4891 /* Add the length exepted for 802.11 header */
4892 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004893 /* Add the channel. Use the one specified as parameter if any or
4894 * the current one (got from the firmware) otherwise
4895 */
4896 if (chan)
4897 freq = chan->center_freq;
4898 else
4899 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4900 &freq);
4901 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004902 af_params->channel = cpu_to_le32(chan_nr);
4903
4904 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4905 le16_to_cpu(action_frame->len));
4906
4907 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004908 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004909
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004910 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004911 af_params);
4912
4913 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4914 GFP_KERNEL);
4915 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004916 } else {
4917 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4918 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4919 }
4920
Hante Meuleman18e2f612013-02-08 15:53:49 +01004921exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004922 return err;
4923}
4924
4925
4926static int
4927brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4928 struct wireless_dev *wdev,
4929 u64 cookie)
4930{
4931 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4932 struct brcmf_cfg80211_vif *vif;
4933 int err = 0;
4934
4935 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4936
4937 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4938 if (vif == NULL) {
4939 brcmf_err("No p2p device available for probe response\n");
4940 err = -ENODEV;
4941 goto exit;
4942 }
4943 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4944exit:
4945 return err;
4946}
4947
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02004948static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
4949 struct wireless_dev *wdev,
4950 struct cfg80211_chan_def *chandef)
4951{
4952 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4953 struct net_device *ndev = wdev->netdev;
4954 struct brcmf_if *ifp;
4955 struct brcmu_chan ch;
4956 enum nl80211_band band = 0;
4957 enum nl80211_chan_width width = 0;
4958 u32 chanspec;
4959 int freq, err;
4960
4961 if (!ndev)
4962 return -ENODEV;
4963 ifp = netdev_priv(ndev);
4964
4965 err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
4966 if (err) {
4967 brcmf_err("chanspec failed (%d)\n", err);
4968 return err;
4969 }
4970
4971 ch.chspec = chanspec;
4972 cfg->d11inf.decchspec(&ch);
4973
4974 switch (ch.band) {
4975 case BRCMU_CHAN_BAND_2G:
4976 band = NL80211_BAND_2GHZ;
4977 break;
4978 case BRCMU_CHAN_BAND_5G:
4979 band = NL80211_BAND_5GHZ;
4980 break;
4981 }
4982
4983 switch (ch.bw) {
4984 case BRCMU_CHAN_BW_80:
4985 width = NL80211_CHAN_WIDTH_80;
4986 break;
4987 case BRCMU_CHAN_BW_40:
4988 width = NL80211_CHAN_WIDTH_40;
4989 break;
4990 case BRCMU_CHAN_BW_20:
4991 width = NL80211_CHAN_WIDTH_20;
4992 break;
4993 case BRCMU_CHAN_BW_80P80:
4994 width = NL80211_CHAN_WIDTH_80P80;
4995 break;
4996 case BRCMU_CHAN_BW_160:
4997 width = NL80211_CHAN_WIDTH_160;
4998 break;
4999 }
5000
5001 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
5002 chandef->chan = ieee80211_get_channel(wiphy, freq);
5003 chandef->width = width;
5004 chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
5005 chandef->center_freq2 = 0;
5006
5007 return 0;
5008}
5009
Piotr Haber61730d42013-04-23 12:53:12 +02005010static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
5011 struct wireless_dev *wdev,
5012 enum nl80211_crit_proto_id proto,
5013 u16 duration)
5014{
5015 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5016 struct brcmf_cfg80211_vif *vif;
5017
5018 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5019
5020 /* only DHCP support for now */
5021 if (proto != NL80211_CRIT_PROTO_DHCP)
5022 return -EINVAL;
5023
5024 /* suppress and abort scanning */
5025 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5026 brcmf_abort_scanning(cfg);
5027
5028 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
5029}
5030
5031static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
5032 struct wireless_dev *wdev)
5033{
5034 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
5035 struct brcmf_cfg80211_vif *vif;
5036
5037 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
5038
5039 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
5040 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
5041}
5042
Hante Meuleman70b7d942014-07-30 13:20:07 +02005043static s32
5044brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
5045 const struct brcmf_event_msg *e, void *data)
5046{
5047 switch (e->reason) {
5048 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
5049 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
5050 break;
5051 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
5052 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
5053 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5054 break;
5055 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
5056 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
5057 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5058 break;
5059 }
5060
5061 return 0;
5062}
5063
Arend van Spriel89c2f382013-08-10 12:27:25 +02005064static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
5065{
5066 int ret;
5067
5068 switch (oper) {
5069 case NL80211_TDLS_DISCOVERY_REQ:
5070 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
5071 break;
5072 case NL80211_TDLS_SETUP:
5073 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
5074 break;
5075 case NL80211_TDLS_TEARDOWN:
5076 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
5077 break;
5078 default:
5079 brcmf_err("unsupported operation: %d\n", oper);
5080 ret = -EOPNOTSUPP;
5081 }
5082 return ret;
5083}
5084
5085static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02005086 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005087 enum nl80211_tdls_operation oper)
5088{
5089 struct brcmf_if *ifp;
5090 struct brcmf_tdls_iovar_le info;
5091 int ret = 0;
5092
5093 ret = brcmf_convert_nl80211_tdls_oper(oper);
5094 if (ret < 0)
5095 return ret;
5096
5097 ifp = netdev_priv(ndev);
5098 memset(&info, 0, sizeof(info));
5099 info.mode = (u8)ret;
5100 if (peer)
5101 memcpy(info.ea, peer, ETH_ALEN);
5102
5103 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
5104 &info, sizeof(info));
5105 if (ret < 0)
5106 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
5107
5108 return ret;
5109}
5110
Hante Meuleman5c22fb82016-02-17 11:27:03 +01005111#ifdef CONFIG_PM
5112static int
5113brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
5114 struct cfg80211_gtk_rekey_data *gtk)
5115{
5116 struct brcmf_if *ifp = netdev_priv(ndev);
5117 struct brcmf_gtk_keyinfo_le gtk_le;
5118 int ret;
5119
5120 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
5121
5122 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
5123 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
5124 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
5125 sizeof(gtk_le.replay_counter));
5126
5127 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
5128 sizeof(gtk_le));
5129 if (ret < 0)
5130 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
5131
5132 return ret;
5133}
5134#endif
5135
5136static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01005137 .add_virtual_intf = brcmf_cfg80211_add_iface,
5138 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005139 .change_virtual_intf = brcmf_cfg80211_change_iface,
5140 .scan = brcmf_cfg80211_scan,
5141 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
5142 .join_ibss = brcmf_cfg80211_join_ibss,
5143 .leave_ibss = brcmf_cfg80211_leave_ibss,
5144 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02005145 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005146 .set_tx_power = brcmf_cfg80211_set_tx_power,
5147 .get_tx_power = brcmf_cfg80211_get_tx_power,
5148 .add_key = brcmf_cfg80211_add_key,
5149 .del_key = brcmf_cfg80211_del_key,
5150 .get_key = brcmf_cfg80211_get_key,
5151 .set_default_key = brcmf_cfg80211_config_default_key,
5152 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
5153 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005154 .connect = brcmf_cfg80211_connect,
5155 .disconnect = brcmf_cfg80211_disconnect,
5156 .suspend = brcmf_cfg80211_suspend,
5157 .resume = brcmf_cfg80211_resume,
5158 .set_pmksa = brcmf_cfg80211_set_pmksa,
5159 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02005160 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02005161 .start_ap = brcmf_cfg80211_start_ap,
5162 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01005163 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02005164 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01005165 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02005166 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
5167 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005168 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
5169 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
5170 .remain_on_channel = brcmf_p2p_remain_on_channel,
5171 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Rafał Miłeckiee6e7aa2016-05-20 13:38:58 +02005172 .get_channel = brcmf_cfg80211_get_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02005173 .start_p2p_device = brcmf_p2p_start_device,
5174 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02005175 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
5176 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02005177 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005178};
5179
Arend van Spriel3eacf862012-10-22 13:55:30 -07005180struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Rafał Miłecki26072332016-06-06 23:03:55 +02005181 enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005182{
Hante Meulemana44aa402014-12-03 21:05:33 +01005183 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005184 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01005185 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005186
Arend van Spriel33a6b152013-02-08 15:53:39 +01005187 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01005188 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07005189 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
5190 if (!vif)
5191 return ERR_PTR(-ENOMEM);
5192
5193 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01005194 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07005195
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07005196 brcmf_init_prof(&vif->profile);
5197
Hante Meulemana44aa402014-12-03 21:05:33 +01005198 if (type == NL80211_IFTYPE_AP) {
5199 mbss = false;
5200 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
5201 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
5202 mbss = true;
5203 break;
5204 }
5205 }
5206 vif->mbss = mbss;
5207 }
5208
Arend van Spriel3eacf862012-10-22 13:55:30 -07005209 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005210 return vif;
5211}
5212
Arend van Spriel427dec52014-01-06 12:40:47 +01005213void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07005214{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005215 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005216 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005217}
5218
Arend van Spriel9df4d542014-01-06 12:40:49 +01005219void brcmf_cfg80211_free_netdev(struct net_device *ndev)
5220{
5221 struct brcmf_cfg80211_vif *vif;
5222 struct brcmf_if *ifp;
5223
5224 ifp = netdev_priv(ndev);
5225 vif = ifp->vif;
5226
Arend van Spriel95ef1232015-08-26 22:15:04 +02005227 if (vif)
5228 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005229 free_netdev(ndev);
5230}
5231
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005232static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005233{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005234 u32 event = e->event_code;
5235 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005236
5237 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005238 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005239 return true;
5240 }
5241
5242 return false;
5243}
5244
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005245static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005246{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005247 u32 event = e->event_code;
5248 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005249
Hante Meuleman68ca3952014-02-25 20:30:26 +01005250 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5251 (event == BRCMF_E_DISASSOC_IND) ||
5252 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005253 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005254 return true;
5255 }
5256 return false;
5257}
5258
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005259static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005260 const struct brcmf_event_msg *e)
5261{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005262 u32 event = e->event_code;
5263 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005264
5265 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005266 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5267 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 return true;
5269 }
5270
5271 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005272 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005273 return true;
5274 }
5275
5276 return false;
5277}
5278
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005279static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005280{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005281 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005282
5283 kfree(conn_info->req_ie);
5284 conn_info->req_ie = NULL;
5285 conn_info->req_ie_len = 0;
5286 kfree(conn_info->resp_ie);
5287 conn_info->resp_ie = NULL;
5288 conn_info->resp_ie_len = 0;
5289}
5290
Hante Meuleman89286dc2013-02-08 15:53:46 +01005291static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5292 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005294 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005295 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005296 u32 req_len;
5297 u32 resp_len;
5298 s32 err = 0;
5299
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005300 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005301
Arend van Sprielac24be62012-10-22 10:36:23 -07005302 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5303 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005304 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005305 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005306 return err;
5307 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005308 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005309 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005310 req_len = le32_to_cpu(assoc_info->req_len);
5311 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005312 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005313 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005314 cfg->extra_buf,
5315 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005316 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005317 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005318 return err;
5319 }
5320 conn_info->req_ie_len = req_len;
5321 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005322 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005323 GFP_KERNEL);
5324 } else {
5325 conn_info->req_ie_len = 0;
5326 conn_info->req_ie = NULL;
5327 }
5328 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005329 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005330 cfg->extra_buf,
5331 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005332 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005333 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005334 return err;
5335 }
5336 conn_info->resp_ie_len = resp_len;
5337 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005338 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005339 GFP_KERNEL);
5340 } else {
5341 conn_info->resp_ie_len = 0;
5342 conn_info->resp_ie = NULL;
5343 }
Arend van Spriel16886732012-12-05 15:26:04 +01005344 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5345 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005346
5347 return err;
5348}
5349
5350static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005351brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005352 struct net_device *ndev,
5353 const struct brcmf_event_msg *e)
5354{
Arend van Sprielc1179032012-10-22 13:55:33 -07005355 struct brcmf_if *ifp = netdev_priv(ndev);
5356 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005357 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5358 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005359 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005360 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005361 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005362 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 u32 freq;
5364 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005365 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005366
Arend van Sprield96b8012012-12-05 15:26:02 +01005367 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368
Hante Meuleman89286dc2013-02-08 15:53:46 +01005369 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005370 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005371 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005372
Franky Lina180b832012-10-10 11:13:09 -07005373 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5374 if (buf == NULL) {
5375 err = -ENOMEM;
5376 goto done;
5377 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378
Franky Lina180b832012-10-10 11:13:09 -07005379 /* data sent to dongle has to be little endian */
5380 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005381 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005382 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005383
5384 if (err)
5385 goto done;
5386
5387 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005388 ch.chspec = le16_to_cpu(bi->chanspec);
5389 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390
Franky Lin83cf17a2013-04-11 13:28:50 +02005391 if (ch.band == BRCMU_CHAN_BAND_2G)
Johannes Berg57fbcce2016-04-12 15:56:15 +02005392 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005393 else
Johannes Berg57fbcce2016-04-12 15:56:15 +02005394 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005395
Rafał Miłecki4712d882016-05-20 13:38:57 +02005396 freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005397 notify_channel = ieee80211_get_channel(wiphy, freq);
5398
Franky Lina180b832012-10-10 11:13:09 -07005399done:
5400 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005401 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005402 conn_info->req_ie, conn_info->req_ie_len,
5403 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005404 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005405
Arend van Sprielc1179032012-10-22 13:55:33 -07005406 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005407 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005408 return err;
5409}
5410
5411static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005412brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005413 struct net_device *ndev, const struct brcmf_event_msg *e,
5414 bool completed)
5415{
Arend van Sprielc1179032012-10-22 13:55:33 -07005416 struct brcmf_if *ifp = netdev_priv(ndev);
5417 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005418 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419
Arend van Sprield96b8012012-12-05 15:26:02 +01005420 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005421
Arend van Sprielc1179032012-10-22 13:55:33 -07005422 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5423 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005424 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005425 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005426 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005427 brcmf_update_bss_info(cfg, ifp);
5428 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5429 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005430 }
5431 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005432 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005433 conn_info->req_ie,
5434 conn_info->req_ie_len,
5435 conn_info->resp_ie,
5436 conn_info->resp_ie_len,
5437 completed ? WLAN_STATUS_SUCCESS :
5438 WLAN_STATUS_AUTH_TIMEOUT,
5439 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005440 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5441 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005442 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005443 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005444 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005445}
5446
5447static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005448brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005449 struct net_device *ndev,
5450 const struct brcmf_event_msg *e, void *data)
5451{
Hante Meuleman7ee29602013-02-06 18:40:43 +01005452 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005453 u32 event = e->event_code;
5454 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005455 struct station_info sinfo;
5456
Arend van Spriel16886732012-12-05 15:26:04 +01005457 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005458 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5459 ndev != cfg_to_ndev(cfg)) {
5460 brcmf_dbg(CONN, "AP mode link down\n");
5461 complete(&cfg->vif_disabled);
5462 return 0;
5463 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005464
Hante Meuleman1a873342012-09-27 14:17:54 +02005465 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005466 (reason == BRCMF_E_STATUS_SUCCESS)) {
5467 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005468 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005469 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005470 return -EINVAL;
5471 }
5472 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005473 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005474 generation++;
5475 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005476 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005477 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5478 (event == BRCMF_E_DEAUTH_IND) ||
5479 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005480 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005481 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005482 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005483}
5484
5485static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005486brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005487 const struct brcmf_event_msg *e, void *data)
5488{
Arend van Spriel19937322012-11-05 16:22:32 -08005489 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5490 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005491 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005492 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005493 s32 err = 0;
5494
Hante Meuleman8851cce2014-07-30 13:20:02 +02005495 if ((e->event_code == BRCMF_E_DEAUTH) ||
5496 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5497 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5498 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5499 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5500 }
5501
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005502 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005503 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005504 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005505 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005506 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005507 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005508 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005509 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005510 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005511 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5512 &ifp->vif->sme_state);
5513 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5514 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005515 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005516 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005517 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005518 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005519 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005520 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005521 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005522 brcmf_link_down(ifp->vif,
5523 brcmf_map_fw_linkdown_reason(e));
5524 brcmf_init_prof(ndev_to_prof(ndev));
5525 if (ndev != cfg_to_ndev(cfg))
5526 complete(&cfg->vif_disabled);
5527 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005528 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005529 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005530 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005531 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5532 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005533 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005534 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005535 }
5536
5537 return err;
5538}
5539
5540static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005541brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005542 const struct brcmf_event_msg *e, void *data)
5543{
Arend van Spriel19937322012-11-05 16:22:32 -08005544 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005545 u32 event = e->event_code;
5546 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005547
5548 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005549 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005550 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005551 else
Arend van Spriel19937322012-11-05 16:22:32 -08005552 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005553 }
5554
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005555 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005556}
5557
5558static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005559brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005560 const struct brcmf_event_msg *e, void *data)
5561{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005562 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005563 enum nl80211_key_type key_type;
5564
5565 if (flags & BRCMF_EVENT_MSG_GROUP)
5566 key_type = NL80211_KEYTYPE_GROUP;
5567 else
5568 key_type = NL80211_KEYTYPE_PAIRWISE;
5569
Arend van Spriel19937322012-11-05 16:22:32 -08005570 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005571 NULL, GFP_KERNEL);
5572
5573 return 0;
5574}
5575
Arend van Sprield3c0b632013-02-08 15:53:37 +01005576static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5577 const struct brcmf_event_msg *e, void *data)
5578{
5579 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5580 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5581 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5582 struct brcmf_cfg80211_vif *vif;
5583
Hante Meuleman37a869e2015-10-29 20:33:17 +01005584 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005585 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005586 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005587
Arend van Sprield3c0b632013-02-08 15:53:37 +01005588 mutex_lock(&event->vif_event_lock);
5589 event->action = ifevent->action;
5590 vif = event->vif;
5591
5592 switch (ifevent->action) {
5593 case BRCMF_E_IF_ADD:
5594 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005595 if (!cfg->vif_event.vif) {
5596 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005597 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005598 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005599
5600 ifp->vif = vif;
5601 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005602 if (ifp->ndev) {
5603 vif->wdev.netdev = ifp->ndev;
5604 ifp->ndev->ieee80211_ptr = &vif->wdev;
5605 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5606 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005607 mutex_unlock(&event->vif_event_lock);
5608 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005609 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005610
5611 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005612 mutex_unlock(&event->vif_event_lock);
5613 /* event may not be upon user request */
5614 if (brcmf_cfg80211_vif_event_armed(cfg))
5615 wake_up(&event->vif_wq);
5616 return 0;
5617
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005618 case BRCMF_E_IF_CHANGE:
5619 mutex_unlock(&event->vif_event_lock);
5620 wake_up(&event->vif_wq);
5621 return 0;
5622
Arend van Sprield3c0b632013-02-08 15:53:37 +01005623 default:
5624 mutex_unlock(&event->vif_event_lock);
5625 break;
5626 }
5627 return -EINVAL;
5628}
5629
Arend van Spriel5b435de2011-10-05 13:19:03 +02005630static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5631{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005632 conf->frag_threshold = (u32)-1;
5633 conf->rts_threshold = (u32)-1;
5634 conf->retry_short = (u32)-1;
5635 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005636}
5637
Arend van Spriel5c36b992012-11-14 18:46:05 -08005638static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005639{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005640 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5641 brcmf_notify_connect_status);
5642 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5643 brcmf_notify_connect_status);
5644 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5645 brcmf_notify_connect_status);
5646 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5647 brcmf_notify_connect_status);
5648 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5649 brcmf_notify_connect_status);
5650 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5651 brcmf_notify_connect_status);
5652 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5653 brcmf_notify_roaming_status);
5654 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5655 brcmf_notify_mic_status);
5656 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5657 brcmf_notify_connect_status);
5658 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5659 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005660 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5661 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005662 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005663 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005664 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5665 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005666 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5667 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005668 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5669 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005670 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5671 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005672}
5673
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005674static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005675{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005676 kfree(cfg->conf);
5677 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005678 kfree(cfg->extra_buf);
5679 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005680 kfree(cfg->wowl.nd);
5681 cfg->wowl.nd = NULL;
5682 kfree(cfg->wowl.nd_info);
5683 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005684 kfree(cfg->escan_info.escan_buf);
5685 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005686}
5687
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005688static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005689{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005690 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5691 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005692 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005693 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5694 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005695 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005696 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5697 if (!cfg->wowl.nd)
5698 goto init_priv_mem_out;
5699 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5700 sizeof(struct cfg80211_wowlan_nd_match *),
5701 GFP_KERNEL);
5702 if (!cfg->wowl.nd_info)
5703 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005704 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5705 if (!cfg->escan_info.escan_buf)
5706 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005707
5708 return 0;
5709
5710init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005711 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005712
5713 return -ENOMEM;
5714}
5715
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005716static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005717{
5718 s32 err = 0;
5719
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005720 cfg->scan_request = NULL;
5721 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005722 cfg->active_scan = true; /* we do active scan per default */
5723 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005724 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005725 if (err)
5726 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005727 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005728 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005729 brcmf_init_escan(cfg);
5730 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005731 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005732 return err;
5733}
5734
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005735static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005736{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005737 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005738 brcmf_abort_scanning(cfg);
5739 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005740}
5741
Arend van Sprield3c0b632013-02-08 15:53:37 +01005742static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5743{
5744 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005745 mutex_init(&event->vif_event_lock);
5746}
5747
Hante Meuleman1119e232015-11-25 11:32:42 +01005748static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005749{
Hante Meuleman1119e232015-11-25 11:32:42 +01005750 s32 err;
5751 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005752 __le32 roamtrigger[2];
5753 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005754
Hante Meuleman1119e232015-11-25 11:32:42 +01005755 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005756 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005757 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5758 else
5759 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5760 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5761 if (err) {
5762 brcmf_err("bcn_timeout error (%d)\n", err);
5763 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005764 }
5765
Hante Meuleman1119e232015-11-25 11:32:42 +01005766 /* Enable/Disable built-in roaming to allow supplicant to take care of
5767 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005768 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005769 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005770 ifp->drvr->settings->roamoff ? "Off" : "On");
5771 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5772 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005773 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005774 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005775 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005776 }
5777
Arend van Sprielf588bc02011-10-12 20:51:22 +02005778 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5779 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005780 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005781 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005782 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005783 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005784 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005785 }
5786
Arend van Sprielf588bc02011-10-12 20:51:22 +02005787 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5788 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005789 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005790 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005791 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005792 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005793 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005794 }
5795
Hante Meuleman1119e232015-11-25 11:32:42 +01005796roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005797 return err;
5798}
5799
5800static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005801brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005802{
5803 s32 err = 0;
5804
Arend van Sprielac24be62012-10-22 10:36:23 -07005805 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005806 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005807 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005808 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005809 goto dongle_scantime_out;
5810 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005811 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005812 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005813 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005814 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005815 goto dongle_scantime_out;
5816 }
5817
Arend van Sprielac24be62012-10-22 10:36:23 -07005818 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005819 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005820 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005821 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005822 goto dongle_scantime_out;
5823 }
5824
5825dongle_scantime_out:
5826 return err;
5827}
5828
Arend van Sprielb48d8912014-07-12 08:49:41 +02005829static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5830 struct brcmu_chan *ch)
5831{
5832 u32 ht40_flag;
5833
5834 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5835 if (ch->sb == BRCMU_CHAN_SB_U) {
5836 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5837 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5838 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5839 } else {
5840 /* It should be one of
5841 * IEEE80211_CHAN_NO_HT40 or
5842 * IEEE80211_CHAN_NO_HT40PLUS
5843 */
5844 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5845 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5846 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5847 }
5848}
5849
5850static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5851 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005852{
5853 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005854 struct ieee80211_supported_band *band;
5855 struct ieee80211_channel *channel;
5856 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005857 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005858 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005859 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005860 u8 *pbuf;
5861 u32 i, j;
5862 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005863 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005864 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005865
5866 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5867
5868 if (pbuf == NULL)
5869 return -ENOMEM;
5870
5871 list = (struct brcmf_chanspec_list *)pbuf;
5872
5873 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5874 BRCMF_DCMD_MEDLEN);
5875 if (err) {
5876 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005877 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005878 }
5879
Arend van Sprielb48d8912014-07-12 08:49:41 +02005880 wiphy = cfg_to_wiphy(cfg);
Johannes Berg57fbcce2016-04-12 15:56:15 +02005881 band = wiphy->bands[NL80211_BAND_2GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005882 if (band)
5883 for (i = 0; i < band->n_channels; i++)
5884 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Johannes Berg57fbcce2016-04-12 15:56:15 +02005885 band = wiphy->bands[NL80211_BAND_5GHZ];
Arend van Spriel58de92d2015-04-14 20:10:24 +02005886 if (band)
5887 for (i = 0; i < band->n_channels; i++)
5888 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005889
5890 total = le32_to_cpu(list->count);
5891 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005892 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5893 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005894
Franky Lin83cf17a2013-04-11 13:28:50 +02005895 if (ch.band == BRCMU_CHAN_BAND_2G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005896 band = wiphy->bands[NL80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005897 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02005898 band = wiphy->bands[NL80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005899 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005900 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005901 continue;
5902 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005903 if (!band)
5904 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005905 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005906 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005907 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005908 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005909 ch.bw == BRCMU_CHAN_BW_80)
5910 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005911
5912 channel = band->channels;
5913 index = band->n_channels;
5914 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02005915 if (channel[j].hw_value == ch.control_ch_num) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005916 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005917 break;
5918 }
5919 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005920 channel[index].center_freq =
Rafał Miłecki4712d882016-05-20 13:38:57 +02005921 ieee80211_channel_to_frequency(ch.control_ch_num,
5922 band->band);
5923 channel[index].hw_value = ch.control_ch_num;
Hante Meulemand48200b2013-04-03 12:40:29 +02005924
Arend van Sprielb48d8912014-07-12 08:49:41 +02005925 /* assuming the chanspecs order is HT20,
5926 * HT40 upper, HT40 lower, and VHT80.
5927 */
5928 if (ch.bw == BRCMU_CHAN_BW_80) {
5929 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5930 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5931 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5932 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005933 /* enable the channel and disable other bandwidths
5934 * for now as mentioned order assure they are enabled
5935 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005936 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005937 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5938 IEEE80211_CHAN_NO_80MHZ;
5939 ch.bw = BRCMU_CHAN_BW_20;
5940 cfg->d11inf.encchspec(&ch);
5941 chaninfo = ch.chspec;
5942 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5943 &chaninfo);
5944 if (!err) {
5945 if (chaninfo & WL_CHAN_RADAR)
5946 channel[index].flags |=
5947 (IEEE80211_CHAN_RADAR |
5948 IEEE80211_CHAN_NO_IR);
5949 if (chaninfo & WL_CHAN_PASSIVE)
5950 channel[index].flags |=
5951 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005952 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005953 }
5954 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005955
Arend van Sprielb48d8912014-07-12 08:49:41 +02005956fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005957 kfree(pbuf);
5958 return err;
5959}
5960
Arend van Sprielb48d8912014-07-12 08:49:41 +02005961static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005962{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005963 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5964 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005965 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005966 struct brcmf_chanspec_list *list;
5967 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005968 u32 val;
5969 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005970 struct brcmu_chan ch;
5971 u32 num_chan;
5972 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005973
5974 /* verify support for bw_cap command */
5975 val = WLC_BAND_5G;
5976 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5977
5978 if (!err) {
5979 /* only set 2G bandwidth using bw_cap command */
5980 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5981 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5982 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5983 sizeof(band_bwcap));
5984 } else {
5985 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5986 val = WLC_N_BW_40ALL;
5987 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5988 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005989
5990 if (!err) {
5991 /* update channel info in 2G band */
5992 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5993
5994 if (pbuf == NULL)
5995 return -ENOMEM;
5996
5997 ch.band = BRCMU_CHAN_BAND_2G;
5998 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005999 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006000 ch.chnum = 0;
6001 cfg->d11inf.encchspec(&ch);
6002
6003 /* pass encoded chanspec in query */
6004 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
6005
6006 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
6007 BRCMF_DCMD_MEDLEN);
6008 if (err) {
6009 brcmf_err("get chanspecs error (%d)\n", err);
6010 kfree(pbuf);
6011 return err;
6012 }
6013
Johannes Berg57fbcce2016-04-12 15:56:15 +02006014 band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
Arend van Sprielb48d8912014-07-12 08:49:41 +02006015 list = (struct brcmf_chanspec_list *)pbuf;
6016 num_chan = le32_to_cpu(list->count);
6017 for (i = 0; i < num_chan; i++) {
6018 ch.chspec = (u16)le32_to_cpu(list->element[i]);
6019 cfg->d11inf.decchspec(&ch);
6020 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
6021 continue;
6022 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
6023 continue;
6024 for (j = 0; j < band->n_channels; j++) {
Rafał Miłecki4712d882016-05-20 13:38:57 +02006025 if (band->channels[j].hw_value == ch.control_ch_num)
Arend van Sprielb48d8912014-07-12 08:49:41 +02006026 break;
6027 }
6028 if (WARN_ON(j == band->n_channels))
6029 continue;
6030
6031 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
6032 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02006033 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006034 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006035 return err;
6036}
6037
Arend van Spriel2375d972014-01-06 12:40:41 +01006038static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
6039{
6040 u32 band, mimo_bwcap;
6041 int err;
6042
6043 band = WLC_BAND_2G;
6044 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6045 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006046 bw_cap[NL80211_BAND_2GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006047 band = WLC_BAND_5G;
6048 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
6049 if (!err) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006050 bw_cap[NL80211_BAND_5GHZ] = band;
Arend van Spriel2375d972014-01-06 12:40:41 +01006051 return;
6052 }
6053 WARN_ON(1);
6054 return;
6055 }
6056 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
6057 mimo_bwcap = 0;
6058 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
6059 if (err)
6060 /* assume 20MHz if firmware does not give a clue */
6061 mimo_bwcap = WLC_N_BW_20ALL;
6062
6063 switch (mimo_bwcap) {
6064 case WLC_N_BW_40ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006065 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006066 /* fall-thru */
6067 case WLC_N_BW_20IN2G_40IN5G:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006068 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006069 /* fall-thru */
6070 case WLC_N_BW_20ALL:
Johannes Berg57fbcce2016-04-12 15:56:15 +02006071 bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
6072 bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
Arend van Spriel2375d972014-01-06 12:40:41 +01006073 break;
6074 default:
6075 brcmf_err("invalid mimo_bw_cap value\n");
6076 }
6077}
Hante Meulemand48200b2013-04-03 12:40:29 +02006078
Arend van Spriel18d6c532014-05-12 10:47:35 +02006079static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
6080 u32 bw_cap[2], u32 nchain)
6081{
6082 band->ht_cap.ht_supported = true;
6083 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
6084 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
6085 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6086 }
6087 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
6088 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
6089 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
6090 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
6091 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
6092 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6093}
6094
6095static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
6096{
6097 u16 mcs_map;
6098 int i;
6099
6100 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
6101 mcs_map = (mcs_map << 2) | supp;
6102
6103 return cpu_to_le16(mcs_map);
6104}
6105
6106static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006107 u32 bw_cap[2], u32 nchain, u32 txstreams,
6108 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006109{
6110 __le16 mcs_map;
6111
6112 /* not allowed in 2.4G band */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006113 if (band->band == NL80211_BAND_2GHZ)
Arend van Spriel18d6c532014-05-12 10:47:35 +02006114 return;
6115
6116 band->vht_cap.vht_supported = true;
6117 /* 80MHz is mandatory */
6118 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
6119 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
6120 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
6121 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
6122 }
6123 /* all support 256-QAM */
6124 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
6125 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
6126 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006127
6128 /* Beamforming support information */
6129 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
6130 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
6131 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
6132 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
6133 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
6134 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
6135 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
6136 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
6137
6138 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
6139 band->vht_cap.cap |=
6140 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
6141 band->vht_cap.cap |= ((txstreams - 1) <<
6142 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
6143 band->vht_cap.cap |=
6144 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
6145 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006146}
6147
Arend van Sprielb48d8912014-07-12 08:49:41 +02006148static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006149{
Arend van Sprielb48d8912014-07-12 08:49:41 +02006150 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07006151 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02006152 u32 nmode = 0;
6153 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006154 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01006155 u32 rxchain;
6156 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006157 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02006158 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01006159 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006160 u32 txstreams = 0;
6161 u32 txbf_bfe_cap = 0;
6162 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006163
Arend van Spriel18d6c532014-05-12 10:47:35 +02006164 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02006165 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
6166 if (err) {
6167 brcmf_err("nmode error (%d)\n", err);
6168 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01006169 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006170 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02006171 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
Johannes Berg57fbcce2016-04-12 15:56:15 +02006172 nmode, vhtmode, bw_cap[NL80211_BAND_2GHZ],
6173 bw_cap[NL80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02006174
Daniel Kim4aca7a12014-02-25 20:30:36 +01006175 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
6176 if (err) {
6177 brcmf_err("rxchain error (%d)\n", err);
6178 nchain = 1;
6179 } else {
6180 for (nchain = 0; rxchain; nchain++)
6181 rxchain = rxchain & (rxchain - 1);
6182 }
6183 brcmf_dbg(INFO, "nchain=%d\n", nchain);
6184
Arend van Sprielb48d8912014-07-12 08:49:41 +02006185 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006186 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006187 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02006188 return err;
6189 }
6190
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006191 if (vhtmode) {
6192 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
6193 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
6194 &txbf_bfe_cap);
6195 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
6196 &txbf_bfr_cap);
6197 }
6198
Arend van Sprielb48d8912014-07-12 08:49:41 +02006199 wiphy = cfg_to_wiphy(cfg);
6200 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
6201 band = wiphy->bands[i];
6202 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01006203 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02006204
Arend van Spriel18d6c532014-05-12 10:47:35 +02006205 if (nmode)
6206 brcmf_update_ht_cap(band, bw_cap, nchain);
6207 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01006208 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
6209 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02006210 }
6211
Arend van Sprielb48d8912014-07-12 08:49:41 +02006212 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006213}
6214
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006215static const struct ieee80211_txrx_stypes
6216brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
6217 [NL80211_IFTYPE_STATION] = {
6218 .tx = 0xffff,
6219 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6220 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6221 },
6222 [NL80211_IFTYPE_P2P_CLIENT] = {
6223 .tx = 0xffff,
6224 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6225 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6226 },
6227 [NL80211_IFTYPE_P2P_GO] = {
6228 .tx = 0xffff,
6229 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6230 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6231 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6232 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6233 BIT(IEEE80211_STYPE_AUTH >> 4) |
6234 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6235 BIT(IEEE80211_STYPE_ACTION >> 4)
6236 },
6237 [NL80211_IFTYPE_P2P_DEVICE] = {
6238 .tx = 0xffff,
6239 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6240 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6241 }
6242};
6243
Arend van Spriel0882dda2015-08-20 22:06:03 +02006244/**
6245 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6246 *
6247 * @wiphy: wiphy object.
6248 * @ifp: interface object needed for feat module api.
6249 *
6250 * The interface modes and combinations are determined dynamically here
6251 * based on firmware functionality.
6252 *
6253 * no p2p and no mbss:
6254 *
6255 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6256 *
6257 * no p2p and mbss:
6258 *
6259 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6260 * #AP <= 4, matching BI, channels = 1, 4 total
6261 *
6262 * p2p, no mchan, and mbss:
6263 *
6264 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6265 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6266 * #AP <= 4, matching BI, channels = 1, 4 total
6267 *
6268 * p2p, mchan, and mbss:
6269 *
6270 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6271 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6272 * #AP <= 4, matching BI, channels = 1, 4 total
6273 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006274static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6275{
6276 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006277 struct ieee80211_iface_limit *c0_limits = NULL;
6278 struct ieee80211_iface_limit *p2p_limits = NULL;
6279 struct ieee80211_iface_limit *mbss_limits = NULL;
6280 bool mbss, p2p;
6281 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006282
Arend van Spriel0882dda2015-08-20 22:06:03 +02006283 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6284 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6285
6286 n_combos = 1 + !!p2p + !!mbss;
6287 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006288 if (!combo)
6289 goto err;
6290
Arend van Spriel0882dda2015-08-20 22:06:03 +02006291 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6292 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006293 goto err;
6294
Arend van Spriel0882dda2015-08-20 22:06:03 +02006295 if (p2p) {
6296 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6297 if (!p2p_limits)
6298 goto err;
6299 }
6300
6301 if (mbss) {
6302 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6303 if (!mbss_limits)
6304 goto err;
6305 }
6306
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006307 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6308 BIT(NL80211_IFTYPE_ADHOC) |
6309 BIT(NL80211_IFTYPE_AP);
6310
Arend van Spriel0882dda2015-08-20 22:06:03 +02006311 c = 0;
6312 i = 0;
6313 combo[c].num_different_channels = 1;
6314 c0_limits[i].max = 1;
6315 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6316 if (p2p) {
6317 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6318 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006319 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6320 BIT(NL80211_IFTYPE_P2P_GO) |
6321 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006322 c0_limits[i].max = 1;
6323 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6324 c0_limits[i].max = 1;
6325 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6326 BIT(NL80211_IFTYPE_P2P_GO);
6327 } else {
6328 c0_limits[i].max = 1;
6329 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006330 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006331 combo[c].max_interfaces = i;
6332 combo[c].n_limits = i;
6333 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006334
Arend van Spriel0882dda2015-08-20 22:06:03 +02006335 if (p2p) {
6336 c++;
6337 i = 0;
6338 combo[c].num_different_channels = 1;
6339 p2p_limits[i].max = 1;
6340 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6341 p2p_limits[i].max = 1;
6342 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6343 p2p_limits[i].max = 1;
6344 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6345 p2p_limits[i].max = 1;
6346 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6347 combo[c].max_interfaces = i;
6348 combo[c].n_limits = i;
6349 combo[c].limits = p2p_limits;
6350 }
6351
6352 if (mbss) {
6353 c++;
6354 combo[c].beacon_int_infra_match = true;
6355 combo[c].num_different_channels = 1;
6356 mbss_limits[0].max = 4;
6357 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
6358 combo[c].max_interfaces = 4;
6359 combo[c].n_limits = 1;
6360 combo[c].limits = mbss_limits;
6361 }
6362 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006363 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006364 return 0;
6365
6366err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006367 kfree(c0_limits);
6368 kfree(p2p_limits);
6369 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006370 kfree(combo);
6371 return -ENOMEM;
6372}
6373
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006374static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6375{
6376 /* scheduled scan settings */
6377 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6378 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6379 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6380 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6381}
6382
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006383#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006384static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006385 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006386 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6387 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6388 .pattern_min_len = 1,
6389 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006390};
6391#endif
6392
Hante Meuleman3021ad92016-01-05 11:05:45 +01006393static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006394{
6395#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006396 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006397
6398 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006399 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6400 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6401 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006402 }
6403 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006404 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6405 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6406 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6407 }
6408
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006409 wiphy->wowlan = &brcmf_wowlan_support;
6410#endif
6411}
6412
Arend van Sprielb48d8912014-07-12 08:49:41 +02006413static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006414{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006415 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006416 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006417 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006418 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006419 __le32 bandlist[3];
6420 u32 n_bands;
6421 int err, i;
6422
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006423 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6424 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006425 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006426
6427 err = brcmf_setup_ifmodes(wiphy, ifp);
6428 if (err)
6429 return err;
6430
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006431 for (i = 0, combo = wiphy->iface_combinations;
6432 i < wiphy->n_iface_combinations; i++, combo++) {
6433 max_interfaces = max(max_interfaces, combo->max_interfaces);
6434 }
6435
6436 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6437 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006438 u8 *addr = drvr->addresses[i].addr;
6439
6440 memcpy(addr, drvr->mac, ETH_ALEN);
6441 if (i) {
6442 addr[0] |= BIT(1);
6443 addr[ETH_ALEN - 1] ^= i;
6444 }
6445 }
6446 wiphy->addresses = drvr->addresses;
6447 wiphy->n_addresses = i;
6448
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006449 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Hante Meuleman240d61a2016-02-17 11:27:10 +01006450 wiphy->cipher_suites = brcmf_cipher_suites;
6451 wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
6452 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
6453 wiphy->n_cipher_suites--;
Arend van Spriel7705ba62016-04-17 16:44:58 +02006454 wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
6455 BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
6456 BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
6457
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006458 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6459 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006460 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6461 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6462 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006463 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006464 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6465 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6466 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006467 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6468 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006469
6470 /* vendor commands/events support */
6471 wiphy->vendor_commands = brcmf_vendor_cmds;
6472 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6473
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006474 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006475 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006476 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6477 sizeof(bandlist));
6478 if (err) {
6479 brcmf_err("could not obtain band info: err=%d\n", err);
6480 return err;
6481 }
6482 /* first entry in bandlist is number of bands */
6483 n_bands = le32_to_cpu(bandlist[0]);
6484 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6485 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6486 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6487 GFP_KERNEL);
6488 if (!band)
6489 return -ENOMEM;
6490
6491 band->channels = kmemdup(&__wl_2ghz_channels,
6492 sizeof(__wl_2ghz_channels),
6493 GFP_KERNEL);
6494 if (!band->channels) {
6495 kfree(band);
6496 return -ENOMEM;
6497 }
6498
6499 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006500 wiphy->bands[NL80211_BAND_2GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006501 }
6502 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6503 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6504 GFP_KERNEL);
6505 if (!band)
6506 return -ENOMEM;
6507
6508 band->channels = kmemdup(&__wl_5ghz_channels,
6509 sizeof(__wl_5ghz_channels),
6510 GFP_KERNEL);
6511 if (!band->channels) {
6512 kfree(band);
6513 return -ENOMEM;
6514 }
6515
6516 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006517 wiphy->bands[NL80211_BAND_5GHZ] = band;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006518 }
6519 }
6520 err = brcmf_setup_wiphybands(wiphy);
6521 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006522}
6523
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006524static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006525{
6526 struct net_device *ndev;
6527 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006528 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006529 s32 power_mode;
6530 s32 err = 0;
6531
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006532 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006533 return err;
6534
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006535 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006536 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006537 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006538
Hante Meuleman40a23292013-01-02 15:22:51 +01006539 /* make sure RF is ready for work */
6540 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6541
Hante Meuleman1678ba82015-12-10 13:43:00 +01006542 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006543
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006544 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006545 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006546 if (err)
6547 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006548 brcmf_dbg(INFO, "power save set to %s\n",
6549 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006550
Hante Meuleman1119e232015-11-25 11:32:42 +01006551 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006552 if (err)
6553 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006554 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6555 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006556 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006557 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006558
Franky Lin52f22fb2016-02-17 11:26:55 +01006559 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006560
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006561 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006562default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006563
6564 return err;
6565
6566}
6567
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006568static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006569{
Arend van Sprielc1179032012-10-22 13:55:33 -07006570 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006571
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006572 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006573}
6574
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006575static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006576{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006577 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006578
Arend van Spriel5b435de2011-10-05 13:19:03 +02006579 /*
6580 * While going down, if associated with AP disassociate
6581 * from AP to save power
6582 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006583 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006584 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006585
6586 /* Make sure WPA_Supplicant receives all the event
6587 generated due to DISASSOC call to the fw to keep
6588 the state fw and WPA_Supplicant state consistent
6589 */
6590 brcmf_delay(500);
6591 }
6592
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006593 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006594 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006595
Arend van Spriel5b435de2011-10-05 13:19:03 +02006596 return 0;
6597}
6598
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006599s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006600{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006601 struct brcmf_if *ifp = netdev_priv(ndev);
6602 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006603 s32 err = 0;
6604
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006605 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006606 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006607 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006608
6609 return err;
6610}
6611
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006612s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006613{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006614 struct brcmf_if *ifp = netdev_priv(ndev);
6615 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006616 s32 err = 0;
6617
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006618 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006619 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006620 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006621
6622 return err;
6623}
6624
Arend van Spriela7965fb2013-04-11 17:08:37 +02006625enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6626{
6627 struct wireless_dev *wdev = &ifp->vif->wdev;
6628
6629 return wdev->iftype;
6630}
6631
Hante Meulemanbfe81972014-10-28 14:56:16 +01006632bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6633 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006634{
6635 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006636
6637 list_for_each_entry(vif, &cfg->vif_list, list) {
6638 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006639 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006640 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006641 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006642}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006643
6644static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6645 u8 action)
6646{
6647 u8 evt_action;
6648
6649 mutex_lock(&event->vif_event_lock);
6650 evt_action = event->action;
6651 mutex_unlock(&event->vif_event_lock);
6652 return evt_action == action;
6653}
6654
6655void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6656 struct brcmf_cfg80211_vif *vif)
6657{
6658 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6659
6660 mutex_lock(&event->vif_event_lock);
6661 event->vif = vif;
6662 event->action = 0;
6663 mutex_unlock(&event->vif_event_lock);
6664}
6665
6666bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6667{
6668 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6669 bool armed;
6670
6671 mutex_lock(&event->vif_event_lock);
6672 armed = event->vif != NULL;
6673 mutex_unlock(&event->vif_event_lock);
6674
6675 return armed;
6676}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006677
6678int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6679 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006680{
6681 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6682
6683 return wait_event_timeout(event->vif_wq,
6684 vif_event_equals(event, action), timeout);
6685}
6686
Hante Meuleman73345fd2016-02-17 11:26:53 +01006687static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6688 struct brcmf_fil_country_le *ccreq)
6689{
Hante Meuleman4d792892016-02-17 11:27:07 +01006690 struct brcmfmac_pd_cc *country_codes;
6691 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006692 s32 found_index;
6693 int i;
6694
6695 country_codes = drvr->settings->country_codes;
6696 if (!country_codes) {
6697 brcmf_dbg(TRACE, "No country codes configured for device\n");
6698 return -EINVAL;
6699 }
6700
6701 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6702 (alpha2[1] == ccreq->country_abbrev[1])) {
6703 brcmf_dbg(TRACE, "Country code already set\n");
6704 return -EAGAIN;
6705 }
6706
6707 found_index = -1;
6708 for (i = 0; i < country_codes->table_size; i++) {
6709 cc = &country_codes->table[i];
6710 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6711 found_index = i;
6712 if ((cc->iso3166[0] == alpha2[0]) &&
6713 (cc->iso3166[1] == alpha2[1])) {
6714 found_index = i;
6715 break;
6716 }
6717 }
6718 if (found_index == -1) {
6719 brcmf_dbg(TRACE, "No country code match found\n");
6720 return -EINVAL;
6721 }
6722 memset(ccreq, 0, sizeof(*ccreq));
6723 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6724 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6725 BRCMF_COUNTRY_BUF_SZ);
6726 ccreq->country_abbrev[0] = alpha2[0];
6727 ccreq->country_abbrev[1] = alpha2[1];
6728 ccreq->country_abbrev[2] = 0;
6729
6730 return 0;
6731}
6732
Arend van Spriel63db1a42014-12-21 12:43:51 +01006733static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6734 struct regulatory_request *req)
6735{
6736 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6737 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6738 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006739 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006740 int i;
6741
Arend van Spriel63db1a42014-12-21 12:43:51 +01006742 /* ignore non-ISO3166 country codes */
6743 for (i = 0; i < sizeof(req->alpha2); i++)
6744 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006745 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6746 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006747 return;
6748 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006749
6750 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6751 req->alpha2[0], req->alpha2[1]);
6752
6753 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6754 if (err) {
6755 brcmf_err("Country code iovar returned err = %d\n", err);
6756 return;
6757 }
6758
6759 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6760 if (err)
6761 return;
6762
6763 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6764 if (err) {
6765 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006766 return;
6767 }
6768 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006769}
6770
Arend van Sprielb48d8912014-07-12 08:49:41 +02006771static void brcmf_free_wiphy(struct wiphy *wiphy)
6772{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006773 int i;
6774
Arend van Spriel58de92d2015-04-14 20:10:24 +02006775 if (!wiphy)
6776 return;
6777
Arend van Spriel0882dda2015-08-20 22:06:03 +02006778 if (wiphy->iface_combinations) {
6779 for (i = 0; i < wiphy->n_iface_combinations; i++)
6780 kfree(wiphy->iface_combinations[i].limits);
6781 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006782 kfree(wiphy->iface_combinations);
Johannes Berg57fbcce2016-04-12 15:56:15 +02006783 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6784 kfree(wiphy->bands[NL80211_BAND_2GHZ]->channels);
6785 kfree(wiphy->bands[NL80211_BAND_2GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006786 }
Johannes Berg57fbcce2016-04-12 15:56:15 +02006787 if (wiphy->bands[NL80211_BAND_5GHZ]) {
6788 kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
6789 kfree(wiphy->bands[NL80211_BAND_5GHZ]);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006790 }
6791 wiphy_free(wiphy);
6792}
6793
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006794struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006795 struct device *busdev,
6796 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006797{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006798 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006799 struct brcmf_cfg80211_info *cfg;
6800 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006801 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006802 struct brcmf_cfg80211_vif *vif;
6803 struct brcmf_if *ifp;
6804 s32 err = 0;
6805 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006806 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006807
6808 if (!ndev) {
6809 brcmf_err("ndev is invalid\n");
6810 return NULL;
6811 }
6812
Muhammad Falak R Wanid464fd82016-05-19 19:29:03 +05306813 ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006814 if (!ops)
6815 return NULL;
6816
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006817 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006818#ifdef CONFIG_PM
6819 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6820 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6821#endif
6822 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006823 if (!wiphy) {
6824 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006825 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006826 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006827 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006828 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006829
6830 cfg = wiphy_priv(wiphy);
6831 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006832 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006833 cfg->pub = drvr;
6834 init_vif_event(&cfg->vif_event);
6835 INIT_LIST_HEAD(&cfg->vif_list);
6836
Rafał Miłecki26072332016-06-06 23:03:55 +02006837 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006838 if (IS_ERR(vif))
6839 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006840
6841 vif->ifp = ifp;
6842 vif->wdev.netdev = ndev;
6843 ndev->ieee80211_ptr = &vif->wdev;
6844 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6845
6846 err = wl_init_priv(cfg);
6847 if (err) {
6848 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006849 brcmf_free_vif(vif);
6850 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006851 }
6852 ifp->vif = vif;
6853
Arend van Sprielb48d8912014-07-12 08:49:41 +02006854 /* determine d11 io type before wiphy setup */
6855 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006856 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006857 brcmf_err("Failed to get D11 version (%d)\n", err);
6858 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006859 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006860 cfg->d11inf.io_type = (u8)io_type;
6861 brcmu_d11_attach(&cfg->d11inf);
6862
6863 err = brcmf_setup_wiphy(wiphy, ifp);
6864 if (err < 0)
6865 goto priv_out;
6866
6867 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006868 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006869 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6870 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6871
6872 /* firmware defaults to 40MHz disabled in 2G band. We signal
6873 * cfg80211 here that we do and have it decide we can enable
6874 * it. But first check if device does support 2G operation.
6875 */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006876 if (wiphy->bands[NL80211_BAND_2GHZ]) {
6877 cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006878 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6879 }
6880 err = wiphy_register(wiphy);
6881 if (err < 0) {
6882 brcmf_err("Could not register wiphy device (%d)\n", err);
6883 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006884 }
6885
6886 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6887 * setup 40MHz in 2GHz band and enable OBSS scanning.
6888 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006889 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6890 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006891 if (!err)
6892 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6893 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006894 else
6895 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006896 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006897 /* p2p might require that "if-events" get processed by fweh. So
6898 * activate the already registered event handlers now and activate
6899 * the rest when initialization has completed. drvr->config needs to
6900 * be assigned before activating events.
6901 */
6902 drvr->config = cfg;
6903 err = brcmf_fweh_activate_events(ifp);
6904 if (err) {
6905 brcmf_err("FWEH activation failed (%d)\n", err);
6906 goto wiphy_unreg_out;
6907 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006908
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006909 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006910 if (err) {
6911 brcmf_err("P2P initilisation failed (%d)\n", err);
6912 goto wiphy_unreg_out;
6913 }
6914 err = brcmf_btcoex_attach(cfg);
6915 if (err) {
6916 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6917 brcmf_p2p_detach(&cfg->p2p);
6918 goto wiphy_unreg_out;
6919 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006920
Hante Meulemana7b82d42015-12-10 13:43:04 +01006921 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6922 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6923 if (err) {
6924 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6925 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6926 } else {
6927 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6928 brcmf_notify_tdls_peer_event);
6929 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006930 }
6931
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006932 /* (re-) activate FWEH event handling */
6933 err = brcmf_fweh_activate_events(ifp);
6934 if (err) {
6935 brcmf_err("FWEH activation failed (%d)\n", err);
6936 goto wiphy_unreg_out;
6937 }
6938
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006939 /* Fill in some of the advertised nl80211 supported features */
6940 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6941 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6942#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006943 if (wiphy->wowlan &&
6944 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006945 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6946#endif
6947 }
6948
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006949 return cfg;
6950
Arend van Sprielb48d8912014-07-12 08:49:41 +02006951wiphy_unreg_out:
6952 wiphy_unregister(cfg->wiphy);
6953priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006954 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006955 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006956 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006957wiphy_out:
6958 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006959 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006960 return NULL;
6961}
6962
6963void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6964{
6965 if (!cfg)
6966 return;
6967
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006968 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006969 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006970 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006971 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006972 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006973}