blob: 5e3acaca7231a3c9bedea4c6fd339afd6244b68c [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 */
75#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
76#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
77
78#define VNDR_IE_CMD_LEN 4 /* length of the set command
79 * string :"add", "del" (+ NUL)
80 */
81#define VNDR_IE_COUNT_OFFSET 4
82#define VNDR_IE_PKTFLAG_OFFSET 8
83#define VNDR_IE_VSIE_OFFSET 12
84#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010085#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020086
87#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
88#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020089
Hante Meuleman89286dc2013-02-08 15:53:46 +010090#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
91#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
92#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
93
Hante Meuleman1678ba82015-12-10 13:43:00 +010094#define BRCMF_SCAN_CHANNEL_TIME 40
95#define BRCMF_SCAN_UNASSOC_TIME 40
96#define BRCMF_SCAN_PASSIVE_TIME 120
97
Hante Meuleman3021ad92016-01-05 11:05:45 +010098#define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000)
99
Arend van Spriel5b435de2011-10-05 13:19:03 +0200100#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
101 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
102
Arend van Sprielce81e312012-10-22 13:55:37 -0700103static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200104{
Arend van Sprielc1179032012-10-22 13:55:33 -0700105 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100106 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
107 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200108 return false;
109 }
110 return true;
111}
112
Arend van Spriel5b435de2011-10-05 13:19:03 +0200113#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
114#define RATETAB_ENT(_rateid, _flags) \
115 { \
116 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
117 .hw_value = (_rateid), \
118 .flags = (_flags), \
119 }
120
121static struct ieee80211_rate __wl_rates[] = {
122 RATETAB_ENT(BRCM_RATE_1M, 0),
123 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
124 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
125 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
126 RATETAB_ENT(BRCM_RATE_6M, 0),
127 RATETAB_ENT(BRCM_RATE_9M, 0),
128 RATETAB_ENT(BRCM_RATE_12M, 0),
129 RATETAB_ENT(BRCM_RATE_18M, 0),
130 RATETAB_ENT(BRCM_RATE_24M, 0),
131 RATETAB_ENT(BRCM_RATE_36M, 0),
132 RATETAB_ENT(BRCM_RATE_48M, 0),
133 RATETAB_ENT(BRCM_RATE_54M, 0),
134};
135
Arend van Spriel5b435de2011-10-05 13:19:03 +0200136#define wl_g_rates (__wl_rates + 0)
Arend van Spriel58de92d2015-04-14 20:10:24 +0200137#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
138#define wl_a_rates (__wl_rates + 4)
139#define wl_a_rates_size (wl_g_rates_size - 4)
140
141#define CHAN2G(_channel, _freq) { \
142 .band = IEEE80211_BAND_2GHZ, \
143 .center_freq = (_freq), \
144 .hw_value = (_channel), \
145 .flags = IEEE80211_CHAN_DISABLED, \
146 .max_antenna_gain = 0, \
147 .max_power = 30, \
148}
149
150#define CHAN5G(_channel) { \
151 .band = IEEE80211_BAND_5GHZ, \
152 .center_freq = 5000 + (5 * (_channel)), \
153 .hw_value = (_channel), \
154 .flags = IEEE80211_CHAN_DISABLED, \
155 .max_antenna_gain = 0, \
156 .max_power = 30, \
157}
158
159static struct ieee80211_channel __wl_2ghz_channels[] = {
160 CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
161 CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
162 CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
163 CHAN2G(13, 2472), CHAN2G(14, 2484)
164};
165
166static struct ieee80211_channel __wl_5ghz_channels[] = {
167 CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
168 CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
169 CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
170 CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
171 CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
172 CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
173};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200174
Arend van Sprielb48d8912014-07-12 08:49:41 +0200175/* Band templates duplicated per wiphy. The channel info
Arend van Spriel58de92d2015-04-14 20:10:24 +0200176 * above is added to the band during setup.
Arend van Sprielb48d8912014-07-12 08:49:41 +0200177 */
178static const struct ieee80211_supported_band __wl_band_2ghz = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200179 .band = IEEE80211_BAND_2GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200180 .bitrates = wl_g_rates,
181 .n_bitrates = wl_g_rates_size,
182};
183
Arend van Spriel58de92d2015-04-14 20:10:24 +0200184static const struct ieee80211_supported_band __wl_band_5ghz = {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200185 .band = IEEE80211_BAND_5GHZ,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200186 .bitrates = wl_a_rates,
187 .n_bitrates = wl_a_rates_size,
188};
189
Hante Meulemand48200b2013-04-03 12:40:29 +0200190/* This is to override regulatory domains defined in cfg80211 module (reg.c)
191 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200192 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
193 * With respect to these flags, wpa_supplicant doesn't * start p2p
194 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200195 * domain are to be done here.
196 */
197static const struct ieee80211_regdomain brcmf_regdom = {
198 .n_reg_rules = 4,
199 .alpha2 = "99",
200 .reg_rules = {
201 /* IEEE 802.11b/g, channels 1..11 */
202 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
203 /* If any */
204 /* IEEE 802.11 channel 14 - Only JP enables
205 * this and for 802.11b only
206 */
207 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
208 /* IEEE 802.11a, channel 36..64 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200209 REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
Hante Meulemand48200b2013-04-03 12:40:29 +0200210 /* IEEE 802.11a, channel 100..165 */
Arend van Sprielc555ecd2014-05-12 10:47:36 +0200211 REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200212};
213
214static const u32 __wl_cipher_suites[] = {
215 WLAN_CIPHER_SUITE_WEP40,
216 WLAN_CIPHER_SUITE_WEP104,
217 WLAN_CIPHER_SUITE_TKIP,
218 WLAN_CIPHER_SUITE_CCMP,
219 WLAN_CIPHER_SUITE_AES_CMAC,
220};
221
Hante Meuleman1a873342012-09-27 14:17:54 +0200222/* Vendor specific ie. id = 221, oui and type defines exact ie */
223struct brcmf_vs_tlv {
224 u8 id;
225 u8 len;
226 u8 oui[3];
227 u8 oui_type;
228};
229
230struct parsed_vndr_ie_info {
231 u8 *ie_ptr;
232 u32 ie_len; /* total length including id & length field */
233 struct brcmf_vs_tlv vndrie;
234};
235
236struct parsed_vndr_ies {
237 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100238 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200239};
240
Arend van Spriel5a394eb2014-05-27 12:56:15 +0200241static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
242 struct cfg80211_chan_def *ch)
Arend van Spriel600a8972014-05-12 10:47:39 +0200243{
244 struct brcmu_chan ch_inf;
245 s32 primary_offset;
246
247 brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
248 ch->chan->center_freq, ch->center_freq1, ch->width);
249 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
Rafał Miłecki36e80722016-01-20 16:46:04 +0100250 primary_offset = ch->chan->center_freq - ch->center_freq1;
Arend van Spriel600a8972014-05-12 10:47:39 +0200251 switch (ch->width) {
252 case NL80211_CHAN_WIDTH_20:
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100253 case NL80211_CHAN_WIDTH_20_NOHT:
Arend van Spriel600a8972014-05-12 10:47:39 +0200254 ch_inf.bw = BRCMU_CHAN_BW_20;
255 WARN_ON(primary_offset != 0);
256 break;
257 case NL80211_CHAN_WIDTH_40:
258 ch_inf.bw = BRCMU_CHAN_BW_40;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100259 if (primary_offset > 0)
Arend van Spriel600a8972014-05-12 10:47:39 +0200260 ch_inf.sb = BRCMU_CHAN_SB_U;
261 else
262 ch_inf.sb = BRCMU_CHAN_SB_L;
263 break;
264 case NL80211_CHAN_WIDTH_80:
265 ch_inf.bw = BRCMU_CHAN_BW_80;
Rafał Miłecki36e80722016-01-20 16:46:04 +0100266 if (primary_offset == -30)
267 ch_inf.sb = BRCMU_CHAN_SB_LL;
268 else if (primary_offset == -10)
269 ch_inf.sb = BRCMU_CHAN_SB_LU;
270 else if (primary_offset == 10)
271 ch_inf.sb = BRCMU_CHAN_SB_UL;
272 else
273 ch_inf.sb = BRCMU_CHAN_SB_UU;
Arend van Spriel600a8972014-05-12 10:47:39 +0200274 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100275 case NL80211_CHAN_WIDTH_80P80:
276 case NL80211_CHAN_WIDTH_160:
277 case NL80211_CHAN_WIDTH_5:
278 case NL80211_CHAN_WIDTH_10:
Arend van Spriel600a8972014-05-12 10:47:39 +0200279 default:
280 WARN_ON_ONCE(1);
281 }
282 switch (ch->chan->band) {
283 case IEEE80211_BAND_2GHZ:
284 ch_inf.band = BRCMU_CHAN_BAND_2G;
285 break;
286 case IEEE80211_BAND_5GHZ:
287 ch_inf.band = BRCMU_CHAN_BAND_5G;
288 break;
Arend van Spriel0cd75b12014-11-11 13:58:44 +0100289 case IEEE80211_BAND_60GHZ:
Arend van Spriel600a8972014-05-12 10:47:39 +0200290 default:
291 WARN_ON_ONCE(1);
292 }
293 d11inf->encchspec(&ch_inf);
294
295 return ch_inf.chspec;
296}
297
Franky Lin83cf17a2013-04-11 13:28:50 +0200298u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
299 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700300{
Franky Lin83cf17a2013-04-11 13:28:50 +0200301 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700302
Franky Lin83cf17a2013-04-11 13:28:50 +0200303 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
304 ch_inf.bw = BRCMU_CHAN_BW_20;
305 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700306
Franky Lin83cf17a2013-04-11 13:28:50 +0200307 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700308}
309
Hante Meuleman89286dc2013-02-08 15:53:46 +0100310/* Traverse a string of 1-byte tag/1-byte length/variable-length value
311 * triples, returning a pointer to the substring whose first element
312 * matches tag
313 */
Johannes Berg4b5800f2014-01-15 14:55:59 +0100314const struct brcmf_tlv *
315brcmf_parse_tlvs(const void *buf, int buflen, uint key)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100316{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100317 const struct brcmf_tlv *elt = buf;
318 int totlen = buflen;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100319
320 /* find tagged parameter */
321 while (totlen >= TLV_HDR_LEN) {
322 int len = elt->len;
323
324 /* validate remaining totlen */
325 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
326 return elt;
327
328 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
329 totlen -= (len + TLV_HDR_LEN);
330 }
331
332 return NULL;
333}
334
335/* Is any of the tlvs the expected entry? If
336 * not update the tlvs buffer pointer/length.
337 */
338static bool
Johannes Berg4b5800f2014-01-15 14:55:59 +0100339brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
340 const u8 *oui, u32 oui_len, u8 type)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100341{
342 /* If the contents match the OUI and the type */
343 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
344 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
345 type == ie[TLV_BODY_OFF + oui_len]) {
346 return true;
347 }
348
349 if (tlvs == NULL)
350 return false;
351 /* point to the next ie */
352 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
353 /* calculate the length of the rest of the buffer */
354 *tlvs_len -= (int)(ie - *tlvs);
355 /* update the pointer to the start of the buffer */
356 *tlvs = ie;
357
358 return false;
359}
360
361static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100362brcmf_find_wpaie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100363{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100364 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100365
366 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Johannes Berg4b5800f2014-01-15 14:55:59 +0100367 if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
Hante Meuleman89286dc2013-02-08 15:53:46 +0100368 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
369 return (struct brcmf_vs_tlv *)ie;
370 }
371 return NULL;
372}
373
374static struct brcmf_vs_tlv *
Johannes Berg4b5800f2014-01-15 14:55:59 +0100375brcmf_find_wpsie(const u8 *parse, u32 len)
Hante Meuleman89286dc2013-02-08 15:53:46 +0100376{
Johannes Berg4b5800f2014-01-15 14:55:59 +0100377 const struct brcmf_tlv *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +0100378
379 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
380 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
381 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
382 return (struct brcmf_vs_tlv *)ie;
383 }
384 return NULL;
385}
386
Arend van Spriel39504a22015-08-20 22:06:05 +0200387static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
388 struct brcmf_cfg80211_vif *vif,
389 enum nl80211_iftype new_type)
390{
391 int iftype_num[NUM_NL80211_IFTYPES];
392 struct brcmf_cfg80211_vif *pos;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100393 bool check_combos = false;
394 int ret = 0;
Arend van Spriel39504a22015-08-20 22:06:05 +0200395
396 memset(&iftype_num[0], 0, sizeof(iftype_num));
397 list_for_each_entry(pos, &cfg->vif_list, list)
Arend van Spriel353c46a2015-12-10 13:43:06 +0100398 if (pos == vif) {
Arend van Spriel39504a22015-08-20 22:06:05 +0200399 iftype_num[new_type]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100400 } else {
401 /* concurrent interfaces so need check combinations */
402 check_combos = true;
Arend van Spriel39504a22015-08-20 22:06:05 +0200403 iftype_num[pos->wdev.iftype]++;
Arend van Spriel353c46a2015-12-10 13:43:06 +0100404 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200405
Arend van Spriel353c46a2015-12-10 13:43:06 +0100406 if (check_combos)
407 ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
408
409 return ret;
Arend van Spriel39504a22015-08-20 22:06:05 +0200410}
411
412static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
413 enum nl80211_iftype new_type)
414{
415 int iftype_num[NUM_NL80211_IFTYPES];
416 struct brcmf_cfg80211_vif *pos;
417
418 memset(&iftype_num[0], 0, sizeof(iftype_num));
419 list_for_each_entry(pos, &cfg->vif_list, list)
420 iftype_num[pos->wdev.iftype]++;
421
422 iftype_num[new_type]++;
423 return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
424}
Hante Meuleman89286dc2013-02-08 15:53:46 +0100425
Arend van Spriel5b435de2011-10-05 13:19:03 +0200426static void convert_key_from_CPU(struct brcmf_wsec_key *key,
427 struct brcmf_wsec_key_le *key_le)
428{
429 key_le->index = cpu_to_le32(key->index);
430 key_le->len = cpu_to_le32(key->len);
431 key_le->algo = cpu_to_le32(key->algo);
432 key_le->flags = cpu_to_le32(key->flags);
433 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
434 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
435 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
436 memcpy(key_le->data, key->data, sizeof(key->data));
437 memcpy(key_le->ea, key->ea, sizeof(key->ea));
438}
439
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200440static int
Hante Meuleman118eb302014-12-21 12:43:49 +0100441send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200442{
443 int err;
444 struct brcmf_wsec_key_le key_le;
445
446 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200447
Hante Meuleman118eb302014-12-21 12:43:49 +0100448 brcmf_netdev_wait_pend8021x(ifp);
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700449
Hante Meuleman118eb302014-12-21 12:43:49 +0100450 err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700451 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200452
Arend van Spriel5b435de2011-10-05 13:19:03 +0200453 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100454 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200455 return err;
456}
457
Hante Meulemanb3657452013-05-27 21:09:53 +0200458static s32
Franky Lin52f22fb2016-02-17 11:26:55 +0100459brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
Hante Meulemanb3657452013-05-27 21:09:53 +0200460{
461 s32 err;
462 u32 mode;
463
464 if (enable)
465 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
466 else
467 mode = 0;
468
469 /* Try to set and enable ARP offload feature, this may fail, then it */
470 /* is simply not supported and err 0 will be returned */
471 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
472 if (err) {
473 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
474 mode, err);
475 err = 0;
476 } else {
477 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
478 if (err) {
479 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
480 enable, err);
481 err = 0;
482 } else
483 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
484 enable, mode);
485 }
486
Franky Lin52f22fb2016-02-17 11:26:55 +0100487 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
488 if (err) {
489 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
490 enable, err);
491 err = 0;
492 } else
493 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
494 enable, mode);
495
Hante Meulemanb3657452013-05-27 21:09:53 +0200496 return err;
497}
498
Hante Meuleman8851cce2014-07-30 13:20:02 +0200499static void
500brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
501{
Arend van Spriel8f2b4592014-09-11 22:51:32 +0200502 struct brcmf_cfg80211_vif *vif;
503 struct brcmf_if *ifp;
504
505 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
506 ifp = vif->ifp;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200507
508 if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
509 (wdev->iftype == NL80211_IFTYPE_AP) ||
510 (wdev->iftype == NL80211_IFTYPE_P2P_GO))
511 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
512 ADDR_DIRECT);
513 else
514 brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
515 ADDR_INDIRECT);
516}
517
Hante Meulemana44aa402014-12-03 21:05:33 +0100518static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
519{
520 struct brcmf_mbss_ssid_le mbss_ssid_le;
521 int bsscfgidx;
522 int err;
523
524 memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le));
525 bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr);
526 if (bsscfgidx < 0)
527 return bsscfgidx;
528
529 mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx);
530 mbss_ssid_le.SSID_len = cpu_to_le32(5);
531 sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx);
532
533 err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le,
534 sizeof(mbss_ssid_le));
535 if (err < 0)
536 brcmf_err("setting ssid failed %d\n", err);
537
538 return err;
539}
540
541/**
542 * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS
543 *
544 * @wiphy: wiphy device of new interface.
545 * @name: name of the new interface.
546 * @flags: not used.
547 * @params: contains mac address for AP device.
548 */
549static
550struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
551 u32 *flags, struct vif_params *params)
552{
553 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
554 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
555 struct brcmf_cfg80211_vif *vif;
556 int err;
557
558 if (brcmf_cfg80211_vif_event_armed(cfg))
559 return ERR_PTR(-EBUSY);
560
561 brcmf_dbg(INFO, "Adding vif \"%s\"\n", name);
562
563 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false);
564 if (IS_ERR(vif))
565 return (struct wireless_dev *)vif;
566
567 brcmf_cfg80211_arm_vif_event(cfg, vif);
568
569 err = brcmf_cfg80211_request_ap_if(ifp);
570 if (err) {
571 brcmf_cfg80211_arm_vif_event(cfg, NULL);
572 goto fail;
573 }
574
575 /* wait for firmware event */
Arend van Spriela9eb0c42016-02-17 11:26:50 +0100576 err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
577 BRCMF_VIF_EVENT_TIMEOUT);
Hante Meulemana44aa402014-12-03 21:05:33 +0100578 brcmf_cfg80211_arm_vif_event(cfg, NULL);
579 if (!err) {
580 brcmf_err("timeout occurred\n");
581 err = -EIO;
582 goto fail;
583 }
584
585 /* interface created in firmware */
586 ifp = vif->ifp;
587 if (!ifp) {
588 brcmf_err("no if pointer provided\n");
589 err = -ENOENT;
590 goto fail;
591 }
592
593 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
594 err = brcmf_net_attach(ifp, true);
595 if (err) {
596 brcmf_err("Registering netdevice failed\n");
597 goto fail;
598 }
599
600 return &ifp->vif->wdev;
601
602fail:
603 brcmf_free_vif(vif);
604 return ERR_PTR(err);
605}
606
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100607static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
608{
609 enum nl80211_iftype iftype;
610
611 iftype = vif->wdev.iftype;
612 return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
613}
614
615static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
616{
617 return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
618}
619
Arend van Spriel9f440b72013-02-08 15:53:36 +0100620static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
621 const char *name,
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100622 unsigned char name_assign_type,
Arend van Spriel9f440b72013-02-08 15:53:36 +0100623 enum nl80211_iftype type,
624 u32 *flags,
625 struct vif_params *params)
626{
Hante Meuleman8851cce2014-07-30 13:20:02 +0200627 struct wireless_dev *wdev;
Arend van Spriel39504a22015-08-20 22:06:05 +0200628 int err;
Hante Meuleman8851cce2014-07-30 13:20:02 +0200629
Arend van Spriel9f440b72013-02-08 15:53:36 +0100630 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
Arend van Spriel39504a22015-08-20 22:06:05 +0200631 err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
632 if (err) {
633 brcmf_err("iface validation failed: err=%d\n", err);
634 return ERR_PTR(err);
635 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100636 switch (type) {
637 case NL80211_IFTYPE_ADHOC:
638 case NL80211_IFTYPE_STATION:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100639 case NL80211_IFTYPE_AP_VLAN:
640 case NL80211_IFTYPE_WDS:
641 case NL80211_IFTYPE_MONITOR:
642 case NL80211_IFTYPE_MESH_POINT:
643 return ERR_PTR(-EOPNOTSUPP);
Hante Meulemana44aa402014-12-03 21:05:33 +0100644 case NL80211_IFTYPE_AP:
645 wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
646 if (!IS_ERR(wdev))
647 brcmf_cfg80211_update_proto_addr_mode(wdev);
648 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100649 case NL80211_IFTYPE_P2P_CLIENT:
650 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200651 case NL80211_IFTYPE_P2P_DEVICE:
Tom Gundersen6bab2e192015-03-18 11:13:39 +0100652 wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
Hante Meuleman8851cce2014-07-30 13:20:02 +0200653 if (!IS_ERR(wdev))
654 brcmf_cfg80211_update_proto_addr_mode(wdev);
655 return wdev;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100656 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100657 default:
658 return ERR_PTR(-EINVAL);
659 }
660}
661
Daniel Kim5e787f72014-06-21 12:11:18 +0200662static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
663{
Arend van Sprielc08437b2014-07-12 08:49:39 +0200664 if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
Daniel Kim5e787f72014-06-21 12:11:18 +0200665 brcmf_set_mpc(ifp, mpc);
666}
667
Arend van Sprielf96aa072013-04-05 10:57:48 +0200668void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100669{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100670 s32 err = 0;
671
672 if (check_vif_up(ifp->vif)) {
673 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
674 if (err) {
675 brcmf_err("fail to set mpc\n");
676 return;
677 }
678 brcmf_dbg(INFO, "MPC : %d\n", mpc);
679 }
680}
681
Arend van Spriela0f472a2013-04-05 10:57:49 +0200682s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
683 struct brcmf_if *ifp, bool aborted,
684 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100685{
686 struct brcmf_scan_params_le params_le;
687 struct cfg80211_scan_request *scan_request;
688 s32 err = 0;
689
690 brcmf_dbg(SCAN, "Enter\n");
691
692 /* clear scan request, because the FW abort can cause a second call */
693 /* to this functon and might cause a double cfg80211_scan_done */
694 scan_request = cfg->scan_request;
695 cfg->scan_request = NULL;
696
697 if (timer_pending(&cfg->escan_timeout))
698 del_timer_sync(&cfg->escan_timeout);
699
700 if (fw_abort) {
701 /* Do a scan abort to stop the driver's scan engine */
702 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
703 memset(&params_le, 0, sizeof(params_le));
Joe Perches93803b32015-03-02 19:54:49 -0800704 eth_broadcast_addr(params_le.bssid);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100705 params_le.bss_type = DOT11_BSSTYPE_ANY;
706 params_le.scan_type = 0;
707 params_le.channel_num = cpu_to_le32(1);
708 params_le.nprobes = cpu_to_le32(1);
709 params_le.active_time = cpu_to_le32(-1);
710 params_le.passive_time = cpu_to_le32(-1);
711 params_le.home_time = cpu_to_le32(-1);
712 /* Scan is aborted by setting channel_list[0] to -1 */
713 params_le.channel_list[0] = cpu_to_le16(-1);
714 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200715 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100716 &params_le, sizeof(params_le));
717 if (err)
718 brcmf_err("Scan abort failed\n");
719 }
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200720
Daniel Kim5e787f72014-06-21 12:11:18 +0200721 brcmf_scan_config_mpc(ifp, 1);
Arend van Spriel0f0fe992014-05-27 12:56:14 +0200722
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100723 /*
724 * e-scan can be initiated by scheduled scan
725 * which takes precedence.
726 */
727 if (cfg->sched_escan) {
728 brcmf_dbg(SCAN, "scheduled scan completed\n");
729 cfg->sched_escan = false;
730 if (!aborted)
731 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100732 } else if (scan_request) {
733 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
734 aborted ? "Aborted" : "Done");
735 cfg80211_scan_done(scan_request, aborted);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100736 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100737 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
738 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100739
740 return err;
741}
742
Arend van Spriel9f440b72013-02-08 15:53:36 +0100743static
744int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
745{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100746 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
747 struct net_device *ndev = wdev->netdev;
748
749 /* vif event pending in firmware */
750 if (brcmf_cfg80211_vif_event_armed(cfg))
751 return -EBUSY;
752
753 if (ndev) {
754 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200755 cfg->escan_info.ifp == netdev_priv(ndev))
756 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
757 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100758
759 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
760 }
761
Arend van Spriel9f440b72013-02-08 15:53:36 +0100762 switch (wdev->iftype) {
763 case NL80211_IFTYPE_ADHOC:
764 case NL80211_IFTYPE_STATION:
765 case NL80211_IFTYPE_AP:
766 case NL80211_IFTYPE_AP_VLAN:
767 case NL80211_IFTYPE_WDS:
768 case NL80211_IFTYPE_MONITOR:
769 case NL80211_IFTYPE_MESH_POINT:
770 return -EOPNOTSUPP;
771 case NL80211_IFTYPE_P2P_CLIENT:
772 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200773 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100774 return brcmf_p2p_del_vif(wiphy, wdev);
775 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100776 default:
777 return -EINVAL;
778 }
779 return -EOPNOTSUPP;
780}
781
Arend van Spriel5b435de2011-10-05 13:19:03 +0200782static s32
783brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
784 enum nl80211_iftype type, u32 *flags,
785 struct vif_params *params)
786{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100787 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700788 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100789 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200790 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200791 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200792 s32 err = 0;
793
Hante Meuleman37a869e2015-10-29 20:33:17 +0100794 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, type=%d\n", ifp->bsscfgidx,
795 type);
Hante Meuleman178e9ef2015-09-18 22:08:11 +0200796
797 /* WAR: There are a number of p2p interface related problems which
798 * need to be handled initially (before doing the validate).
799 * wpa_supplicant tends to do iface changes on p2p device/client/go
800 * which are not always possible/allowed. However we need to return
801 * OK otherwise the wpa_supplicant wont start. The situation differs
802 * on configuration and setup (p2pon=1 module param). The first check
803 * is to see if the request is a change to station for p2p iface.
804 */
805 if ((type == NL80211_IFTYPE_STATION) &&
806 ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
807 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
808 (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
809 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
810 /* Now depending on whether module param p2pon=1 was used the
811 * response needs to be either 0 or EOPNOTSUPP. The reason is
812 * that if p2pon=1 is used, but a newer supplicant is used then
813 * we should return an error, as this combination wont work.
814 * In other situations 0 is returned and supplicant will start
815 * normally. It will give a trace in cfg80211, but it is the
816 * only way to get it working. Unfortunately this will result
817 * in situation where we wont support new supplicant in
818 * combination with module param p2pon=1, but that is the way
819 * it is. If the user tries this then unloading of driver might
820 * fail/lock.
821 */
822 if (cfg->p2p.p2pdev_dynamically)
823 return -EOPNOTSUPP;
824 else
825 return 0;
826 }
Arend van Spriel39504a22015-08-20 22:06:05 +0200827 err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
828 if (err) {
829 brcmf_err("iface validation failed: err=%d\n", err);
830 return err;
831 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200832 switch (type) {
833 case NL80211_IFTYPE_MONITOR:
834 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100835 brcmf_err("type (%d) : currently we do not support this type\n",
836 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200837 return -EOPNOTSUPP;
838 case NL80211_IFTYPE_ADHOC:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200839 infra = 0;
840 break;
841 case NL80211_IFTYPE_STATION:
Arend van Spriel5b435de2011-10-05 13:19:03 +0200842 infra = 1;
843 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200844 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100845 case NL80211_IFTYPE_P2P_GO:
Hante Meuleman1a873342012-09-27 14:17:54 +0200846 ap = 1;
847 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200848 default:
849 err = -EINVAL;
850 goto done;
851 }
852
Hante Meuleman1a873342012-09-27 14:17:54 +0200853 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100854 if (type == NL80211_IFTYPE_P2P_GO) {
855 brcmf_dbg(INFO, "IF Type = P2P GO\n");
856 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
857 }
858 if (!err) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100859 brcmf_dbg(INFO, "IF Type = AP\n");
860 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200861 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100862 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200863 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100864 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200865 err = -EAGAIN;
866 goto done;
867 }
Arend van Spriel967fe2c2014-03-15 17:18:21 +0100868 brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100869 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200870 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200871 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200872
Hante Meuleman8851cce2014-07-30 13:20:02 +0200873 brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
874
Arend van Spriel5b435de2011-10-05 13:19:03 +0200875done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100876 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200877
878 return err;
879}
880
Franky Lin83cf17a2013-04-11 13:28:50 +0200881static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
882 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200883 struct cfg80211_scan_request *request)
884{
885 u32 n_ssids;
886 u32 n_channels;
887 s32 i;
888 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200889 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200890 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200891 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200892
Joe Perches93803b32015-03-02 19:54:49 -0800893 eth_broadcast_addr(params_le->bssid);
Hante Meulemane756af52012-09-11 21:18:52 +0200894 params_le->bss_type = DOT11_BSSTYPE_ANY;
895 params_le->scan_type = 0;
896 params_le->channel_num = 0;
897 params_le->nprobes = cpu_to_le32(-1);
898 params_le->active_time = cpu_to_le32(-1);
899 params_le->passive_time = cpu_to_le32(-1);
900 params_le->home_time = cpu_to_le32(-1);
901 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
902
903 /* if request is null exit so it will be all channel broadcast scan */
904 if (!request)
905 return;
906
907 n_ssids = request->n_ssids;
908 n_channels = request->n_channels;
909 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100910 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
911 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200912 if (n_channels > 0) {
913 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200914 chanspec = channel_to_chanspec(&cfg->d11inf,
915 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100916 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
917 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200918 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200919 }
920 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100921 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200922 }
923 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100924 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200925 if (n_ssids > 0) {
926 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
927 n_channels * sizeof(u16);
928 offset = roundup(offset, sizeof(u32));
929 ptr = (char *)params_le + offset;
930 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200931 memset(&ssid_le, 0, sizeof(ssid_le));
932 ssid_le.SSID_len =
933 cpu_to_le32(request->ssids[i].ssid_len);
934 memcpy(ssid_le.SSID, request->ssids[i].ssid,
935 request->ssids[i].ssid_len);
936 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100937 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200938 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100939 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
940 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200941 memcpy(ptr, &ssid_le, sizeof(ssid_le));
942 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200943 }
944 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100945 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200946 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100947 brcmf_dbg(SCAN, "SSID %s len=%d\n",
948 params_le->ssid_le.SSID,
949 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200950 params_le->ssid_le.SSID_len =
951 cpu_to_le32(request->ssids->ssid_len);
952 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
953 request->ssids->ssid_len);
954 }
955 }
956 /* Adding mask to channel numbers */
957 params_le->channel_num =
958 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
959 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
960}
961
962static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200963brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemanc4958102015-11-25 11:32:41 +0100964 struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200965{
966 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
967 offsetof(struct brcmf_escan_params_le, params_le);
968 struct brcmf_escan_params_le *params;
969 s32 err = 0;
970
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100971 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200972
973 if (request != NULL) {
974 /* Allocate space for populating ssids in struct */
975 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
976
977 /* Allocate space for populating ssids in struct */
Hante Meulemane9a6ca82015-11-25 11:32:37 +0100978 params_size += sizeof(struct brcmf_ssid_le) * request->n_ssids;
Hante Meulemane756af52012-09-11 21:18:52 +0200979 }
980
981 params = kzalloc(params_size, GFP_KERNEL);
982 if (!params) {
983 err = -ENOMEM;
984 goto exit;
985 }
986 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +0200987 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200988 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
Hante Meulemanc4958102015-11-25 11:32:41 +0100989 params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200990 params->sync_id = cpu_to_le16(0x1234);
991
Arend van Spriela0f472a2013-04-05 10:57:49 +0200992 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200993 if (err) {
994 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100995 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200996 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100997 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200998 }
999
1000 kfree(params);
1001exit:
1002 return err;
1003}
1004
1005static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001006brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +02001007 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +02001008{
1009 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001010 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001011 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001012 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +02001013
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001014 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001015 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +01001016 escan->wiphy = wiphy;
1017 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001018 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +02001019 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001020 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001021 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001022 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001023 return err;
1024 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001025 brcmf_scan_config_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001026 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02001027 results->version = 0;
1028 results->count = 0;
1029 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
1030
Hante Meulemanc4958102015-11-25 11:32:41 +01001031 err = escan->run(cfg, ifp, request);
Hante Meulemane756af52012-09-11 21:18:52 +02001032 if (err)
Daniel Kim5e787f72014-06-21 12:11:18 +02001033 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001034 return err;
1035}
1036
1037static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +02001038brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +02001039 struct cfg80211_scan_request *request,
1040 struct cfg80211_ssid *this_ssid)
1041{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001042 struct brcmf_if *ifp = vif->ifp;
1043 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +02001044 struct cfg80211_ssid *ssids;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001045 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +02001046 bool escan_req;
1047 bool spec_scan;
1048 s32 err;
Hante Meuleman675f5d82015-12-10 13:43:01 +01001049 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +02001050 u32 SSID_len;
1051
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001052 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001053
Arend van Sprielc1179032012-10-22 13:55:33 -07001054 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001055 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001056 return -EAGAIN;
1057 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001058 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001059 brcmf_err("Scanning being aborted: status (%lu)\n",
1060 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001061 return -EAGAIN;
1062 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02001063 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
1064 brcmf_err("Scanning suppressed: status (%lu)\n",
1065 cfg->scan_status);
1066 return -EAGAIN;
1067 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001068 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001069 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +02001070 return -EAGAIN;
1071 }
1072
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001073 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +02001074 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
1075 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +01001076
Hante Meulemane756af52012-09-11 21:18:52 +02001077 escan_req = false;
1078 if (request) {
1079 /* scan bss */
1080 ssids = request->ssids;
1081 escan_req = true;
1082 } else {
1083 /* scan in ibss */
1084 /* we don't do escan in ibss */
1085 ssids = this_ssid;
1086 }
1087
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001088 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -07001089 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +02001090 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01001091 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +02001092 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +01001093 if (err)
1094 goto scan_out;
1095
Arend van Spriela0f472a2013-04-05 10:57:49 +02001096 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -08001097 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +02001098 goto scan_out;
1099 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001100 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
1101 ssids->ssid, ssids->ssid_len);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001102 memset(&ssid_le, 0, sizeof(ssid_le));
1103 SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
1104 ssid_le.SSID_len = cpu_to_le32(0);
Hante Meulemane756af52012-09-11 21:18:52 +02001105 spec_scan = false;
1106 if (SSID_len) {
Hante Meuleman675f5d82015-12-10 13:43:01 +01001107 memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
1108 ssid_le.SSID_len = cpu_to_le32(SSID_len);
Hante Meulemane756af52012-09-11 21:18:52 +02001109 spec_scan = true;
1110 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +01001111 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +02001112
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001113 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -07001114 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001115 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +02001116 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001117 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001118 goto scan_out;
1119 }
Daniel Kim5e787f72014-06-21 12:11:18 +02001120 brcmf_scan_config_mpc(ifp, 0);
Hante Meuleman675f5d82015-12-10 13:43:01 +01001121 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
1122 sizeof(ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001123 if (err) {
1124 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001125 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
Hante Meuleman675f5d82015-12-10 13:43:01 +01001126 ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +02001127 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01001128 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +02001129
Daniel Kim5e787f72014-06-21 12:11:18 +02001130 brcmf_scan_config_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +02001131 goto scan_out;
1132 }
1133 }
1134
Hante Meuleman661fa952015-02-06 18:36:47 +01001135 /* Arm scan timeout timer */
1136 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemand5367332016-02-17 11:26:51 +01001137 BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
Hante Meuleman661fa952015-02-06 18:36:47 +01001138
Hante Meulemane756af52012-09-11 21:18:52 +02001139 return 0;
1140
1141scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001142 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001143 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001144 return err;
1145}
1146
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001148brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149{
Arend van Spriela0f472a2013-04-05 10:57:49 +02001150 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001151 s32 err = 0;
1152
Arend van Sprield96b8012012-12-05 15:26:02 +01001153 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +02001154 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
1155 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001156 return -EIO;
1157
Arend van Spriela0f472a2013-04-05 10:57:49 +02001158 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001159
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001161 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001162
Arend van Sprield96b8012012-12-05 15:26:02 +01001163 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001164 return err;
1165}
1166
1167static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1168{
1169 s32 err = 0;
1170
Arend van Sprielac24be62012-10-22 10:36:23 -07001171 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1172 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001173 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001174 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001175
1176 return err;
1177}
1178
1179static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1180{
1181 s32 err = 0;
1182
Arend van Sprielac24be62012-10-22 10:36:23 -07001183 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1184 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001185 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001186 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001187
1188 return err;
1189}
1190
1191static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1192{
1193 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001194 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001195
Arend van Sprielac24be62012-10-22 10:36:23 -07001196 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001197 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001198 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 return err;
1200 }
1201 return err;
1202}
1203
1204static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1205{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001206 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1207 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001208 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209 s32 err = 0;
1210
Arend van Sprield96b8012012-12-05 15:26:02 +01001211 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001212 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001213 return -EIO;
1214
1215 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001216 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1217 cfg->conf->rts_threshold = wiphy->rts_threshold;
1218 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001219 if (!err)
1220 goto done;
1221 }
1222 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001223 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1224 cfg->conf->frag_threshold = wiphy->frag_threshold;
1225 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226 if (!err)
1227 goto done;
1228 }
1229 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001230 && (cfg->conf->retry_long != wiphy->retry_long)) {
1231 cfg->conf->retry_long = wiphy->retry_long;
1232 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001233 if (!err)
1234 goto done;
1235 }
1236 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001237 && (cfg->conf->retry_short != wiphy->retry_short)) {
1238 cfg->conf->retry_short = wiphy->retry_short;
1239 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001240 if (!err)
1241 goto done;
1242 }
1243
1244done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001245 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001246 return err;
1247}
1248
Arend van Spriel5b435de2011-10-05 13:19:03 +02001249static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1250{
1251 memset(prof, 0, sizeof(*prof));
1252}
1253
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001254static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
1255{
1256 u16 reason;
1257
1258 switch (e->event_code) {
1259 case BRCMF_E_DEAUTH:
1260 case BRCMF_E_DEAUTH_IND:
1261 case BRCMF_E_DISASSOC_IND:
1262 reason = e->reason;
1263 break;
1264 case BRCMF_E_LINK:
1265 default:
1266 reason = 0;
1267 break;
1268 }
1269 return reason;
1270}
1271
1272static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001273{
Piotr Haber61730d42013-04-23 12:53:12 +02001274 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 s32 err = 0;
1276
Arend van Sprield96b8012012-12-05 15:26:02 +01001277 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001278
Hante Meulemanb0a79082015-12-10 13:43:07 +01001279 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001280 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001281 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001282 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001283 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001284 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001285 }
Hante Meulemanb0a79082015-12-10 13:43:07 +01001286 if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
1287 (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
1288 cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
1289 true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001290 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001291 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001292 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1293 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001294 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295}
1296
1297static s32
1298brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1299 struct cfg80211_ibss_params *params)
1300{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001301 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001302 struct brcmf_if *ifp = netdev_priv(ndev);
1303 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001304 struct brcmf_join_params join_params;
1305 size_t join_params_size = 0;
1306 s32 err = 0;
1307 s32 wsec = 0;
1308 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001309 u16 chanspec;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001310 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001311
Arend van Sprield96b8012012-12-05 15:26:02 +01001312 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001313 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001314 return -EIO;
1315
1316 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001317 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001319 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001320 return -EOPNOTSUPP;
1321 }
1322
Arend van Sprielc1179032012-10-22 13:55:33 -07001323 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001324
1325 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001326 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001327 else
Arend van Spriel16886732012-12-05 15:26:04 +01001328 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329
Johannes Berg683b6d32012-11-08 21:25:48 +01001330 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001331 brcmf_dbg(CONN, "channel: %d\n",
1332 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001333 else
Arend van Spriel16886732012-12-05 15:26:04 +01001334 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001335
1336 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001337 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001338 else
Arend van Spriel16886732012-12-05 15:26:04 +01001339 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001340
1341 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001342 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001343 else
Arend van Spriel16886732012-12-05 15:26:04 +01001344 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001345
1346 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001347 brcmf_dbg(CONN, "beacon interval: %d\n",
1348 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001349 else
Arend van Spriel16886732012-12-05 15:26:04 +01001350 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001351
1352 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001353 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001354 else
Arend van Spriel16886732012-12-05 15:26:04 +01001355 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001356
1357 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001358 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001359 else
Arend van Spriel16886732012-12-05 15:26:04 +01001360 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001361
1362 /* Configure Privacy for starter */
1363 if (params->privacy)
1364 wsec |= WEP_ENABLED;
1365
Arend van Sprielc1179032012-10-22 13:55:33 -07001366 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001367 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001368 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001369 goto done;
1370 }
1371
1372 /* Configure Beacon Interval for starter */
1373 if (params->beacon_interval)
1374 bcnprd = params->beacon_interval;
1375 else
1376 bcnprd = 100;
1377
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001378 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001379 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001380 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001381 goto done;
1382 }
1383
1384 /* Configure required join parameter */
1385 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1386
1387 /* SSID */
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001388 ssid_len = min_t(u32, params->ssid_len, IEEE80211_MAX_SSID_LEN);
1389 memcpy(join_params.ssid_le.SSID, params->ssid, ssid_len);
1390 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001391 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001392
1393 /* BSSID */
1394 if (params->bssid) {
1395 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001396 join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001397 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001398 } else {
Joe Perches93803b32015-03-02 19:54:49 -08001399 eth_broadcast_addr(join_params.params_le.bssid);
1400 eth_zero_addr(profile->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001401 }
1402
Arend van Spriel5b435de2011-10-05 13:19:03 +02001403 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001404 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001405 u32 target_channel;
1406
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001407 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001409 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410 if (params->channel_fixed) {
1411 /* adding chanspec */
Arend van Spriel600a8972014-05-12 10:47:39 +02001412 chanspec = chandef_to_chanspec(&cfg->d11inf,
1413 &params->chandef);
Hante Meuleman17012612013-02-06 18:40:44 +01001414 join_params.params_le.chanspec_list[0] =
1415 cpu_to_le16(chanspec);
1416 join_params.params_le.chanspec_num = cpu_to_le32(1);
1417 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418 }
1419
1420 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001421 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001422 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001423 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001425 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001426 goto done;
1427 }
1428 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001429 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001431 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001432
1433
Arend van Sprielc1179032012-10-22 13:55:33 -07001434 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001435 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001437 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001438 goto done;
1439 }
1440
1441done:
1442 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001443 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001444 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001445 return err;
1446}
1447
1448static s32
1449brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1450{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001451 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452
Arend van Sprield96b8012012-12-05 15:26:02 +01001453 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman6a98d642016-01-02 09:41:40 +01001454 if (!check_vif_up(ifp->vif)) {
1455 /* When driver is being unloaded, it can end up here. If an
1456 * error is returned then later on a debug trace in the wireless
1457 * core module will be printed. To avoid this 0 is returned.
1458 */
1459 return 0;
1460 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001461
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01001462 brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01001463 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001464
Arend van Sprield96b8012012-12-05 15:26:02 +01001465 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03001467 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001468}
1469
1470static s32 brcmf_set_wpa_version(struct net_device *ndev,
1471 struct cfg80211_connect_params *sme)
1472{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001473 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474 struct brcmf_cfg80211_security *sec;
1475 s32 val = 0;
1476 s32 err = 0;
1477
1478 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1479 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1480 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1481 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1482 else
1483 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001484 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001485 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001486 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001487 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001488 return err;
1489 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001490 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001491 sec->wpa_versions = sme->crypto.wpa_versions;
1492 return err;
1493}
1494
1495static s32 brcmf_set_auth_type(struct net_device *ndev,
1496 struct cfg80211_connect_params *sme)
1497{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001498 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001499 struct brcmf_cfg80211_security *sec;
1500 s32 val = 0;
1501 s32 err = 0;
1502
1503 switch (sme->auth_type) {
1504 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1505 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001506 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001507 break;
1508 case NL80211_AUTHTYPE_SHARED_KEY:
1509 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001510 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 break;
1512 case NL80211_AUTHTYPE_AUTOMATIC:
1513 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001514 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001515 break;
1516 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001517 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518 default:
1519 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001520 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001521 break;
1522 }
1523
Hante Meuleman89286dc2013-02-08 15:53:46 +01001524 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001525 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001526 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001527 return err;
1528 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001529 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530 sec->auth_type = sme->auth_type;
1531 return err;
1532}
1533
1534static s32
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001535brcmf_set_wsec_mode(struct net_device *ndev,
1536 struct cfg80211_connect_params *sme, bool mfp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001538 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539 struct brcmf_cfg80211_security *sec;
1540 s32 pval = 0;
1541 s32 gval = 0;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001542 s32 wsec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543 s32 err = 0;
1544
1545 if (sme->crypto.n_ciphers_pairwise) {
1546 switch (sme->crypto.ciphers_pairwise[0]) {
1547 case WLAN_CIPHER_SUITE_WEP40:
1548 case WLAN_CIPHER_SUITE_WEP104:
1549 pval = WEP_ENABLED;
1550 break;
1551 case WLAN_CIPHER_SUITE_TKIP:
1552 pval = TKIP_ENABLED;
1553 break;
1554 case WLAN_CIPHER_SUITE_CCMP:
1555 pval = AES_ENABLED;
1556 break;
1557 case WLAN_CIPHER_SUITE_AES_CMAC:
1558 pval = AES_ENABLED;
1559 break;
1560 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001561 brcmf_err("invalid cipher pairwise (%d)\n",
1562 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001563 return -EINVAL;
1564 }
1565 }
1566 if (sme->crypto.cipher_group) {
1567 switch (sme->crypto.cipher_group) {
1568 case WLAN_CIPHER_SUITE_WEP40:
1569 case WLAN_CIPHER_SUITE_WEP104:
1570 gval = WEP_ENABLED;
1571 break;
1572 case WLAN_CIPHER_SUITE_TKIP:
1573 gval = TKIP_ENABLED;
1574 break;
1575 case WLAN_CIPHER_SUITE_CCMP:
1576 gval = AES_ENABLED;
1577 break;
1578 case WLAN_CIPHER_SUITE_AES_CMAC:
1579 gval = AES_ENABLED;
1580 break;
1581 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001582 brcmf_err("invalid cipher group (%d)\n",
1583 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001584 return -EINVAL;
1585 }
1586 }
1587
Arend van Spriel16886732012-12-05 15:26:04 +01001588 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001589 /* In case of privacy, but no security and WPS then simulate */
1590 /* setting AES. WPS-2.0 allows no security */
1591 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1592 sme->privacy)
1593 pval = AES_ENABLED;
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001594
1595 if (mfp)
1596 wsec = pval | gval | MFP_CAPABLE;
1597 else
1598 wsec = pval | gval;
1599 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001600 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001601 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001602 return err;
1603 }
1604
Arend van Spriel06bb1232012-09-27 14:17:56 +02001605 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001606 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1607 sec->cipher_group = sme->crypto.cipher_group;
1608
1609 return err;
1610}
1611
1612static s32
1613brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1614{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001615 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001616 struct brcmf_cfg80211_security *sec;
1617 s32 val = 0;
1618 s32 err = 0;
1619
1620 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001621 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1622 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001624 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 return err;
1626 }
1627 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1628 switch (sme->crypto.akm_suites[0]) {
1629 case WLAN_AKM_SUITE_8021X:
1630 val = WPA_AUTH_UNSPECIFIED;
1631 break;
1632 case WLAN_AKM_SUITE_PSK:
1633 val = WPA_AUTH_PSK;
1634 break;
1635 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001636 brcmf_err("invalid cipher group (%d)\n",
1637 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001638 return -EINVAL;
1639 }
1640 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1641 switch (sme->crypto.akm_suites[0]) {
1642 case WLAN_AKM_SUITE_8021X:
1643 val = WPA2_AUTH_UNSPECIFIED;
1644 break;
1645 case WLAN_AKM_SUITE_PSK:
1646 val = WPA2_AUTH_PSK;
1647 break;
1648 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001649 brcmf_err("invalid cipher group (%d)\n",
1650 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001651 return -EINVAL;
1652 }
1653 }
1654
Arend van Spriel16886732012-12-05 15:26:04 +01001655 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001656 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1657 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001658 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001659 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001660 return err;
1661 }
1662 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001663 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001664 sec->wpa_auth = sme->crypto.akm_suites[0];
1665
1666 return err;
1667}
1668
1669static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001670brcmf_set_sharedkey(struct net_device *ndev,
1671 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001672{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001673 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001674 struct brcmf_cfg80211_security *sec;
1675 struct brcmf_wsec_key key;
1676 s32 val;
1677 s32 err = 0;
1678
Arend van Spriel16886732012-12-05 15:26:04 +01001679 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001680
Roland Vossena718e2f2011-10-12 20:51:24 +02001681 if (sme->key_len == 0)
1682 return 0;
1683
Arend van Spriel06bb1232012-09-27 14:17:56 +02001684 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001685 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1686 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001687
1688 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1689 return 0;
1690
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001691 if (!(sec->cipher_pairwise &
1692 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1693 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001694
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001695 memset(&key, 0, sizeof(key));
1696 key.len = (u32) sme->key_len;
1697 key.index = (u32) sme->key_idx;
1698 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001699 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001700 return -EINVAL;
1701 }
1702 memcpy(key.data, sme->key, key.len);
1703 key.flags = BRCMF_PRIMARY_KEY;
1704 switch (sec->cipher_pairwise) {
1705 case WLAN_CIPHER_SUITE_WEP40:
1706 key.algo = CRYPTO_ALGO_WEP1;
1707 break;
1708 case WLAN_CIPHER_SUITE_WEP104:
1709 key.algo = CRYPTO_ALGO_WEP128;
1710 break;
1711 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001712 brcmf_err("Invalid algorithm (%d)\n",
1713 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001714 return -EINVAL;
1715 }
1716 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001717 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1718 key.len, key.index, key.algo);
1719 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Hante Meuleman118eb302014-12-21 12:43:49 +01001720 err = send_key_to_dongle(netdev_priv(ndev), &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001721 if (err)
1722 return err;
1723
1724 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001725 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001726 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001727 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001728 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001729 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001730 }
1731 return err;
1732}
1733
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001734static
1735enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1736 enum nl80211_auth_type type)
1737{
Arend van Sprielc08437b2014-07-12 08:49:39 +02001738 if (type == NL80211_AUTHTYPE_AUTOMATIC &&
1739 brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
1740 brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
1741 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001742 }
1743 return type;
1744}
1745
Arend van Spriel5b435de2011-10-05 13:19:03 +02001746static s32
1747brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001748 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001749{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001750 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001751 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001752 struct ieee80211_channel *chan = sme->channel;
1753 struct brcmf_join_params join_params;
1754 size_t join_params_size;
Johannes Berg4b5800f2014-01-15 14:55:59 +01001755 const struct brcmf_tlv *rsn_ie;
1756 const struct brcmf_vs_tlv *wpa_ie;
1757 const void *ie;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001758 u32 ie_len;
1759 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001760 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001761 s32 err = 0;
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001762 u32 ssid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763
Arend van Sprield96b8012012-12-05 15:26:02 +01001764 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001765 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001766 return -EIO;
1767
1768 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001769 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 return -EOPNOTSUPP;
1771 }
1772
Hante Meuleman89286dc2013-02-08 15:53:46 +01001773 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1774 /* A normal (non P2P) connection request setup. */
1775 ie = NULL;
1776 ie_len = 0;
1777 /* find the WPA_IE */
1778 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1779 if (wpa_ie) {
1780 ie = wpa_ie;
1781 ie_len = wpa_ie->len + TLV_HDR_LEN;
1782 } else {
1783 /* find the RSN_IE */
Johannes Berg4b5800f2014-01-15 14:55:59 +01001784 rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
1785 sme->ie_len,
Hante Meuleman89286dc2013-02-08 15:53:46 +01001786 WLAN_EID_RSN);
1787 if (rsn_ie) {
1788 ie = rsn_ie;
1789 ie_len = rsn_ie->len + TLV_HDR_LEN;
1790 }
1791 }
1792 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1793 }
1794
1795 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1796 sme->ie, sme->ie_len);
1797 if (err)
1798 brcmf_err("Set Assoc REQ IE Failed\n");
1799 else
1800 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1801
Arend van Sprielc1179032012-10-22 13:55:33 -07001802 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803
1804 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001805 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001806 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001807 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001808 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1809 cfg->channel, chan->center_freq, chanspec);
1810 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001811 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001812 chanspec = 0;
1813 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001814
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001815 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001816
1817 err = brcmf_set_wpa_version(ndev, sme);
1818 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001819 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001820 goto done;
1821 }
1822
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001823 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824 err = brcmf_set_auth_type(ndev, sme);
1825 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001826 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001827 goto done;
1828 }
1829
Daniel Kim87b7e9e2014-03-25 21:45:09 +01001830 err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001831 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001832 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001833 goto done;
1834 }
1835
1836 err = brcmf_set_key_mgmt(ndev, sme);
1837 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001838 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001839 goto done;
1840 }
1841
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001842 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001843 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001844 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001845 goto done;
1846 }
1847
Hante Meuleman89286dc2013-02-08 15:53:46 +01001848 /* Join with specific BSSID and cached SSID
1849 * If SSID is zero join based on BSSID only
1850 */
1851 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1852 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1853 if (cfg->channel)
1854 join_params_size += sizeof(u16);
1855 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1856 if (ext_join_params == NULL) {
1857 err = -ENOMEM;
1858 goto done;
1859 }
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001860 ssid_len = min_t(u32, sme->ssid_len, IEEE80211_MAX_SSID_LEN);
1861 ext_join_params->ssid_le.SSID_len = cpu_to_le32(ssid_len);
1862 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, ssid_len);
1863 if (ssid_len < IEEE80211_MAX_SSID_LEN)
1864 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n",
1865 ext_join_params->ssid_le.SSID, ssid_len);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001866
Hante Meuleman89286dc2013-02-08 15:53:46 +01001867 /* Set up join scan parameters */
1868 ext_join_params->scan_le.scan_type = -1;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001869 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1870
1871 if (sme->bssid)
1872 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1873 else
Joe Perches93803b32015-03-02 19:54:49 -08001874 eth_broadcast_addr(ext_join_params->assoc_le.bssid);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001875
1876 if (cfg->channel) {
1877 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1878
1879 ext_join_params->assoc_le.chanspec_list[0] =
1880 cpu_to_le16(chanspec);
Hante Meuleman63dd99e2014-03-15 17:18:19 +01001881 /* Increase dwell time to receive probe response or detect
1882 * beacon from target AP at a noisy air only during connect
1883 * command.
1884 */
1885 ext_join_params->scan_le.active_time =
1886 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1887 ext_join_params->scan_le.passive_time =
1888 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1889 /* To sync with presence period of VSDB GO send probe request
1890 * more frequently. Probe request will be stopped when it gets
1891 * probe response from target AP/GO.
1892 */
1893 ext_join_params->scan_le.nprobes =
1894 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1895 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1896 } else {
1897 ext_join_params->scan_le.active_time = cpu_to_le32(-1);
1898 ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
1899 ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001900 }
1901
1902 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1903 join_params_size);
1904 kfree(ext_join_params);
1905 if (!err)
1906 /* This is it. join command worked, we are done */
1907 goto done;
1908
1909 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 memset(&join_params, 0, sizeof(join_params));
1911 join_params_size = sizeof(join_params.ssid_le);
1912
Hante Meulemane9a6ca82015-11-25 11:32:37 +01001913 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid_len);
1914 join_params.ssid_le.SSID_len = cpu_to_le32(ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001915
Hante Meuleman89286dc2013-02-08 15:53:46 +01001916 if (sme->bssid)
1917 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1918 else
Joe Perches93803b32015-03-02 19:54:49 -08001919 eth_broadcast_addr(join_params.params_le.bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001920
Hante Meuleman17012612013-02-06 18:40:44 +01001921 if (cfg->channel) {
1922 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1923 join_params.params_le.chanspec_num = cpu_to_le32(1);
1924 join_params_size += sizeof(join_params.params_le);
1925 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001926 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001927 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001928 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001929 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001930
1931done:
1932 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001933 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001934 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001935 return err;
1936}
1937
1938static s32
1939brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1940 u16 reason_code)
1941{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001942 struct brcmf_if *ifp = netdev_priv(ndev);
1943 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001944 struct brcmf_scb_val_le scbval;
1945 s32 err = 0;
1946
Arend van Sprield96b8012012-12-05 15:26:02 +01001947 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001948 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001949 return -EIO;
1950
Arend van Sprielc1179032012-10-22 13:55:33 -07001951 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel4f3fff12014-11-20 22:27:02 +01001952 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Johannes Berg80279fb2015-05-22 16:22:20 +02001953 cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001954
Arend van Spriel06bb1232012-09-27 14:17:56 +02001955 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001956 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001957 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001958 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001959 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001960 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001961
Arend van Sprield96b8012012-12-05 15:26:02 +01001962 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001963 return err;
1964}
1965
1966static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001967brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001968 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001969{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001970 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001971 struct net_device *ndev = cfg_to_ndev(cfg);
1972 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02001973 s32 err;
1974 s32 disable;
1975 u32 qdbm = 127;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001976
Hante Meuleman60dc35e2015-09-18 22:08:06 +02001977 brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
Arend van Sprielce81e312012-10-22 13:55:37 -07001978 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001979 return -EIO;
1980
1981 switch (type) {
1982 case NL80211_TX_POWER_AUTOMATIC:
1983 break;
1984 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 case NL80211_TX_POWER_FIXED:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02001986 if (mbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001987 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001988 err = -EINVAL;
1989 goto done;
1990 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02001991 qdbm = MBM_TO_DBM(4 * mbm);
1992 if (qdbm > 127)
1993 qdbm = 127;
1994 qdbm |= WL_TXPWR_OVERRIDE;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001995 break;
Hante Meuleman60dc35e2015-09-18 22:08:06 +02001996 default:
1997 brcmf_err("Unsupported type %d\n", type);
1998 err = -EINVAL;
1999 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002000 }
2001 /* Make sure radio is off or on as far as software is concerned */
2002 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07002003 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002004 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002005 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002006
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002007 err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002009 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002010
2011done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002012 brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002013 return err;
2014}
2015
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002016static s32
2017brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
2018 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002019{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002020 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002021 struct net_device *ndev = cfg_to_ndev(cfg);
2022 struct brcmf_if *ifp = netdev_priv(ndev);
2023 s32 qdbm = 0;
2024 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002025
Arend van Sprield96b8012012-12-05 15:26:02 +01002026 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002027 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002028 return -EIO;
2029
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002030 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002031 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002032 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002033 goto done;
2034 }
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002035 *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002036
2037done:
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002038 brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002039 return err;
2040}
2041
2042static s32
2043brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman60dc35e2015-09-18 22:08:06 +02002044 u8 key_idx, bool unicast, bool multicast)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002045{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002046 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002047 u32 index;
2048 u32 wsec;
2049 s32 err = 0;
2050
Arend van Sprield96b8012012-12-05 15:26:02 +01002051 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002052 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002053 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054 return -EIO;
2055
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002056 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002058 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002059 goto done;
2060 }
2061
2062 if (wsec & WEP_ENABLED) {
2063 /* Just select a new current key */
2064 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002065 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07002066 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002068 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 }
2070done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002071 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 return err;
2073}
2074
2075static s32
2076brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
2077 u8 key_idx, const u8 *mac_addr, struct key_params *params)
2078{
Hante Meuleman992f6062013-04-02 21:06:17 +02002079 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002081 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02002082 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02002083
2084 memset(&key, 0, sizeof(key));
2085 key.index = (u32) key_idx;
2086 /* Instead of bcast for ea address for default wep keys,
2087 driver needs it to be Null */
2088 if (!is_multicast_ether_addr(mac_addr))
2089 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
2090 key.len = (u32) params->key_len;
2091 /* check for key index change */
2092 if (key.len == 0) {
2093 /* key delete */
Hante Meuleman118eb302014-12-21 12:43:49 +01002094 err = send_key_to_dongle(ifp, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002096 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002097 } else {
2098 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002099 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 return -EINVAL;
2101 }
2102
Arend van Spriel16886732012-12-05 15:26:04 +01002103 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002104 memcpy(key.data, params->key, key.len);
2105
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002106 if (!brcmf_is_apmode(ifp->vif) &&
Hante Meuleman992f6062013-04-02 21:06:17 +02002107 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
2108 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002109 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2110 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2111 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2112 }
2113
2114 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
2115 if (params->seq && params->seq_len == 6) {
2116 /* rx iv */
2117 u8 *ivptr;
2118 ivptr = (u8 *) params->seq;
2119 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2120 (ivptr[3] << 8) | ivptr[2];
2121 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2122 key.iv_initialized = true;
2123 }
2124
2125 switch (params->cipher) {
2126 case WLAN_CIPHER_SUITE_WEP40:
2127 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01002128 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129 break;
2130 case WLAN_CIPHER_SUITE_WEP104:
2131 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01002132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002133 break;
2134 case WLAN_CIPHER_SUITE_TKIP:
2135 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002136 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002137 break;
2138 case WLAN_CIPHER_SUITE_AES_CMAC:
2139 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01002140 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 break;
2142 case WLAN_CIPHER_SUITE_CCMP:
2143 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01002144 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002145 break;
2146 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002147 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002148 return -EINVAL;
2149 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002150 err = send_key_to_dongle(ifp, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002151 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002152 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002153 }
2154 return err;
2155}
2156
2157static s32
2158brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
2159 u8 key_idx, bool pairwise, const u8 *mac_addr,
2160 struct key_params *params)
2161{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002162 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman118eb302014-12-21 12:43:49 +01002163 struct brcmf_wsec_key *key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164 s32 val;
2165 s32 wsec;
2166 s32 err = 0;
2167 u8 keybuf[8];
2168
Arend van Sprield96b8012012-12-05 15:26:02 +01002169 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002170 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002171 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002172 return -EIO;
2173
Hante Meuleman118eb302014-12-21 12:43:49 +01002174 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
2175 /* we ignore this key index in this case */
2176 brcmf_err("invalid key index (%d)\n", key_idx);
2177 return -EINVAL;
2178 }
2179
Daniel Kim787eb032014-01-29 15:32:23 +01002180 if (mac_addr &&
2181 (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
2182 (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01002183 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002184 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
2185 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002186
Hante Meuleman118eb302014-12-21 12:43:49 +01002187 key = &ifp->vif->profile.key[key_idx];
2188 memset(key, 0, sizeof(*key));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189
Hante Meuleman118eb302014-12-21 12:43:49 +01002190 if (params->key_len > sizeof(key->data)) {
2191 brcmf_err("Too long key length (%u)\n", params->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002192 err = -EINVAL;
2193 goto done;
2194 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002195 key->len = params->key_len;
2196 key->index = key_idx;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002197
Hante Meuleman118eb302014-12-21 12:43:49 +01002198 memcpy(key->data, params->key, key->len);
2199
2200 key->flags = BRCMF_PRIMARY_KEY;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201 switch (params->cipher) {
2202 case WLAN_CIPHER_SUITE_WEP40:
Hante Meuleman118eb302014-12-21 12:43:49 +01002203 key->algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002204 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002205 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002206 break;
2207 case WLAN_CIPHER_SUITE_WEP104:
Hante Meuleman118eb302014-12-21 12:43:49 +01002208 key->algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002209 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002210 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002211 break;
2212 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel967fe2c2014-03-15 17:18:21 +01002213 if (!brcmf_is_apmode(ifp->vif)) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002214 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman118eb302014-12-21 12:43:49 +01002215 memcpy(keybuf, &key->data[24], sizeof(keybuf));
2216 memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
2217 memcpy(&key->data[16], keybuf, sizeof(keybuf));
Hante Meuleman1a873342012-09-27 14:17:54 +02002218 }
Hante Meuleman118eb302014-12-21 12:43:49 +01002219 key->algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002220 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002221 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002222 break;
2223 case WLAN_CIPHER_SUITE_AES_CMAC:
Hante Meuleman118eb302014-12-21 12:43:49 +01002224 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002225 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002226 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002227 break;
2228 case WLAN_CIPHER_SUITE_CCMP:
Hante Meuleman118eb302014-12-21 12:43:49 +01002229 key->algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002230 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002231 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 break;
2233 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002234 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002235 err = -EINVAL;
2236 goto done;
2237 }
2238
Hante Meuleman118eb302014-12-21 12:43:49 +01002239 err = send_key_to_dongle(ifp, key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002240 if (err)
2241 goto done;
2242
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002243 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002245 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002246 goto done;
2247 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002248 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002249 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002250 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002251 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002252 goto done;
2253 }
2254
Arend van Spriel5b435de2011-10-05 13:19:03 +02002255done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002256 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002257 return err;
2258}
2259
2260static s32
2261brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2262 u8 key_idx, bool pairwise, const u8 *mac_addr)
2263{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002264 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 struct brcmf_wsec_key key;
2266 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267
Arend van Sprield96b8012012-12-05 15:26:02 +01002268 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002269 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002270 return -EIO;
2271
Hante Meuleman118eb302014-12-21 12:43:49 +01002272 if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
Hante Meuleman256c3742012-11-05 16:22:28 -08002273 /* we ignore this key index in this case */
Hante Meuleman256c3742012-11-05 16:22:28 -08002274 return -EINVAL;
2275 }
2276
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277 memset(&key, 0, sizeof(key));
2278
2279 key.index = (u32) key_idx;
2280 key.flags = BRCMF_PRIMARY_KEY;
2281 key.algo = CRYPTO_ALGO_OFF;
2282
Arend van Spriel16886732012-12-05 15:26:04 +01002283 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284
2285 /* Set the new key/index */
Hante Meuleman118eb302014-12-21 12:43:49 +01002286 err = send_key_to_dongle(ifp, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002287
Arend van Sprield96b8012012-12-05 15:26:02 +01002288 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289 return err;
2290}
2291
2292static s32
2293brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2294 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2295 void (*callback) (void *cookie, struct key_params * params))
2296{
2297 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002298 struct brcmf_if *ifp = netdev_priv(ndev);
2299 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002300 struct brcmf_cfg80211_security *sec;
2301 s32 wsec;
2302 s32 err = 0;
2303
Arend van Sprield96b8012012-12-05 15:26:02 +01002304 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002305 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002306 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307 return -EIO;
2308
2309 memset(&params, 0, sizeof(params));
2310
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002311 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002312 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002313 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314 /* Ignore this error, may happen during DISASSOC */
2315 err = -EAGAIN;
2316 goto done;
2317 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002318 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002319 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002320 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2321 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002322 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2324 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002325 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002326 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002327 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002328 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002329 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002330 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002331 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002332 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002333 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002334 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002335 err = -EINVAL;
2336 goto done;
2337 }
2338 callback(cookie, &params);
2339
2340done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002341 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002342 return err;
2343}
2344
2345static s32
2346brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2347 struct net_device *ndev, u8 key_idx)
2348{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002349 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002350
2351 return -EOPNOTSUPP;
2352}
2353
Hante Meuleman118eb302014-12-21 12:43:49 +01002354static void
2355brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
2356{
2357 s32 err;
2358 u8 key_idx;
2359 struct brcmf_wsec_key *key;
2360 s32 wsec;
2361
2362 for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
2363 key = &ifp->vif->profile.key[key_idx];
2364 if ((key->algo == CRYPTO_ALGO_WEP1) ||
2365 (key->algo == CRYPTO_ALGO_WEP128))
2366 break;
2367 }
2368 if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
2369 return;
2370
2371 err = send_key_to_dongle(ifp, key);
2372 if (err) {
2373 brcmf_err("Setting WEP key failed (%d)\n", err);
2374 return;
2375 }
2376 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2377 if (err) {
2378 brcmf_err("get wsec error (%d)\n", err);
2379 return;
2380 }
2381 wsec |= WEP_ENABLED;
2382 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2383 if (err)
2384 brcmf_err("set wsec error (%d)\n", err);
2385}
2386
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002387static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
2388{
2389 struct nl80211_sta_flag_update *sfu;
2390
2391 brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
2392 si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
2393 sfu = &si->sta_flags;
2394 sfu->mask = BIT(NL80211_STA_FLAG_WME) |
2395 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
2396 BIT(NL80211_STA_FLAG_ASSOCIATED) |
2397 BIT(NL80211_STA_FLAG_AUTHORIZED);
2398 if (fw_sta_flags & BRCMF_STA_WME)
2399 sfu->set |= BIT(NL80211_STA_FLAG_WME);
2400 if (fw_sta_flags & BRCMF_STA_AUTHE)
2401 sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
2402 if (fw_sta_flags & BRCMF_STA_ASSOC)
2403 sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
2404 if (fw_sta_flags & BRCMF_STA_AUTHO)
2405 sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
2406}
2407
2408static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
2409{
2410 struct {
2411 __le32 len;
2412 struct brcmf_bss_info_le bss_le;
2413 } *buf;
2414 u16 capability;
2415 int err;
2416
2417 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2418 if (!buf)
2419 return;
2420
2421 buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
2422 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
2423 WL_BSS_INFO_MAX);
2424 if (err) {
2425 brcmf_err("Failed to get bss info (%d)\n", err);
2426 return;
2427 }
2428 si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2429 si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
2430 si->bss_param.dtim_period = buf->bss_le.dtim_period;
2431 capability = le16_to_cpu(buf->bss_le.capability);
2432 if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
2433 si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
2434 if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
2435 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2436 if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2437 si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2438}
2439
Arend van Spriel5b435de2011-10-05 13:19:03 +02002440static s32
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002441brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
2442 struct station_info *sinfo)
2443{
2444 struct brcmf_scb_val_le scbval;
2445 struct brcmf_pktcnt_le pktcnt;
2446 s32 err;
2447 u32 rate;
2448 u32 rssi;
2449
2450 /* Get the current tx rate */
2451 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2452 if (err < 0) {
2453 brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err);
2454 return err;
2455 }
2456 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
2457 sinfo->txrate.legacy = rate * 5;
2458
2459 memset(&scbval, 0, sizeof(scbval));
2460 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
2461 sizeof(scbval));
2462 if (err) {
2463 brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err);
2464 return err;
2465 }
2466 rssi = le32_to_cpu(scbval.val);
2467 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2468 sinfo->signal = rssi;
2469
2470 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
2471 sizeof(pktcnt));
2472 if (err) {
2473 brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err);
2474 return err;
2475 }
2476 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
2477 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
2478 BIT(NL80211_STA_INFO_TX_PACKETS) |
2479 BIT(NL80211_STA_INFO_TX_FAILED);
2480 sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt);
2481 sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt);
2482 sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt);
2483 sinfo->tx_failed = le32_to_cpu(pktcnt.tx_bad_pkt);
2484
2485 return 0;
2486}
2487
2488static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002489brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +02002490 const u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002491{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002492 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002493 s32 err = 0;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002494 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002495 u32 sta_flags;
2496 u32 is_tdls_peer;
Hante Meulemancae355d2015-10-08 20:33:17 +02002497 s32 total_rssi;
2498 s32 count_rssi;
2499 u32 i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002500
Arend van Sprield96b8012012-12-05 15:26:02 +01002501 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002502 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002503 return -EIO;
2504
Hante Meuleman3f5893d2016-01-02 09:41:37 +01002505 if (brcmf_is_ibssmode(ifp->vif))
2506 return brcmf_cfg80211_get_station_ibss(ifp, sinfo);
2507
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002508 memset(&sta_info_le, 0, sizeof(sta_info_le));
2509 memcpy(&sta_info_le, mac, ETH_ALEN);
2510 err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
2511 &sta_info_le,
2512 sizeof(sta_info_le));
2513 is_tdls_peer = !err;
2514 if (err) {
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002515 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002516 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002517 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002518 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002519 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002520 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002521 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002522 }
2523 brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
2524 sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
2525 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2526 sta_flags = le32_to_cpu(sta_info_le.flags);
2527 brcmf_convert_sta_flags(sta_flags, sinfo);
2528 sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2529 if (is_tdls_peer)
2530 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
2531 else
2532 sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
2533 if (sta_flags & BRCMF_STA_ASSOC) {
2534 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
2535 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
2536 brcmf_fill_bss_param(ifp, sinfo);
2537 }
2538 if (sta_flags & BRCMF_STA_SCBSTATS) {
2539 sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2540 sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
2541 sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
2542 sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
2543 sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
2544 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
2545 sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
2546 sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
2547 if (sinfo->tx_packets) {
Johannes Berg319090b2014-11-17 14:08:11 +01002548 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002549 sinfo->txrate.legacy =
2550 le32_to_cpu(sta_info_le.tx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002551 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002552 if (sinfo->rx_packets) {
2553 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
Hante Meuleman124d5172015-10-08 20:33:16 +02002554 sinfo->rxrate.legacy =
2555 le32_to_cpu(sta_info_le.rx_rate) / 100;
Hante Meuleman1a873342012-09-27 14:17:54 +02002556 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002557 if (le16_to_cpu(sta_info_le.ver) >= 4) {
2558 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
2559 sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
2560 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
2561 sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
2562 }
Hante Meulemancae355d2015-10-08 20:33:17 +02002563 total_rssi = 0;
2564 count_rssi = 0;
2565 for (i = 0; i < BRCMF_ANT_MAX; i++) {
2566 if (sta_info_le.rssi[i]) {
2567 sinfo->chain_signal_avg[count_rssi] =
2568 sta_info_le.rssi[i];
2569 sinfo->chain_signal[count_rssi] =
2570 sta_info_le.rssi[i];
2571 total_rssi += sta_info_le.rssi[i];
2572 count_rssi++;
2573 }
2574 }
2575 if (count_rssi) {
2576 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
2577 sinfo->chains = count_rssi;
2578
2579 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2580 total_rssi /= count_rssi;
2581 sinfo->signal = total_rssi;
2582 }
Arend van Spriel1f0dc592015-06-11 00:12:19 +02002583 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002584done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002585 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002586 return err;
2587}
2588
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02002589static int
2590brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
2591 int idx, u8 *mac, struct station_info *sinfo)
2592{
2593 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2594 struct brcmf_if *ifp = netdev_priv(ndev);
2595 s32 err;
2596
2597 brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
2598
2599 if (idx == 0) {
2600 cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
2601 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
2602 &cfg->assoclist,
2603 sizeof(cfg->assoclist));
2604 if (err) {
2605 brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
2606 err);
2607 cfg->assoclist.count = 0;
2608 return -EOPNOTSUPP;
2609 }
2610 }
2611 if (idx < le32_to_cpu(cfg->assoclist.count)) {
2612 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
2613 return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
2614 }
2615 return -ENOENT;
2616}
2617
Arend van Spriel5b435de2011-10-05 13:19:03 +02002618static s32
2619brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2620 bool enabled, s32 timeout)
2621{
2622 s32 pm;
2623 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002624 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002625 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002626
Arend van Sprield96b8012012-12-05 15:26:02 +01002627 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002628
2629 /*
2630 * Powersave enable/disable request is coming from the
2631 * cfg80211 even before the interface is up. In that
2632 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002633 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002634 * FW later while initializing the dongle
2635 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002636 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002637 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002638
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002639 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002640 goto done;
2641 }
2642
2643 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002644 /* Do not enable the power save after assoc if it is a p2p interface */
2645 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2646 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2647 pm = PM_OFF;
2648 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002649 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650
Arend van Sprielc1179032012-10-22 13:55:33 -07002651 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002652 if (err) {
2653 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002654 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002655 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002656 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002657 }
2658done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002659 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002660 return err;
2661}
2662
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002663static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002664 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002665{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002666 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002667 struct ieee80211_channel *notify_channel;
2668 struct cfg80211_bss *bss;
2669 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002670 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002671 u16 channel;
2672 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002673 u16 notify_capability;
2674 u16 notify_interval;
2675 u8 *notify_ie;
2676 size_t notify_ielen;
2677 s32 notify_signal;
2678
2679 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002680 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002681 return 0;
2682 }
2683
Franky Lin83cf17a2013-04-11 13:28:50 +02002684 if (!bi->ctl_ch) {
2685 ch.chspec = le16_to_cpu(bi->chanspec);
2686 cfg->d11inf.decchspec(&ch);
2687 bi->ctl_ch = ch.chnum;
2688 }
2689 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002690
2691 if (channel <= CH_MAX_2G_CHANNEL)
2692 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2693 else
2694 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2695
2696 freq = ieee80211_channel_to_frequency(channel, band->band);
2697 notify_channel = ieee80211_get_channel(wiphy, freq);
2698
Arend van Spriel5b435de2011-10-05 13:19:03 +02002699 notify_capability = le16_to_cpu(bi->capability);
2700 notify_interval = le16_to_cpu(bi->beacon_period);
2701 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2702 notify_ielen = le32_to_cpu(bi->ie_length);
2703 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2704
Arend van Spriel16886732012-12-05 15:26:04 +01002705 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2706 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2707 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2708 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2709 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002711 bss = cfg80211_inform_bss(wiphy, notify_channel,
2712 CFG80211_BSS_FTYPE_UNKNOWN,
2713 (const u8 *)bi->BSSID,
2714 0, notify_capability,
2715 notify_interval, notify_ie,
2716 notify_ielen, notify_signal,
2717 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718
Franky Line78946e2011-11-10 20:30:34 +01002719 if (!bss)
2720 return -ENOMEM;
2721
Johannes Berg5b112d32013-02-01 01:49:58 +01002722 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002723
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03002724 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002725}
2726
Roland Vossen6f09be02011-10-18 14:03:02 +02002727static struct brcmf_bss_info_le *
2728next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2729{
2730 if (bss == NULL)
2731 return list->bss_info_le;
2732 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2733 le32_to_cpu(bss->length));
2734}
2735
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002736static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002737{
2738 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002739 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002740 s32 err = 0;
2741 int i;
2742
Hante Meulemanef8596e2014-09-30 10:23:13 +02002743 bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002744 if (bss_list->count != 0 &&
2745 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002746 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2747 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002748 return -EOPNOTSUPP;
2749 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002750 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002751 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002752 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002753 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002754 if (err)
2755 break;
2756 }
2757 return err;
2758}
2759
Hante Meulemanb0a79082015-12-10 13:43:07 +01002760static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg,
2761 struct net_device *ndev, const u8 *bssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002762{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002763 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002764 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002765 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002767 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002768 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002769 u8 *buf = NULL;
2770 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002771 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772 u16 notify_capability;
2773 u16 notify_interval;
2774 u8 *notify_ie;
2775 size_t notify_ielen;
2776 s32 notify_signal;
2777
Arend van Sprield96b8012012-12-05 15:26:02 +01002778 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002779
2780 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2781 if (buf == NULL) {
2782 err = -ENOMEM;
2783 goto CleanUp;
2784 }
2785
2786 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2787
Arend van Sprielac24be62012-10-22 10:36:23 -07002788 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2789 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002790 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002791 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792 goto CleanUp;
2793 }
2794
Roland Vossend34bf642011-10-18 14:03:01 +02002795 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002796
Franky Lin83cf17a2013-04-11 13:28:50 +02002797 ch.chspec = le16_to_cpu(bi->chanspec);
2798 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002799
Franky Lin83cf17a2013-04-11 13:28:50 +02002800 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2802 else
2803 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2804
Franky Lin83cf17a2013-04-11 13:28:50 +02002805 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Hante Meulemanb0a79082015-12-10 13:43:07 +01002806 cfg->channel = freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002807 notify_channel = ieee80211_get_channel(wiphy, freq);
2808
Arend van Spriel5b435de2011-10-05 13:19:03 +02002809 notify_capability = le16_to_cpu(bi->capability);
2810 notify_interval = le16_to_cpu(bi->beacon_period);
2811 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2812 notify_ielen = le32_to_cpu(bi->ie_length);
2813 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2814
Franky Lin83cf17a2013-04-11 13:28:50 +02002815 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002816 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2817 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2818 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819
Johannes Berg5bc8c1f2014-08-12 21:01:28 +02002820 bss = cfg80211_inform_bss(wiphy, notify_channel,
2821 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
2822 notify_capability, notify_interval,
2823 notify_ie, notify_ielen, notify_signal,
2824 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002825
Franky Line78946e2011-11-10 20:30:34 +01002826 if (!bss) {
2827 err = -ENOMEM;
2828 goto CleanUp;
2829 }
2830
Johannes Berg5b112d32013-02-01 01:49:58 +01002831 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002832
Arend van Spriel5b435de2011-10-05 13:19:03 +02002833CleanUp:
2834
2835 kfree(buf);
2836
Arend van Sprield96b8012012-12-05 15:26:02 +01002837 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002838
2839 return err;
2840}
2841
Hante Meuleman89286dc2013-02-08 15:53:46 +01002842static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2843 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002844{
Roland Vossend34bf642011-10-18 14:03:01 +02002845 struct brcmf_bss_info_le *bi;
Johannes Berg4b5800f2014-01-15 14:55:59 +01002846 const struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002847 u16 beacon_interval;
2848 u8 dtim_period;
2849 size_t ie_len;
2850 u8 *ie;
2851 s32 err = 0;
2852
Arend van Sprield96b8012012-12-05 15:26:02 +01002853 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002854 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002855 return err;
2856
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002857 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002858 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002859 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002861 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002862 goto update_bss_info_out;
2863 }
2864
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002865 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2866 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002867 if (err)
2868 goto update_bss_info_out;
2869
2870 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2871 ie_len = le32_to_cpu(bi->ie_length);
2872 beacon_interval = le16_to_cpu(bi->beacon_period);
2873
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002874 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002875 if (tim)
2876 dtim_period = tim->data[1];
2877 else {
2878 /*
2879 * active scan was done so we could not get dtim
2880 * information out of probe response.
2881 * so we speficially query dtim information to dongle.
2882 */
2883 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002884 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002886 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002887 goto update_bss_info_out;
2888 }
2889 dtim_period = (u8)var;
2890 }
2891
Arend van Spriel5b435de2011-10-05 13:19:03 +02002892update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002893 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002894 return err;
2895}
2896
Hante Meuleman18e2f612013-02-08 15:53:49 +01002897void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002898{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002899 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002900
Arend van Sprielc1179032012-10-22 13:55:33 -07002901 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002902 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002903 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002904 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002905 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002906 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2907 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002908}
2909
Hante Meulemane756af52012-09-11 21:18:52 +02002910static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2911{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002912 struct brcmf_cfg80211_info *cfg =
2913 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002914 escan_timeout_work);
2915
Hante Meulemanef8596e2014-09-30 10:23:13 +02002916 brcmf_inform_bss(cfg);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002917 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002918}
2919
2920static void brcmf_escan_timeout(unsigned long data)
2921{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002922 struct brcmf_cfg80211_info *cfg =
2923 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002924
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002925 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002926 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002927 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002928 }
2929}
2930
2931static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002932brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2933 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002934 struct brcmf_bss_info_le *bss_info_le)
2935{
Franky Lin83cf17a2013-04-11 13:28:50 +02002936 struct brcmu_chan ch_bss, ch_bss_info_le;
2937
2938 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2939 cfg->d11inf.decchspec(&ch_bss);
2940 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2941 cfg->d11inf.decchspec(&ch_bss_info_le);
2942
Hante Meulemane756af52012-09-11 21:18:52 +02002943 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002944 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002945 bss_info_le->SSID_len == bss->SSID_len &&
2946 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002947 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2948 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002949 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2950 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2951
Hante Meulemane756af52012-09-11 21:18:52 +02002952 /* preserve max RSSI if the measurements are
2953 * both on-channel or both off-channel
2954 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002955 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002956 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002957 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2958 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002959 /* preserve the on-channel rssi measurement
2960 * if the new measurement is off channel
2961 */
2962 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002963 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002964 }
2965 return 1;
2966 }
2967 return 0;
2968}
2969
2970static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002971brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002972 const struct brcmf_event_msg *e, void *data)
2973{
Arend van Spriel19937322012-11-05 16:22:32 -08002974 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002975 s32 status;
Hante Meulemane756af52012-09-11 21:18:52 +02002976 struct brcmf_escan_result_le *escan_result_le;
2977 struct brcmf_bss_info_le *bss_info_le;
2978 struct brcmf_bss_info_le *bss = NULL;
2979 u32 bi_length;
2980 struct brcmf_scan_results *list;
2981 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002982 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002983
Arend van Spriel5c36b992012-11-14 18:46:05 -08002984 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002985
Arend van Spriela0f472a2013-04-05 10:57:49 +02002986 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meuleman37a869e2015-10-29 20:33:17 +01002987 brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002988 return -EPERM;
2989 }
2990
2991 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002992 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002993 escan_result_le = (struct brcmf_escan_result_le *) data;
2994 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002995 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002996 goto exit;
2997 }
Hante Meulemane756af52012-09-11 21:18:52 +02002998 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002999 brcmf_err("Invalid bss_count %d: ignoring\n",
3000 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02003001 goto exit;
3002 }
3003 bss_info_le = &escan_result_le->bss_info_le;
3004
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003005 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
3006 goto exit;
3007
3008 if (!cfg->scan_request) {
3009 brcmf_dbg(SCAN, "result without cfg80211 request\n");
3010 goto exit;
3011 }
3012
Hante Meulemane756af52012-09-11 21:18:52 +02003013 bi_length = le32_to_cpu(bss_info_le->length);
3014 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
3015 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003016 brcmf_err("Invalid bss_info length %d: ignoring\n",
3017 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003018 goto exit;
3019 }
3020
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003021 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02003022 BIT(NL80211_IFTYPE_ADHOC))) {
3023 if (le16_to_cpu(bss_info_le->capability) &
3024 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003025 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003026 goto exit;
3027 }
3028 }
3029
3030 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003031 cfg->escan_info.escan_buf;
Hante Meulemand5367332016-02-17 11:26:51 +01003032 if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003033 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02003034 goto exit;
3035 }
3036
3037 for (i = 0; i < list->count; i++) {
3038 bss = bss ? (struct brcmf_bss_info_le *)
3039 ((unsigned char *)bss +
3040 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02003041 if (brcmf_compare_update_same_bss(cfg, bss,
3042 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02003043 goto exit;
3044 }
Hante Meulemand5367332016-02-17 11:26:51 +01003045 memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
3046 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02003047 list->version = le32_to_cpu(bss_info_le->version);
3048 list->buflen += bi_length;
3049 list->count++;
3050 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003051 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003052 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
3053 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003054 if (cfg->scan_request) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003055 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02003056 aborted = status != BRCMF_E_STATUS_SUCCESS;
Hante Meulemanef8596e2014-09-30 10:23:13 +02003057 brcmf_notify_escan_complete(cfg, ifp, aborted, false);
Hante Meulemane756af52012-09-11 21:18:52 +02003058 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01003059 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
3060 status);
Hante Meulemane756af52012-09-11 21:18:52 +02003061 }
3062exit:
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03003063 return 0;
Hante Meulemane756af52012-09-11 21:18:52 +02003064}
3065
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003066static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02003067{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003068 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
3069 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08003070 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
3071 /* Init scan_timeout timer */
3072 init_timer(&cfg->escan_timeout);
3073 cfg->escan_timeout.data = (unsigned long) cfg;
3074 cfg->escan_timeout.function = brcmf_escan_timeout;
3075 INIT_WORK(&cfg->escan_timeout_work,
3076 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02003077}
3078
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003079/* PFN result doesn't have all the info which are required by the supplicant
3080 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3081 * via wl_inform_single_bss in the required format. Escan does require the
3082 * scan request in the form of cfg80211_scan_request. For timebeing, create
3083 * cfg80211_scan_request one out of the received PNO event.
3084 */
3085static s32
3086brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
3087 const struct brcmf_event_msg *e, void *data)
3088{
3089 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3090 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3091 struct cfg80211_scan_request *request = NULL;
3092 struct cfg80211_ssid *ssid = NULL;
3093 struct ieee80211_channel *channel = NULL;
3094 struct wiphy *wiphy = cfg_to_wiphy(cfg);
3095 int err = 0;
3096 int channel_req = 0;
3097 int band = 0;
3098 struct brcmf_pno_scanresults_le *pfn_result;
3099 u32 result_count;
3100 u32 status;
3101
3102 brcmf_dbg(SCAN, "Enter\n");
3103
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003104 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3105 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3106 return 0;
3107 }
3108
Hante Meuleman5419f7f2016-01-05 11:05:46 +01003109 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3110 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
3111 return 0;
3112 }
3113
3114 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3115 result_count = le32_to_cpu(pfn_result->count);
3116 status = le32_to_cpu(pfn_result->status);
3117
3118 /* PFN event is limited to fit 512 bytes so we may get
3119 * multiple NET_FOUND events. For now place a warning here.
3120 */
3121 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3122 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3123 if (result_count > 0) {
3124 int i;
3125
3126 request = kzalloc(sizeof(*request), GFP_KERNEL);
3127 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3128 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3129 if (!request || !ssid || !channel) {
3130 err = -ENOMEM;
3131 goto out_err;
3132 }
3133
3134 request->wiphy = wiphy;
3135 data += sizeof(struct brcmf_pno_scanresults_le);
3136 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3137
3138 for (i = 0; i < result_count; i++) {
3139 netinfo = &netinfo_start[i];
3140 if (!netinfo) {
3141 brcmf_err("Invalid netinfo ptr. index: %d\n",
3142 i);
3143 err = -EINVAL;
3144 goto out_err;
3145 }
3146
3147 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
3148 netinfo->SSID, netinfo->channel);
3149 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3150 ssid[i].ssid_len = netinfo->SSID_len;
3151 request->n_ssids++;
3152
3153 channel_req = netinfo->channel;
3154 if (channel_req <= CH_MAX_2G_CHANNEL)
3155 band = NL80211_BAND_2GHZ;
3156 else
3157 band = NL80211_BAND_5GHZ;
3158 channel[i].center_freq =
3159 ieee80211_channel_to_frequency(channel_req,
3160 band);
3161 channel[i].band = band;
3162 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3163 request->channels[i] = &channel[i];
3164 request->n_channels++;
3165 }
3166
3167 /* assign parsed ssid array */
3168 if (request->n_ssids)
3169 request->ssids = &ssid[0];
3170
3171 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3172 /* Abort any on-going scan */
3173 brcmf_abort_scanning(cfg);
3174 }
3175
3176 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3177 cfg->escan_info.run = brcmf_run_escan;
3178 err = brcmf_do_escan(cfg, wiphy, ifp, request);
3179 if (err) {
3180 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3181 goto out_err;
3182 }
3183 cfg->sched_escan = true;
3184 cfg->scan_request = request;
3185 } else {
3186 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3187 goto out_err;
3188 }
3189
3190 kfree(ssid);
3191 kfree(channel);
3192 kfree(request);
3193 return 0;
3194
3195out_err:
3196 kfree(ssid);
3197 kfree(channel);
3198 kfree(request);
3199 cfg80211_sched_scan_stopped(wiphy);
3200 return err;
3201}
3202
3203static int brcmf_dev_pno_clean(struct net_device *ndev)
3204{
3205 int ret;
3206
3207 /* Disable pfn */
3208 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3209 if (ret == 0) {
3210 /* clear pfn */
3211 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3212 NULL, 0);
3213 }
3214 if (ret < 0)
3215 brcmf_err("failed code %d\n", ret);
3216
3217 return ret;
3218}
3219
3220static int brcmf_dev_pno_config(struct brcmf_if *ifp,
3221 struct cfg80211_sched_scan_request *request)
3222{
3223 struct brcmf_pno_param_le pfn_param;
3224 struct brcmf_pno_macaddr_le pfn_mac;
3225 s32 err;
3226 u8 *mac_mask;
3227 int i;
3228
3229 memset(&pfn_param, 0, sizeof(pfn_param));
3230 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3231
3232 /* set extra pno params */
3233 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3234 pfn_param.repeat = BRCMF_PNO_REPEAT;
3235 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3236
3237 /* set up pno scan fr */
3238 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3239
3240 err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
3241 sizeof(pfn_param));
3242 if (err) {
3243 brcmf_err("pfn_set failed, err=%d\n", err);
3244 return err;
3245 }
3246
3247 /* Find out if mac randomization should be turned on */
3248 if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
3249 return 0;
3250
3251 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
3252 pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
3253
3254 memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
3255 mac_mask = request->mac_addr_mask;
3256 for (i = 0; i < ETH_ALEN; i++) {
3257 pfn_mac.mac[i] &= mac_mask[i];
3258 pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
3259 }
3260 /* Clear multi bit */
3261 pfn_mac.mac[0] &= 0xFE;
3262 /* Set locally administered */
3263 pfn_mac.mac[0] |= 0x02;
3264
3265 err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
3266 sizeof(pfn_mac));
3267 if (err)
3268 brcmf_err("pfn_macaddr failed, err=%d\n", err);
3269
3270 return err;
3271}
3272
3273static int
3274brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3275 struct net_device *ndev,
3276 struct cfg80211_sched_scan_request *request)
3277{
3278 struct brcmf_if *ifp = netdev_priv(ndev);
3279 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3280 struct brcmf_pno_net_param_le pfn;
3281 int i;
3282 int ret = 0;
3283
3284 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3285 request->n_match_sets, request->n_ssids);
3286 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3287 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3288 return -EAGAIN;
3289 }
3290 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3291 brcmf_err("Scanning suppressed: status (%lu)\n",
3292 cfg->scan_status);
3293 return -EAGAIN;
3294 }
3295
3296 if (!request->n_ssids || !request->n_match_sets) {
3297 brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3298 request->n_ssids);
3299 return -EINVAL;
3300 }
3301
3302 if (request->n_ssids > 0) {
3303 for (i = 0; i < request->n_ssids; i++) {
3304 /* Active scan req for ssids */
3305 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3306 request->ssids[i].ssid);
3307
3308 /* match_set ssids is a supert set of n_ssid list,
3309 * so we need not add these set separately.
3310 */
3311 }
3312 }
3313
3314 if (request->n_match_sets > 0) {
3315 /* clean up everything */
3316 ret = brcmf_dev_pno_clean(ndev);
3317 if (ret < 0) {
3318 brcmf_err("failed error=%d\n", ret);
3319 return ret;
3320 }
3321
3322 /* configure pno */
3323 if (brcmf_dev_pno_config(ifp, request))
3324 return -EINVAL;
3325
3326 /* configure each match set */
3327 for (i = 0; i < request->n_match_sets; i++) {
3328 struct cfg80211_ssid *ssid;
3329 u32 ssid_len;
3330
3331 ssid = &request->match_sets[i].ssid;
3332 ssid_len = ssid->ssid_len;
3333
3334 if (!ssid_len) {
3335 brcmf_err("skip broadcast ssid\n");
3336 continue;
3337 }
3338 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3339 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3340 pfn.wsec = cpu_to_le32(0);
3341 pfn.infra = cpu_to_le32(1);
3342 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3343 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3344 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3345 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3346 sizeof(pfn));
3347 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3348 ret == 0 ? "set" : "failed", ssid->ssid);
3349 }
3350 /* Enable the PNO */
3351 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3352 brcmf_err("PNO enable failed!! ret=%d\n", ret);
3353 return -EINVAL;
3354 }
3355 } else {
3356 return -EINVAL;
3357 }
3358
3359 return 0;
3360}
3361
3362static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3363 struct net_device *ndev)
3364{
3365 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3366
3367 brcmf_dbg(SCAN, "enter\n");
3368 brcmf_dev_pno_clean(ndev);
3369 if (cfg->sched_escan)
3370 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3371 return 0;
3372}
3373
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05003374static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003375{
3376 if (ms < 1000 / HZ) {
3377 cond_resched();
3378 mdelay(ms);
3379 } else {
3380 msleep(ms);
3381 }
3382}
3383
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003384static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
3385 u8 *pattern, u32 patternsize, u8 *mask,
3386 u32 packet_offset)
3387{
3388 struct brcmf_fil_wowl_pattern_le *filter;
3389 u32 masksize;
3390 u32 patternoffset;
3391 u8 *buf;
3392 u32 bufsize;
3393 s32 ret;
3394
3395 masksize = (patternsize + 7) / 8;
3396 patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
3397
3398 bufsize = sizeof(*filter) + patternsize + masksize;
3399 buf = kzalloc(bufsize, GFP_KERNEL);
3400 if (!buf)
3401 return -ENOMEM;
3402 filter = (struct brcmf_fil_wowl_pattern_le *)buf;
3403
3404 memcpy(filter->cmd, cmd, 4);
3405 filter->masksize = cpu_to_le32(masksize);
3406 filter->offset = cpu_to_le32(packet_offset);
3407 filter->patternoffset = cpu_to_le32(patternoffset);
3408 filter->patternsize = cpu_to_le32(patternsize);
3409 filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
3410
3411 if ((mask) && (masksize))
3412 memcpy(buf + sizeof(*filter), mask, masksize);
3413 if ((pattern) && (patternsize))
3414 memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
3415
3416 ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
3417
3418 kfree(buf);
3419 return ret;
3420}
3421
Hante Meuleman3021ad92016-01-05 11:05:45 +01003422static s32
3423brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
3424 void *data)
3425{
3426 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
3427 struct brcmf_pno_scanresults_le *pfn_result;
3428 struct brcmf_pno_net_info_le *netinfo;
3429
3430 brcmf_dbg(SCAN, "Enter\n");
3431
Hante Meuleman0aedbca2016-02-17 11:26:54 +01003432 if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
3433 brcmf_dbg(SCAN, "Event data to small. Ignore\n");
3434 return 0;
3435 }
3436
Hante Meuleman3021ad92016-01-05 11:05:45 +01003437 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3438
3439 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
3440 brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
3441 return 0;
3442 }
3443
3444 if (le32_to_cpu(pfn_result->count) < 1) {
3445 brcmf_err("Invalid result count, expected 1 (%d)\n",
3446 le32_to_cpu(pfn_result->count));
3447 return -EINVAL;
3448 }
3449
3450 data += sizeof(struct brcmf_pno_scanresults_le);
3451 netinfo = (struct brcmf_pno_net_info_le *)data;
3452 memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
3453 cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
3454 cfg->wowl.nd->n_channels = 1;
3455 cfg->wowl.nd->channels[0] =
3456 ieee80211_channel_to_frequency(netinfo->channel,
3457 netinfo->channel <= CH_MAX_2G_CHANNEL ?
3458 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
3459 cfg->wowl.nd_info->n_matches = 1;
3460 cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
3461
3462 /* Inform (the resume task) that the net detect information was recvd */
3463 cfg->wowl.nd_data_completed = true;
3464 wake_up(&cfg->wowl.nd_data_wait);
3465
3466 return 0;
3467}
3468
Hante Meulemanaeb64222015-10-29 20:33:19 +01003469#ifdef CONFIG_PM
3470
3471static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3472{
Hante Meuleman3021ad92016-01-05 11:05:45 +01003473 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemanaeb64222015-10-29 20:33:19 +01003474 struct brcmf_wowl_wakeind_le wake_ind_le;
3475 struct cfg80211_wowlan_wakeup wakeup_data;
3476 struct cfg80211_wowlan_wakeup *wakeup;
3477 u32 wakeind;
3478 s32 err;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003479 int timeout;
Hante Meulemanaeb64222015-10-29 20:33:19 +01003480
3481 err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
3482 sizeof(wake_ind_le));
Hante Meuleman3021ad92016-01-05 11:05:45 +01003483 if (err) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003484 brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
3485 return;
3486 }
3487
3488 wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
3489 if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
Hante Meuleman3021ad92016-01-05 11:05:45 +01003490 BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
3491 BRCMF_WOWL_PFN_FOUND)) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003492 wakeup = &wakeup_data;
3493 memset(&wakeup_data, 0, sizeof(wakeup_data));
3494 wakeup_data.pattern_idx = -1;
3495
3496 if (wakeind & BRCMF_WOWL_MAGIC) {
3497 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
3498 wakeup_data.magic_pkt = true;
3499 }
3500 if (wakeind & BRCMF_WOWL_DIS) {
3501 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
3502 wakeup_data.disconnect = true;
3503 }
3504 if (wakeind & BRCMF_WOWL_BCN) {
3505 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
3506 wakeup_data.disconnect = true;
3507 }
3508 if (wakeind & BRCMF_WOWL_RETR) {
3509 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
3510 wakeup_data.disconnect = true;
3511 }
3512 if (wakeind & BRCMF_WOWL_NET) {
3513 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
3514 /* For now always map to pattern 0, no API to get
3515 * correct information available at the moment.
3516 */
3517 wakeup_data.pattern_idx = 0;
3518 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003519 if (wakeind & BRCMF_WOWL_PFN_FOUND) {
3520 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
3521 timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
3522 cfg->wowl.nd_data_completed,
3523 BRCMF_ND_INFO_TIMEOUT);
3524 if (!timeout)
3525 brcmf_err("No result for wowl net detect\n");
3526 else
3527 wakeup_data.net_detect = cfg->wowl.nd_info;
3528 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003529 if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
3530 brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
3531 wakeup_data.gtk_rekey_failure = true;
3532 }
Hante Meulemanaeb64222015-10-29 20:33:19 +01003533 } else {
3534 wakeup = NULL;
3535 }
3536 cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
3537}
3538
3539#else
3540
3541static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
3542{
3543}
3544
3545#endif /* CONFIG_PM */
3546
Arend van Spriel5b435de2011-10-05 13:19:03 +02003547static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
3548{
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003549 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3550 struct net_device *ndev = cfg_to_ndev(cfg);
3551 struct brcmf_if *ifp = netdev_priv(ndev);
3552
Arend van Sprield96b8012012-12-05 15:26:02 +01003553 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003554
Hante Meuleman3021ad92016-01-05 11:05:45 +01003555 if (cfg->wowl.active) {
Hante Meulemanaeb64222015-10-29 20:33:19 +01003556 brcmf_report_wowl_wakeind(wiphy, ifp);
3557 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
3558 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003559 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3560 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003561 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003562 cfg->wowl.pre_pmmode);
3563 cfg->wowl.active = false;
3564 if (cfg->wowl.nd_enabled) {
3565 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3566 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3567 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3568 brcmf_notify_sched_scan_results);
3569 cfg->wowl.nd_enabled = false;
3570 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003571 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003572 return 0;
3573}
3574
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003575static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3576 struct brcmf_if *ifp,
3577 struct cfg80211_wowlan *wowl)
3578{
3579 u32 wowl_config;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003580 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003581
3582 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3583
Hante Meuleman73ef9e62016-02-17 11:27:05 +01003584 if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
3585 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003586 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003587 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3588
3589 wowl_config = 0;
3590 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003591 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003592 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003593 wowl_config |= BRCMF_WOWL_MAGIC;
3594 if ((wowl->patterns) && (wowl->n_patterns)) {
3595 wowl_config |= BRCMF_WOWL_NET;
3596 for (i = 0; i < wowl->n_patterns; i++) {
3597 brcmf_config_wowl_pattern(ifp, "add",
3598 (u8 *)wowl->patterns[i].pattern,
3599 wowl->patterns[i].pattern_len,
3600 (u8 *)wowl->patterns[i].mask,
3601 wowl->patterns[i].pkt_offset);
3602 }
3603 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003604 if (wowl->nd_config) {
3605 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3606 wowl->nd_config);
3607 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3608
3609 cfg->wowl.nd_data_completed = false;
3610 cfg->wowl.nd_enabled = true;
3611 /* Now reroute the event for PFN to the wowl function. */
3612 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3613 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3614 brcmf_wowl_nd_results);
3615 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003616 if (wowl->gtk_rekey_failure)
3617 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003618 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3619 wowl_config |= BRCMF_WOWL_UNASSOC;
3620
Hante Meulemanaeb64222015-10-29 20:33:19 +01003621 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003622 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3623 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3624 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003625 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003626}
3627
Arend van Spriel5b435de2011-10-05 13:19:03 +02003628static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003629 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003630{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003631 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3632 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003633 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003634 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003635
Arend van Sprield96b8012012-12-05 15:26:02 +01003636 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003637
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003638 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003639 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003640 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003641 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003642 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003643
Hante Meuleman3021ad92016-01-05 11:05:45 +01003644 /* Stop scheduled scan */
3645 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3646 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3647
Arend van Spriel7d641072012-10-22 13:55:39 -07003648 /* end any scanning */
3649 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003650 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003651
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003652 if (wowl == NULL) {
3653 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3654 list_for_each_entry(vif, &cfg->vif_list, list) {
3655 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3656 continue;
3657 /* While going to suspend if associated with AP
3658 * disassociate from AP to save power while system is
3659 * in suspended state
3660 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003661 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003662 /* Make sure WPA_Supplicant receives all the event
3663 * generated due to DISASSOC call to the fw to keep
3664 * the state fw and WPA_Supplicant state consistent
3665 */
3666 brcmf_delay(500);
3667 }
3668 /* Configure MPC */
3669 brcmf_set_mpc(ifp, 1);
3670
3671 } else {
3672 /* Configure WOWL paramaters */
3673 brcmf_configure_wowl(cfg, ifp, wowl);
3674 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003675
Arend van Spriel7d641072012-10-22 13:55:39 -07003676exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003677 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003678 /* clear any scanning activity */
3679 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003680 return 0;
3681}
3682
3683static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003684brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003685{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003686 struct brcmf_pmk_list_le *pmk_list;
3687 int i;
3688 u32 npmk;
3689 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003690
Hante Meuleman6c404f32015-12-10 13:43:03 +01003691 pmk_list = &cfg->pmk_list;
3692 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003693
Hante Meuleman6c404f32015-12-10 13:43:03 +01003694 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3695 for (i = 0; i < npmk; i++)
3696 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003697
Hante Meuleman6c404f32015-12-10 13:43:03 +01003698 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3699 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003700
3701 return err;
3702}
3703
3704static s32
3705brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3706 struct cfg80211_pmksa *pmksa)
3707{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003708 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003709 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003710 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3711 s32 err;
3712 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003713
Arend van Sprield96b8012012-12-05 15:26:02 +01003714 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003715 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003716 return -EIO;
3717
Hante Meuleman6c404f32015-12-10 13:43:03 +01003718 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3719 for (i = 0; i < npmk; i++)
3720 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003721 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003722 if (i < BRCMF_MAXPMKID) {
3723 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3724 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3725 if (i == npmk) {
3726 npmk++;
3727 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003728 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003729 } else {
3730 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3731 return -EINVAL;
3732 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003733
Hante Meuleman6c404f32015-12-10 13:43:03 +01003734 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3735 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3736 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3737 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3738 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003739
Hante Meuleman6c404f32015-12-10 13:43:03 +01003740 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003741
Arend van Sprield96b8012012-12-05 15:26:02 +01003742 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003743 return err;
3744}
3745
3746static s32
3747brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003748 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003749{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003750 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003751 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003752 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3753 s32 err;
3754 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003755
Arend van Sprield96b8012012-12-05 15:26:02 +01003756 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003757 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003758 return -EIO;
3759
Hante Meuleman6c404f32015-12-10 13:43:03 +01003760 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003761
Hante Meuleman6c404f32015-12-10 13:43:03 +01003762 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3763 for (i = 0; i < npmk; i++)
3764 if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003765 break;
3766
Hante Meuleman6c404f32015-12-10 13:43:03 +01003767 if ((npmk > 0) && (i < npmk)) {
3768 for (; i < (npmk - 1); i++) {
3769 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3770 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003771 WLAN_PMKID_LEN);
3772 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003773 memset(&pmk[i], 0, sizeof(*pmk));
3774 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3775 } else {
3776 brcmf_err("Cache entry not found\n");
3777 return -EINVAL;
3778 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003779
Hante Meuleman6c404f32015-12-10 13:43:03 +01003780 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003781
Arend van Sprield96b8012012-12-05 15:26:02 +01003782 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003783 return err;
3784
3785}
3786
3787static s32
3788brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3789{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003790 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003791 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003792 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003793
Arend van Sprield96b8012012-12-05 15:26:02 +01003794 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003795 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003796 return -EIO;
3797
Hante Meuleman6c404f32015-12-10 13:43:03 +01003798 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3799 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003800
Arend van Sprield96b8012012-12-05 15:26:02 +01003801 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003802 return err;
3803
3804}
3805
Hante Meuleman1f170112013-02-06 18:40:38 +01003806static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003807{
3808 s32 err;
3809
3810 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003811 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003812 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003813 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003814 return err;
3815 }
3816 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003817 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003818 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003819 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003820 return err;
3821 }
3822 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003823 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003824 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003825 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003826 return err;
3827 }
3828
3829 return 0;
3830}
3831
3832static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3833{
3834 if (is_rsn_ie)
3835 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3836
3837 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3838}
3839
3840static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003841brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003842 const struct brcmf_vs_tlv *wpa_ie,
3843 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003844{
3845 u32 auth = 0; /* d11 open authentication */
3846 u16 count;
3847 s32 err = 0;
3848 s32 len = 0;
3849 u32 i;
3850 u32 wsec;
3851 u32 pval = 0;
3852 u32 gval = 0;
3853 u32 wpa_auth = 0;
3854 u32 offset;
3855 u8 *data;
3856 u16 rsn_cap;
3857 u32 wme_bss_disable;
3858
Arend van Sprield96b8012012-12-05 15:26:02 +01003859 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003860 if (wpa_ie == NULL)
3861 goto exit;
3862
3863 len = wpa_ie->len + TLV_HDR_LEN;
3864 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003865 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003866 if (!is_rsn_ie)
3867 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003868 else
3869 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003870
3871 /* check for multicast cipher suite */
3872 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3873 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003874 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003875 goto exit;
3876 }
3877
3878 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3879 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003880 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003881 goto exit;
3882 }
3883 offset += TLV_OUI_LEN;
3884
3885 /* pick up multicast cipher */
3886 switch (data[offset]) {
3887 case WPA_CIPHER_NONE:
3888 gval = 0;
3889 break;
3890 case WPA_CIPHER_WEP_40:
3891 case WPA_CIPHER_WEP_104:
3892 gval = WEP_ENABLED;
3893 break;
3894 case WPA_CIPHER_TKIP:
3895 gval = TKIP_ENABLED;
3896 break;
3897 case WPA_CIPHER_AES_CCM:
3898 gval = AES_ENABLED;
3899 break;
3900 default:
3901 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003902 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003903 goto exit;
3904 }
3905
3906 offset++;
3907 /* walk thru unicast cipher list and pick up what we recognize */
3908 count = data[offset] + (data[offset + 1] << 8);
3909 offset += WPA_IE_SUITE_COUNT_LEN;
3910 /* Check for unicast suite(s) */
3911 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3912 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003913 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003914 goto exit;
3915 }
3916 for (i = 0; i < count; i++) {
3917 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3918 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003919 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003920 goto exit;
3921 }
3922 offset += TLV_OUI_LEN;
3923 switch (data[offset]) {
3924 case WPA_CIPHER_NONE:
3925 break;
3926 case WPA_CIPHER_WEP_40:
3927 case WPA_CIPHER_WEP_104:
3928 pval |= WEP_ENABLED;
3929 break;
3930 case WPA_CIPHER_TKIP:
3931 pval |= TKIP_ENABLED;
3932 break;
3933 case WPA_CIPHER_AES_CCM:
3934 pval |= AES_ENABLED;
3935 break;
3936 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003937 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003938 }
3939 offset++;
3940 }
3941 /* walk thru auth management suite list and pick up what we recognize */
3942 count = data[offset] + (data[offset + 1] << 8);
3943 offset += WPA_IE_SUITE_COUNT_LEN;
3944 /* Check for auth key management suite(s) */
3945 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3946 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003947 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 goto exit;
3949 }
3950 for (i = 0; i < count; i++) {
3951 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3952 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003953 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003954 goto exit;
3955 }
3956 offset += TLV_OUI_LEN;
3957 switch (data[offset]) {
3958 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003959 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003960 wpa_auth |= WPA_AUTH_NONE;
3961 break;
3962 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003963 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003964 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3965 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3966 break;
3967 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003968 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003969 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3970 (wpa_auth |= WPA_AUTH_PSK);
3971 break;
3972 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003973 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003974 }
3975 offset++;
3976 }
3977
3978 if (is_rsn_ie) {
3979 wme_bss_disable = 1;
3980 if ((offset + RSN_CAP_LEN) <= len) {
3981 rsn_cap = data[offset] + (data[offset + 1] << 8);
3982 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3983 wme_bss_disable = 0;
3984 }
3985 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003986 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003987 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003989 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003990 goto exit;
3991 }
3992 }
3993 /* FOR WPS , set SES_OW_ENABLED */
3994 wsec = (pval | gval | SES_OW_ENABLED);
3995
3996 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003997 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003998 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003999 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004000 goto exit;
4001 }
4002 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004003 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004004 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004005 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 goto exit;
4007 }
4008 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004009 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004010 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004011 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004012 goto exit;
4013 }
4014
4015exit:
4016 return err;
4017}
4018
4019static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004020brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004021 struct parsed_vndr_ies *vndr_ies)
4022{
Hante Meuleman1a873342012-09-27 14:17:54 +02004023 struct brcmf_vs_tlv *vndrie;
4024 struct brcmf_tlv *ie;
4025 struct parsed_vndr_ie_info *parsed_info;
4026 s32 remaining_len;
4027
4028 remaining_len = (s32)vndr_ie_len;
4029 memset(vndr_ies, 0, sizeof(*vndr_ies));
4030
4031 ie = (struct brcmf_tlv *)vndr_ie_buf;
4032 while (ie) {
4033 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4034 goto next;
4035 vndrie = (struct brcmf_vs_tlv *)ie;
4036 /* len should be bigger than OUI length + one */
4037 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004038 brcmf_err("invalid vndr ie. length is too small %d\n",
4039 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004040 goto next;
4041 }
4042 /* if wpa or wme ie, do not add ie */
4043 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4044 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4045 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004046 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004047 goto next;
4048 }
4049
4050 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4051
4052 /* save vndr ie information */
4053 parsed_info->ie_ptr = (char *)vndrie;
4054 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4055 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4056
4057 vndr_ies->count++;
4058
Arend van Sprield96b8012012-12-05 15:26:02 +01004059 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4060 parsed_info->vndrie.oui[0],
4061 parsed_info->vndrie.oui[1],
4062 parsed_info->vndrie.oui[2],
4063 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004064
Arend van Spriel9f440b72013-02-08 15:53:36 +01004065 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004066 break;
4067next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004068 remaining_len -= (ie->len + TLV_HDR_LEN);
4069 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004070 ie = NULL;
4071 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004072 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4073 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004074 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004075 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004076}
4077
4078static u32
4079brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4080{
4081
Hante Meuleman1a873342012-09-27 14:17:54 +02004082 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4083 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4084
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304085 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004086
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304087 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004088
4089 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4090
4091 return ie_len + VNDR_IE_HDR_SIZE;
4092}
4093
Arend van Spriel1332e262012-11-05 16:22:18 -08004094s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4095 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004096{
Arend van Spriel1332e262012-11-05 16:22:18 -08004097 struct brcmf_if *ifp;
4098 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004099 s32 err = 0;
4100 u8 *iovar_ie_buf;
4101 u8 *curr_ie_buf;
4102 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004103 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004104 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004105 u32 del_add_ie_buf_len = 0;
4106 u32 total_ie_buf_len = 0;
4107 u32 parsed_ie_buf_len = 0;
4108 struct parsed_vndr_ies old_vndr_ies;
4109 struct parsed_vndr_ies new_vndr_ies;
4110 struct parsed_vndr_ie_info *vndrie_info;
4111 s32 i;
4112 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004113 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004114
Arend van Spriel1332e262012-11-05 16:22:18 -08004115 if (!vif)
4116 return -ENODEV;
4117 ifp = vif->ifp;
4118 saved_ie = &vif->saved_ie;
4119
Hante Meuleman37a869e2015-10-29 20:33:17 +01004120 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4121 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004122 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4123 if (!iovar_ie_buf)
4124 return -ENOMEM;
4125 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004126 switch (pktflag) {
4127 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4128 mgmt_ie_buf = saved_ie->probe_req_ie;
4129 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4130 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4131 break;
4132 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4133 mgmt_ie_buf = saved_ie->probe_res_ie;
4134 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4135 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4136 break;
4137 case BRCMF_VNDR_IE_BEACON_FLAG:
4138 mgmt_ie_buf = saved_ie->beacon_ie;
4139 mgmt_ie_len = &saved_ie->beacon_ie_len;
4140 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4141 break;
4142 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4143 mgmt_ie_buf = saved_ie->assoc_req_ie;
4144 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4145 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4146 break;
4147 default:
4148 err = -EPERM;
4149 brcmf_err("not suitable type\n");
4150 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004151 }
4152
4153 if (vndr_ie_len > mgmt_ie_buf_len) {
4154 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004155 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004156 goto exit;
4157 }
4158
4159 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4160 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4161 ptr = curr_ie_buf;
4162 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4163 for (i = 0; i < new_vndr_ies.count; i++) {
4164 vndrie_info = &new_vndr_ies.ie_info[i];
4165 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4166 vndrie_info->ie_len);
4167 parsed_ie_buf_len += vndrie_info->ie_len;
4168 }
4169 }
4170
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004171 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004172 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4173 (memcmp(mgmt_ie_buf, curr_ie_buf,
4174 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004175 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004176 goto exit;
4177 }
4178
4179 /* parse old vndr_ie */
4180 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4181
4182 /* make a command to delete old ie */
4183 for (i = 0; i < old_vndr_ies.count; i++) {
4184 vndrie_info = &old_vndr_ies.ie_info[i];
4185
Arend van Sprield96b8012012-12-05 15:26:02 +01004186 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4187 vndrie_info->vndrie.id,
4188 vndrie_info->vndrie.len,
4189 vndrie_info->vndrie.oui[0],
4190 vndrie_info->vndrie.oui[1],
4191 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004192
4193 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4194 vndrie_info->ie_ptr,
4195 vndrie_info->ie_len,
4196 "del");
4197 curr_ie_buf += del_add_ie_buf_len;
4198 total_ie_buf_len += del_add_ie_buf_len;
4199 }
4200 }
4201
4202 *mgmt_ie_len = 0;
4203 /* Add if there is any extra IE */
4204 if (mgmt_ie_buf && parsed_ie_buf_len) {
4205 ptr = mgmt_ie_buf;
4206
4207 remained_buf_len = mgmt_ie_buf_len;
4208
4209 /* make a command to add new ie */
4210 for (i = 0; i < new_vndr_ies.count; i++) {
4211 vndrie_info = &new_vndr_ies.ie_info[i];
4212
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004213 /* verify remained buf size before copy data */
4214 if (remained_buf_len < (vndrie_info->vndrie.len +
4215 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004216 brcmf_err("no space in mgmt_ie_buf: len left %d",
4217 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004218 break;
4219 }
4220 remained_buf_len -= (vndrie_info->ie_len +
4221 VNDR_IE_VSIE_OFFSET);
4222
Arend van Sprield96b8012012-12-05 15:26:02 +01004223 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4224 vndrie_info->vndrie.id,
4225 vndrie_info->vndrie.len,
4226 vndrie_info->vndrie.oui[0],
4227 vndrie_info->vndrie.oui[1],
4228 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004229
4230 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4231 vndrie_info->ie_ptr,
4232 vndrie_info->ie_len,
4233 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004234
4235 /* save the parsed IE in wl struct */
4236 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4237 vndrie_info->ie_len);
4238 *mgmt_ie_len += vndrie_info->ie_len;
4239
4240 curr_ie_buf += del_add_ie_buf_len;
4241 total_ie_buf_len += del_add_ie_buf_len;
4242 }
4243 }
4244 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004245 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004246 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004247 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004248 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004249 }
4250
4251exit:
4252 kfree(iovar_ie_buf);
4253 return err;
4254}
4255
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004256s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4257{
4258 s32 pktflags[] = {
4259 BRCMF_VNDR_IE_PRBREQ_FLAG,
4260 BRCMF_VNDR_IE_PRBRSP_FLAG,
4261 BRCMF_VNDR_IE_BEACON_FLAG
4262 };
4263 int i;
4264
4265 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4266 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4267
4268 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4269 return 0;
4270}
4271
Hante Meuleman1a873342012-09-27 14:17:54 +02004272static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004273brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4274 struct cfg80211_beacon_data *beacon)
4275{
4276 s32 err;
4277
4278 /* Set Beacon IEs to FW */
4279 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4280 beacon->tail, beacon->tail_len);
4281 if (err) {
4282 brcmf_err("Set Beacon IE Failed\n");
4283 return err;
4284 }
4285 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4286
4287 /* Set Probe Response IEs to FW */
4288 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4289 beacon->proberesp_ies,
4290 beacon->proberesp_ies_len);
4291 if (err)
4292 brcmf_err("Set Probe Resp IE Failed\n");
4293 else
4294 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4295
4296 return err;
4297}
4298
4299static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004300brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4301 struct cfg80211_ap_settings *settings)
4302{
4303 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004304 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004305 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004306 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004307 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004308 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004309 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004310 const struct brcmf_tlv *rsn_ie;
4311 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004312 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004313 enum nl80211_iftype dev_role;
4314 struct brcmf_fil_bss_enable_le bss_enable;
Arend van Spriel06c01582014-05-12 10:47:37 +02004315 u16 chanspec;
Hante Meulemana44aa402014-12-03 21:05:33 +01004316 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004317 int is_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004318
Arend van Spriel06c01582014-05-12 10:47:37 +02004319 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4320 settings->chandef.chan->hw_value,
4321 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004322 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004323 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4324 settings->ssid, settings->ssid_len, settings->auth_type,
4325 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004326 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004327 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004328
Arend van Spriel98027762014-12-21 12:43:53 +01004329 /* store current 11d setting */
4330 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4331 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4332 settings->beacon.tail_len,
4333 WLAN_EID_COUNTRY);
4334 is_11d = country_ie ? 1 : 0;
4335
Hante Meuleman1a873342012-09-27 14:17:54 +02004336 memset(&ssid_le, 0, sizeof(ssid_le));
4337 if (settings->ssid == NULL || settings->ssid_len == 0) {
4338 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4339 ssid_ie = brcmf_parse_tlvs(
4340 (u8 *)&settings->beacon.head[ie_offset],
4341 settings->beacon.head_len - ie_offset,
4342 WLAN_EID_SSID);
4343 if (!ssid_ie)
4344 return -EINVAL;
4345
4346 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4347 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004348 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004349 } else {
4350 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4351 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4352 }
4353
Hante Meulemana44aa402014-12-03 21:05:33 +01004354 if (!mbss) {
4355 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004356 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004357 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004358
4359 /* find the RSN_IE */
4360 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4361 settings->beacon.tail_len, WLAN_EID_RSN);
4362
4363 /* find the WPA_IE */
4364 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4365 settings->beacon.tail_len);
4366
Hante Meuleman1a873342012-09-27 14:17:54 +02004367 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004368 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004369 if (wpa_ie != NULL) {
4370 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004371 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004372 if (err < 0)
4373 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004374 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004375 struct brcmf_vs_tlv *tmp_ie;
4376
4377 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4378
Hante Meuleman1a873342012-09-27 14:17:54 +02004379 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004380 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004381 if (err < 0)
4382 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004383 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004384 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004385 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004386 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004387 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004388
Hante Meulemana0f07952013-02-08 15:53:47 +01004389 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004390
Hante Meulemana44aa402014-12-03 21:05:33 +01004391 if (!mbss) {
4392 chanspec = chandef_to_chanspec(&cfg->d11inf,
4393 &settings->chandef);
4394 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004395 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004396 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4397 chanspec, err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004398 goto exit;
4399 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004400
Arend van Spriel98027762014-12-21 12:43:53 +01004401 if (is_11d != ifp->vif->is_11d) {
4402 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4403 is_11d);
4404 if (err < 0) {
4405 brcmf_err("Regulatory Set Error, %d\n", err);
4406 goto exit;
4407 }
4408 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004409 if (settings->beacon_interval) {
4410 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4411 settings->beacon_interval);
4412 if (err < 0) {
4413 brcmf_err("Beacon Interval Set Error, %d\n",
4414 err);
4415 goto exit;
4416 }
4417 }
4418 if (settings->dtim_period) {
4419 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4420 settings->dtim_period);
4421 if (err < 0) {
4422 brcmf_err("DTIM Interval Set Error, %d\n", err);
4423 goto exit;
4424 }
4425 }
4426
Hante Meuleman8abffd82015-10-29 20:33:16 +01004427 if ((dev_role == NL80211_IFTYPE_AP) &&
4428 ((ifp->ifidx == 0) ||
4429 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004430 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4431 if (err < 0) {
4432 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4433 goto exit;
4434 }
4435 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4436 }
4437
4438 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004439 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004440 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004441 goto exit;
4442 }
Arend van Spriel98027762014-12-21 12:43:53 +01004443 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4444 /* Multiple-BSS should use same 11d configuration */
4445 err = -EINVAL;
4446 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004447 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004448 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004449 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4450 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4451
Hante Meulemana0f07952013-02-08 15:53:47 +01004452 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4453 if (err < 0) {
4454 brcmf_err("setting AP mode failed %d\n", err);
4455 goto exit;
4456 }
4457 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4458 if (err < 0) {
4459 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4460 goto exit;
4461 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004462 /* On DOWN the firmware removes the WEP keys, reconfigure
4463 * them if they were set.
4464 */
4465 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004466
4467 memset(&join_params, 0, sizeof(join_params));
4468 /* join parameters starts with ssid */
4469 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4470 /* create softap */
4471 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4472 &join_params, sizeof(join_params));
4473 if (err < 0) {
4474 brcmf_err("SET SSID error (%d)\n", err);
4475 goto exit;
4476 }
4477 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4478 } else {
4479 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4480 sizeof(ssid_le));
4481 if (err < 0) {
4482 brcmf_err("setting ssid failed %d\n", err);
4483 goto exit;
4484 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004485 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004486 bss_enable.enable = cpu_to_le32(1);
4487 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4488 sizeof(bss_enable));
4489 if (err < 0) {
4490 brcmf_err("bss_enable config failed %d\n", err);
4491 goto exit;
4492 }
4493
4494 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4495 }
Arend van Sprielc1179032012-10-22 13:55:33 -07004496 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004497 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004498
4499exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004500 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004501 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004502 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004503 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004504 return err;
4505}
4506
4507static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4508{
Arend van Sprielc1179032012-10-22 13:55:33 -07004509 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004510 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004511 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004512 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004513
Arend van Sprield96b8012012-12-05 15:26:02 +01004514 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004515
Hante Meuleman426d0a52013-02-08 15:53:53 +01004516 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004517 /* Due to most likely deauths outstanding we sleep */
4518 /* first to make sure they get processed by fw. */
4519 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004520
Hante Meulemana44aa402014-12-03 21:05:33 +01004521 if (ifp->vif->mbss) {
4522 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4523 return err;
4524 }
4525
Hante Meuleman5c33a942013-04-02 21:06:18 +02004526 memset(&join_params, 0, sizeof(join_params));
4527 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4528 &join_params, sizeof(join_params));
4529 if (err < 0)
4530 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004531 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004532 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004533 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004534 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4535 if (err < 0)
4536 brcmf_err("setting AP mode failed %d\n", err);
4537 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4538 if (err < 0)
4539 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004540 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4541 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Arend van Spriel98027762014-12-21 12:43:53 +01004542 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4543 ifp->vif->is_11d);
4544 if (err < 0)
4545 brcmf_err("restoring REGULATORY setting failed %d\n",
4546 err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004547 /* Bring device back up so it can be used again */
4548 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4549 if (err < 0)
4550 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004551 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004552 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004553 bss_enable.enable = cpu_to_le32(0);
4554 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4555 sizeof(bss_enable));
4556 if (err < 0)
4557 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004558 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004559 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004560 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004561 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004562 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004563
Hante Meuleman1a873342012-09-27 14:17:54 +02004564 return err;
4565}
4566
Hante Meulemana0f07952013-02-08 15:53:47 +01004567static s32
4568brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4569 struct cfg80211_beacon_data *info)
4570{
Hante Meulemana0f07952013-02-08 15:53:47 +01004571 struct brcmf_if *ifp = netdev_priv(ndev);
4572 s32 err;
4573
4574 brcmf_dbg(TRACE, "Enter\n");
4575
Hante Meulemana0f07952013-02-08 15:53:47 +01004576 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4577
4578 return err;
4579}
4580
Hante Meuleman1a873342012-09-27 14:17:54 +02004581static int
4582brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004583 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004584{
Hante Meulemana0f07952013-02-08 15:53:47 +01004585 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004586 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004587 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004588 s32 err;
4589
Jouni Malinen89c771e2014-10-10 20:52:40 +03004590 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004591 return -EFAULT;
4592
Jouni Malinen89c771e2014-10-10 20:52:40 +03004593 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004594
Hante Meulemana0f07952013-02-08 15:53:47 +01004595 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4596 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004597 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004598 return -EIO;
4599
Jouni Malinen89c771e2014-10-10 20:52:40 +03004600 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004601 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004602 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004603 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004604 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004605 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004606
Arend van Sprield96b8012012-12-05 15:26:02 +01004607 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004608 return err;
4609}
4610
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004611static int
4612brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4613 const u8 *mac, struct station_parameters *params)
4614{
4615 struct brcmf_if *ifp = netdev_priv(ndev);
4616 s32 err;
4617
4618 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4619 params->sta_flags_mask, params->sta_flags_set);
4620
4621 /* Ignore all 00 MAC */
4622 if (is_zero_ether_addr(mac))
4623 return 0;
4624
4625 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4626 return 0;
4627
4628 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4629 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4630 (void *)mac, ETH_ALEN);
4631 else
4632 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4633 (void *)mac, ETH_ALEN);
4634 if (err < 0)
4635 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4636
4637 return err;
4638}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004639
4640static void
4641brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4642 struct wireless_dev *wdev,
4643 u16 frame_type, bool reg)
4644{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004645 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004646 u16 mgmt_type;
4647
4648 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4649
4650 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004651 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004652 if (reg)
4653 vif->mgmt_rx_reg |= BIT(mgmt_type);
4654 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004655 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004656}
4657
4658
4659static int
4660brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004661 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004662{
4663 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004664 struct ieee80211_channel *chan = params->chan;
4665 const u8 *buf = params->buf;
4666 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004667 const struct ieee80211_mgmt *mgmt;
4668 struct brcmf_cfg80211_vif *vif;
4669 s32 err = 0;
4670 s32 ie_offset;
4671 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004672 struct brcmf_fil_action_frame_le *action_frame;
4673 struct brcmf_fil_af_params_le *af_params;
4674 bool ack;
4675 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004676 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004677
4678 brcmf_dbg(TRACE, "Enter\n");
4679
4680 *cookie = 0;
4681
4682 mgmt = (const struct ieee80211_mgmt *)buf;
4683
Hante Meulemana0f07952013-02-08 15:53:47 +01004684 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4685 brcmf_err("Driver only allows MGMT packet type\n");
4686 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004687 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004688
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004689 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4690
Hante Meulemana0f07952013-02-08 15:53:47 +01004691 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4692 /* Right now the only reason to get a probe response */
4693 /* is for p2p listen response or for p2p GO from */
4694 /* wpa_supplicant. Unfortunately the probe is send */
4695 /* on primary ndev, while dongle wants it on the p2p */
4696 /* vif. Since this is only reason for a probe */
4697 /* response to be sent, the vif is taken from cfg. */
4698 /* If ever desired to send proberesp for non p2p */
4699 /* response then data should be checked for */
4700 /* "DIRECT-". Note in future supplicant will take */
4701 /* dedicated p2p wdev to do this and then this 'hack'*/
4702 /* is not needed anymore. */
4703 ie_offset = DOT11_MGMT_HDR_LEN +
4704 DOT11_BCN_PRB_FIXED_LEN;
4705 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004706 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4707 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4708 err = brcmf_vif_set_mgmt_ie(vif,
4709 BRCMF_VNDR_IE_PRBRSP_FLAG,
4710 &buf[ie_offset],
4711 ie_len);
4712 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4713 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004714 } else if (ieee80211_is_action(mgmt->frame_control)) {
4715 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4716 if (af_params == NULL) {
4717 brcmf_err("unable to allocate frame\n");
4718 err = -ENOMEM;
4719 goto exit;
4720 }
4721 action_frame = &af_params->action_frame;
4722 /* Add the packet Id */
4723 action_frame->packet_id = cpu_to_le32(*cookie);
4724 /* Add BSSID */
4725 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4726 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4727 /* Add the length exepted for 802.11 header */
4728 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004729 /* Add the channel. Use the one specified as parameter if any or
4730 * the current one (got from the firmware) otherwise
4731 */
4732 if (chan)
4733 freq = chan->center_freq;
4734 else
4735 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4736 &freq);
4737 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004738 af_params->channel = cpu_to_le32(chan_nr);
4739
4740 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4741 le16_to_cpu(action_frame->len));
4742
4743 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004744 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004745
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004746 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004747 af_params);
4748
4749 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4750 GFP_KERNEL);
4751 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004752 } else {
4753 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4754 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4755 }
4756
Hante Meuleman18e2f612013-02-08 15:53:49 +01004757exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004758 return err;
4759}
4760
4761
4762static int
4763brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4764 struct wireless_dev *wdev,
4765 u64 cookie)
4766{
4767 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4768 struct brcmf_cfg80211_vif *vif;
4769 int err = 0;
4770
4771 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4772
4773 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4774 if (vif == NULL) {
4775 brcmf_err("No p2p device available for probe response\n");
4776 err = -ENODEV;
4777 goto exit;
4778 }
4779 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4780exit:
4781 return err;
4782}
4783
Piotr Haber61730d42013-04-23 12:53:12 +02004784static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4785 struct wireless_dev *wdev,
4786 enum nl80211_crit_proto_id proto,
4787 u16 duration)
4788{
4789 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4790 struct brcmf_cfg80211_vif *vif;
4791
4792 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4793
4794 /* only DHCP support for now */
4795 if (proto != NL80211_CRIT_PROTO_DHCP)
4796 return -EINVAL;
4797
4798 /* suppress and abort scanning */
4799 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4800 brcmf_abort_scanning(cfg);
4801
4802 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4803}
4804
4805static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4806 struct wireless_dev *wdev)
4807{
4808 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4809 struct brcmf_cfg80211_vif *vif;
4810
4811 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4812
4813 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4814 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4815}
4816
Hante Meuleman70b7d942014-07-30 13:20:07 +02004817static s32
4818brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4819 const struct brcmf_event_msg *e, void *data)
4820{
4821 switch (e->reason) {
4822 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4823 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4824 break;
4825 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4826 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4827 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4828 break;
4829 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4830 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4831 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4832 break;
4833 }
4834
4835 return 0;
4836}
4837
Arend van Spriel89c2f382013-08-10 12:27:25 +02004838static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4839{
4840 int ret;
4841
4842 switch (oper) {
4843 case NL80211_TDLS_DISCOVERY_REQ:
4844 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4845 break;
4846 case NL80211_TDLS_SETUP:
4847 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4848 break;
4849 case NL80211_TDLS_TEARDOWN:
4850 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4851 break;
4852 default:
4853 brcmf_err("unsupported operation: %d\n", oper);
4854 ret = -EOPNOTSUPP;
4855 }
4856 return ret;
4857}
4858
4859static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02004860 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004861 enum nl80211_tdls_operation oper)
4862{
4863 struct brcmf_if *ifp;
4864 struct brcmf_tdls_iovar_le info;
4865 int ret = 0;
4866
4867 ret = brcmf_convert_nl80211_tdls_oper(oper);
4868 if (ret < 0)
4869 return ret;
4870
4871 ifp = netdev_priv(ndev);
4872 memset(&info, 0, sizeof(info));
4873 info.mode = (u8)ret;
4874 if (peer)
4875 memcpy(info.ea, peer, ETH_ALEN);
4876
4877 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4878 &info, sizeof(info));
4879 if (ret < 0)
4880 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4881
4882 return ret;
4883}
4884
Hante Meuleman5c22fb82016-02-17 11:27:03 +01004885#ifdef CONFIG_PM
4886static int
4887brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
4888 struct cfg80211_gtk_rekey_data *gtk)
4889{
4890 struct brcmf_if *ifp = netdev_priv(ndev);
4891 struct brcmf_gtk_keyinfo_le gtk_le;
4892 int ret;
4893
4894 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
4895
4896 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
4897 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
4898 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
4899 sizeof(gtk_le.replay_counter));
4900
4901 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
4902 sizeof(gtk_le));
4903 if (ret < 0)
4904 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
4905
4906 return ret;
4907}
4908#endif
4909
4910static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004911 .add_virtual_intf = brcmf_cfg80211_add_iface,
4912 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004913 .change_virtual_intf = brcmf_cfg80211_change_iface,
4914 .scan = brcmf_cfg80211_scan,
4915 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4916 .join_ibss = brcmf_cfg80211_join_ibss,
4917 .leave_ibss = brcmf_cfg80211_leave_ibss,
4918 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02004919 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004920 .set_tx_power = brcmf_cfg80211_set_tx_power,
4921 .get_tx_power = brcmf_cfg80211_get_tx_power,
4922 .add_key = brcmf_cfg80211_add_key,
4923 .del_key = brcmf_cfg80211_del_key,
4924 .get_key = brcmf_cfg80211_get_key,
4925 .set_default_key = brcmf_cfg80211_config_default_key,
4926 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4927 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004928 .connect = brcmf_cfg80211_connect,
4929 .disconnect = brcmf_cfg80211_disconnect,
4930 .suspend = brcmf_cfg80211_suspend,
4931 .resume = brcmf_cfg80211_resume,
4932 .set_pmksa = brcmf_cfg80211_set_pmksa,
4933 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004934 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004935 .start_ap = brcmf_cfg80211_start_ap,
4936 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004937 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004938 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004939 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004940 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4941 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004942 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4943 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4944 .remain_on_channel = brcmf_p2p_remain_on_channel,
4945 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004946 .start_p2p_device = brcmf_p2p_start_device,
4947 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004948 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4949 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004950 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004951};
4952
Arend van Spriel3eacf862012-10-22 13:55:30 -07004953struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004954 enum nl80211_iftype type,
4955 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004956{
Hante Meulemana44aa402014-12-03 21:05:33 +01004957 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004958 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01004959 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004960
Arend van Spriel33a6b152013-02-08 15:53:39 +01004961 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004962 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004963 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4964 if (!vif)
4965 return ERR_PTR(-ENOMEM);
4966
4967 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004968 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004969
Arend van Spriel3eacf862012-10-22 13:55:30 -07004970 vif->pm_block = pm_block;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004971
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004972 brcmf_init_prof(&vif->profile);
4973
Hante Meulemana44aa402014-12-03 21:05:33 +01004974 if (type == NL80211_IFTYPE_AP) {
4975 mbss = false;
4976 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
4977 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
4978 mbss = true;
4979 break;
4980 }
4981 }
4982 vif->mbss = mbss;
4983 }
4984
Arend van Spriel3eacf862012-10-22 13:55:30 -07004985 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004986 return vif;
4987}
4988
Arend van Spriel427dec52014-01-06 12:40:47 +01004989void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004990{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004991 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004992 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004993}
4994
Arend van Spriel9df4d542014-01-06 12:40:49 +01004995void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4996{
4997 struct brcmf_cfg80211_vif *vif;
4998 struct brcmf_if *ifp;
4999
5000 ifp = netdev_priv(ndev);
5001 vif = ifp->vif;
5002
Arend van Spriel95ef1232015-08-26 22:15:04 +02005003 if (vif)
5004 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005005 free_netdev(ndev);
5006}
5007
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005008static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005009{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005010 u32 event = e->event_code;
5011 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005012
5013 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005014 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005015 return true;
5016 }
5017
5018 return false;
5019}
5020
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005021static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005022{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005023 u32 event = e->event_code;
5024 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005025
Hante Meuleman68ca3952014-02-25 20:30:26 +01005026 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5027 (event == BRCMF_E_DISASSOC_IND) ||
5028 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005029 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005030 return true;
5031 }
5032 return false;
5033}
5034
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005035static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005036 const struct brcmf_event_msg *e)
5037{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005038 u32 event = e->event_code;
5039 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005040
5041 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005042 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5043 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005044 return true;
5045 }
5046
5047 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005048 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005049 return true;
5050 }
5051
5052 return false;
5053}
5054
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005055static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005056{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005057 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005058
5059 kfree(conn_info->req_ie);
5060 conn_info->req_ie = NULL;
5061 conn_info->req_ie_len = 0;
5062 kfree(conn_info->resp_ie);
5063 conn_info->resp_ie = NULL;
5064 conn_info->resp_ie_len = 0;
5065}
5066
Hante Meuleman89286dc2013-02-08 15:53:46 +01005067static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5068 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005069{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005070 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005071 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005072 u32 req_len;
5073 u32 resp_len;
5074 s32 err = 0;
5075
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005076 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005077
Arend van Sprielac24be62012-10-22 10:36:23 -07005078 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5079 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005080 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005081 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005082 return err;
5083 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005084 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005085 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005086 req_len = le32_to_cpu(assoc_info->req_len);
5087 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005088 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005089 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005090 cfg->extra_buf,
5091 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005092 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005093 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005094 return err;
5095 }
5096 conn_info->req_ie_len = req_len;
5097 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005098 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005099 GFP_KERNEL);
5100 } else {
5101 conn_info->req_ie_len = 0;
5102 conn_info->req_ie = NULL;
5103 }
5104 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005105 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005106 cfg->extra_buf,
5107 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005108 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005109 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005110 return err;
5111 }
5112 conn_info->resp_ie_len = resp_len;
5113 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005114 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005115 GFP_KERNEL);
5116 } else {
5117 conn_info->resp_ie_len = 0;
5118 conn_info->resp_ie = NULL;
5119 }
Arend van Spriel16886732012-12-05 15:26:04 +01005120 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5121 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005122
5123 return err;
5124}
5125
5126static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005127brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005128 struct net_device *ndev,
5129 const struct brcmf_event_msg *e)
5130{
Arend van Sprielc1179032012-10-22 13:55:33 -07005131 struct brcmf_if *ifp = netdev_priv(ndev);
5132 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005133 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5134 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005135 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005136 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005137 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005138 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005139 u32 freq;
5140 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005141 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005142
Arend van Sprield96b8012012-12-05 15:26:02 +01005143 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005144
Hante Meuleman89286dc2013-02-08 15:53:46 +01005145 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005146 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005147 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005148
Franky Lina180b832012-10-10 11:13:09 -07005149 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5150 if (buf == NULL) {
5151 err = -ENOMEM;
5152 goto done;
5153 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005154
Franky Lina180b832012-10-10 11:13:09 -07005155 /* data sent to dongle has to be little endian */
5156 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005157 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005158 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005159
5160 if (err)
5161 goto done;
5162
5163 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005164 ch.chspec = le16_to_cpu(bi->chanspec);
5165 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005166
Franky Lin83cf17a2013-04-11 13:28:50 +02005167 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005168 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5169 else
5170 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5171
Franky Lin83cf17a2013-04-11 13:28:50 +02005172 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005173 notify_channel = ieee80211_get_channel(wiphy, freq);
5174
Franky Lina180b832012-10-10 11:13:09 -07005175done:
5176 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005177 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005178 conn_info->req_ie, conn_info->req_ie_len,
5179 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005180 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005181
Arend van Sprielc1179032012-10-22 13:55:33 -07005182 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005183 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005184 return err;
5185}
5186
5187static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005188brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005189 struct net_device *ndev, const struct brcmf_event_msg *e,
5190 bool completed)
5191{
Arend van Sprielc1179032012-10-22 13:55:33 -07005192 struct brcmf_if *ifp = netdev_priv(ndev);
5193 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005194 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005195
Arend van Sprield96b8012012-12-05 15:26:02 +01005196 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005197
Arend van Sprielc1179032012-10-22 13:55:33 -07005198 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5199 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005200 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005201 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005202 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005203 brcmf_update_bss_info(cfg, ifp);
5204 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5205 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005206 }
5207 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005208 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005209 conn_info->req_ie,
5210 conn_info->req_ie_len,
5211 conn_info->resp_ie,
5212 conn_info->resp_ie_len,
5213 completed ? WLAN_STATUS_SUCCESS :
5214 WLAN_STATUS_AUTH_TIMEOUT,
5215 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005216 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5217 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005218 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005219 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005220 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005221}
5222
5223static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005224brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005225 struct net_device *ndev,
5226 const struct brcmf_event_msg *e, void *data)
5227{
Hante Meulemana44aa402014-12-03 21:05:33 +01005228 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman7ee29602013-02-06 18:40:43 +01005229 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005230 u32 event = e->event_code;
5231 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005232 struct station_info sinfo;
5233
Arend van Spriel16886732012-12-05 15:26:04 +01005234 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005235 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5236 ndev != cfg_to_ndev(cfg)) {
5237 brcmf_dbg(CONN, "AP mode link down\n");
5238 complete(&cfg->vif_disabled);
Hante Meulemana44aa402014-12-03 21:05:33 +01005239 if (ifp->vif->mbss)
Arend van Sprielee6e3a32015-08-26 22:14:55 +02005240 brcmf_remove_interface(ifp);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005241 return 0;
5242 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005243
Hante Meuleman1a873342012-09-27 14:17:54 +02005244 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005245 (reason == BRCMF_E_STATUS_SUCCESS)) {
5246 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005247 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005248 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005249 return -EINVAL;
5250 }
5251 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005252 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005253 generation++;
5254 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005255 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005256 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5257 (event == BRCMF_E_DEAUTH_IND) ||
5258 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005259 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005260 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005261 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005262}
5263
5264static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005265brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005266 const struct brcmf_event_msg *e, void *data)
5267{
Arend van Spriel19937322012-11-05 16:22:32 -08005268 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5269 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005270 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005271 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005272 s32 err = 0;
5273
Hante Meuleman8851cce2014-07-30 13:20:02 +02005274 if ((e->event_code == BRCMF_E_DEAUTH) ||
5275 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5276 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5277 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5278 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5279 }
5280
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005281 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005282 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005283 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005284 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005285 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005286 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005287 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005288 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005289 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005290 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5291 &ifp->vif->sme_state);
5292 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5293 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005294 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005295 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005296 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005297 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005298 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005299 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005300 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005301 brcmf_link_down(ifp->vif,
5302 brcmf_map_fw_linkdown_reason(e));
5303 brcmf_init_prof(ndev_to_prof(ndev));
5304 if (ndev != cfg_to_ndev(cfg))
5305 complete(&cfg->vif_disabled);
5306 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005307 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005308 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005309 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005310 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5311 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005312 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005313 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005314 }
5315
5316 return err;
5317}
5318
5319static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005320brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005321 const struct brcmf_event_msg *e, void *data)
5322{
Arend van Spriel19937322012-11-05 16:22:32 -08005323 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005324 u32 event = e->event_code;
5325 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005326
5327 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005328 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005329 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005330 else
Arend van Spriel19937322012-11-05 16:22:32 -08005331 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005332 }
5333
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005334 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005335}
5336
5337static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005338brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005339 const struct brcmf_event_msg *e, void *data)
5340{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005341 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005342 enum nl80211_key_type key_type;
5343
5344 if (flags & BRCMF_EVENT_MSG_GROUP)
5345 key_type = NL80211_KEYTYPE_GROUP;
5346 else
5347 key_type = NL80211_KEYTYPE_PAIRWISE;
5348
Arend van Spriel19937322012-11-05 16:22:32 -08005349 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005350 NULL, GFP_KERNEL);
5351
5352 return 0;
5353}
5354
Arend van Sprield3c0b632013-02-08 15:53:37 +01005355static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5356 const struct brcmf_event_msg *e, void *data)
5357{
5358 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5359 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5360 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5361 struct brcmf_cfg80211_vif *vif;
5362
Hante Meuleman37a869e2015-10-29 20:33:17 +01005363 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005364 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005365 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005366
Arend van Sprield3c0b632013-02-08 15:53:37 +01005367 mutex_lock(&event->vif_event_lock);
5368 event->action = ifevent->action;
5369 vif = event->vif;
5370
5371 switch (ifevent->action) {
5372 case BRCMF_E_IF_ADD:
5373 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005374 if (!cfg->vif_event.vif) {
5375 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005376 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005377 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005378
5379 ifp->vif = vif;
5380 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005381 if (ifp->ndev) {
5382 vif->wdev.netdev = ifp->ndev;
5383 ifp->ndev->ieee80211_ptr = &vif->wdev;
5384 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5385 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005386 mutex_unlock(&event->vif_event_lock);
5387 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005388 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005389
5390 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005391 mutex_unlock(&event->vif_event_lock);
5392 /* event may not be upon user request */
5393 if (brcmf_cfg80211_vif_event_armed(cfg))
5394 wake_up(&event->vif_wq);
5395 return 0;
5396
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005397 case BRCMF_E_IF_CHANGE:
5398 mutex_unlock(&event->vif_event_lock);
5399 wake_up(&event->vif_wq);
5400 return 0;
5401
Arend van Sprield3c0b632013-02-08 15:53:37 +01005402 default:
5403 mutex_unlock(&event->vif_event_lock);
5404 break;
5405 }
5406 return -EINVAL;
5407}
5408
Arend van Spriel5b435de2011-10-05 13:19:03 +02005409static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5410{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005411 conf->frag_threshold = (u32)-1;
5412 conf->rts_threshold = (u32)-1;
5413 conf->retry_short = (u32)-1;
5414 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415}
5416
Arend van Spriel5c36b992012-11-14 18:46:05 -08005417static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005418{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005419 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5420 brcmf_notify_connect_status);
5421 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5422 brcmf_notify_connect_status);
5423 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5424 brcmf_notify_connect_status);
5425 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5426 brcmf_notify_connect_status);
5427 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5428 brcmf_notify_connect_status);
5429 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5430 brcmf_notify_connect_status);
5431 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5432 brcmf_notify_roaming_status);
5433 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5434 brcmf_notify_mic_status);
5435 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5436 brcmf_notify_connect_status);
5437 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5438 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005439 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5440 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005441 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005442 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005443 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5444 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005445 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5446 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005447 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5448 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005449 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5450 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005451}
5452
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005453static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005454{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005455 kfree(cfg->conf);
5456 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005457 kfree(cfg->extra_buf);
5458 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005459 kfree(cfg->wowl.nd);
5460 cfg->wowl.nd = NULL;
5461 kfree(cfg->wowl.nd_info);
5462 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005463 kfree(cfg->escan_info.escan_buf);
5464 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005465}
5466
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005467static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005468{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005469 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5470 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005471 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005472 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5473 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005474 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005475 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5476 if (!cfg->wowl.nd)
5477 goto init_priv_mem_out;
5478 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5479 sizeof(struct cfg80211_wowlan_nd_match *),
5480 GFP_KERNEL);
5481 if (!cfg->wowl.nd_info)
5482 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005483 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5484 if (!cfg->escan_info.escan_buf)
5485 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005486
5487 return 0;
5488
5489init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005490 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005491
5492 return -ENOMEM;
5493}
5494
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005495static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005496{
5497 s32 err = 0;
5498
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005499 cfg->scan_request = NULL;
5500 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005501 cfg->active_scan = true; /* we do active scan per default */
5502 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005503 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005504 if (err)
5505 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005506 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005507 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005508 brcmf_init_escan(cfg);
5509 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005510 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005511 return err;
5512}
5513
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005514static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005515{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005516 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005517 brcmf_abort_scanning(cfg);
5518 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005519}
5520
Arend van Sprield3c0b632013-02-08 15:53:37 +01005521static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5522{
5523 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005524 mutex_init(&event->vif_event_lock);
5525}
5526
Hante Meuleman1119e232015-11-25 11:32:42 +01005527static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005528{
Hante Meuleman1119e232015-11-25 11:32:42 +01005529 s32 err;
5530 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005531 __le32 roamtrigger[2];
5532 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005533
Hante Meuleman1119e232015-11-25 11:32:42 +01005534 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005535 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005536 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5537 else
5538 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5539 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5540 if (err) {
5541 brcmf_err("bcn_timeout error (%d)\n", err);
5542 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005543 }
5544
Hante Meuleman1119e232015-11-25 11:32:42 +01005545 /* Enable/Disable built-in roaming to allow supplicant to take care of
5546 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005547 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005548 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005549 ifp->drvr->settings->roamoff ? "Off" : "On");
5550 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5551 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005552 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005553 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005554 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005555 }
5556
Arend van Sprielf588bc02011-10-12 20:51:22 +02005557 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5558 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005559 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005560 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005561 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005562 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005563 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005564 }
5565
Arend van Sprielf588bc02011-10-12 20:51:22 +02005566 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5567 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005568 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005569 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005570 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005571 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005572 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005573 }
5574
Hante Meuleman1119e232015-11-25 11:32:42 +01005575roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005576 return err;
5577}
5578
5579static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005580brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005581{
5582 s32 err = 0;
5583
Arend van Sprielac24be62012-10-22 10:36:23 -07005584 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005585 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005586 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005587 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005588 goto dongle_scantime_out;
5589 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005590 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005591 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005592 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005593 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005594 goto dongle_scantime_out;
5595 }
5596
Arend van Sprielac24be62012-10-22 10:36:23 -07005597 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005598 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005599 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005600 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005601 goto dongle_scantime_out;
5602 }
5603
5604dongle_scantime_out:
5605 return err;
5606}
5607
Arend van Sprielb48d8912014-07-12 08:49:41 +02005608static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5609 struct brcmu_chan *ch)
5610{
5611 u32 ht40_flag;
5612
5613 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5614 if (ch->sb == BRCMU_CHAN_SB_U) {
5615 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5616 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5617 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5618 } else {
5619 /* It should be one of
5620 * IEEE80211_CHAN_NO_HT40 or
5621 * IEEE80211_CHAN_NO_HT40PLUS
5622 */
5623 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5624 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5625 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5626 }
5627}
5628
5629static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5630 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005631{
5632 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005633 struct ieee80211_supported_band *band;
5634 struct ieee80211_channel *channel;
5635 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005636 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005637 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005638 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005639 u8 *pbuf;
5640 u32 i, j;
5641 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005642 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005643 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005644
5645 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5646
5647 if (pbuf == NULL)
5648 return -ENOMEM;
5649
5650 list = (struct brcmf_chanspec_list *)pbuf;
5651
5652 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5653 BRCMF_DCMD_MEDLEN);
5654 if (err) {
5655 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005656 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005657 }
5658
Arend van Sprielb48d8912014-07-12 08:49:41 +02005659 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel58de92d2015-04-14 20:10:24 +02005660 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5661 if (band)
5662 for (i = 0; i < band->n_channels; i++)
5663 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5664 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5665 if (band)
5666 for (i = 0; i < band->n_channels; i++)
5667 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005668
5669 total = le32_to_cpu(list->count);
5670 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005671 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5672 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005673
Franky Lin83cf17a2013-04-11 13:28:50 +02005674 if (ch.band == BRCMU_CHAN_BAND_2G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005675 band = wiphy->bands[IEEE80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005676 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005677 band = wiphy->bands[IEEE80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005678 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005679 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005680 continue;
5681 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005682 if (!band)
5683 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005684 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005685 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005686 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005687 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005688 ch.bw == BRCMU_CHAN_BW_80)
5689 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005690
5691 channel = band->channels;
5692 index = band->n_channels;
5693 for (j = 0; j < band->n_channels; j++) {
5694 if (channel[j].hw_value == ch.chnum) {
5695 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005696 break;
5697 }
5698 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005699 channel[index].center_freq =
5700 ieee80211_channel_to_frequency(ch.chnum, band->band);
5701 channel[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005702
Arend van Sprielb48d8912014-07-12 08:49:41 +02005703 /* assuming the chanspecs order is HT20,
5704 * HT40 upper, HT40 lower, and VHT80.
5705 */
5706 if (ch.bw == BRCMU_CHAN_BW_80) {
5707 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5708 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5709 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5710 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005711 /* enable the channel and disable other bandwidths
5712 * for now as mentioned order assure they are enabled
5713 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005714 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005715 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5716 IEEE80211_CHAN_NO_80MHZ;
5717 ch.bw = BRCMU_CHAN_BW_20;
5718 cfg->d11inf.encchspec(&ch);
5719 chaninfo = ch.chspec;
5720 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5721 &chaninfo);
5722 if (!err) {
5723 if (chaninfo & WL_CHAN_RADAR)
5724 channel[index].flags |=
5725 (IEEE80211_CHAN_RADAR |
5726 IEEE80211_CHAN_NO_IR);
5727 if (chaninfo & WL_CHAN_PASSIVE)
5728 channel[index].flags |=
5729 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005730 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005731 }
5732 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005733
Arend van Sprielb48d8912014-07-12 08:49:41 +02005734fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005735 kfree(pbuf);
5736 return err;
5737}
5738
Arend van Sprielb48d8912014-07-12 08:49:41 +02005739static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005740{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005741 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5742 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005743 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005744 struct brcmf_chanspec_list *list;
5745 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005746 u32 val;
5747 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005748 struct brcmu_chan ch;
5749 u32 num_chan;
5750 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005751
5752 /* verify support for bw_cap command */
5753 val = WLC_BAND_5G;
5754 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5755
5756 if (!err) {
5757 /* only set 2G bandwidth using bw_cap command */
5758 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5759 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5760 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5761 sizeof(band_bwcap));
5762 } else {
5763 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5764 val = WLC_N_BW_40ALL;
5765 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5766 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005767
5768 if (!err) {
5769 /* update channel info in 2G band */
5770 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5771
5772 if (pbuf == NULL)
5773 return -ENOMEM;
5774
5775 ch.band = BRCMU_CHAN_BAND_2G;
5776 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005777 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005778 ch.chnum = 0;
5779 cfg->d11inf.encchspec(&ch);
5780
5781 /* pass encoded chanspec in query */
5782 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5783
5784 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5785 BRCMF_DCMD_MEDLEN);
5786 if (err) {
5787 brcmf_err("get chanspecs error (%d)\n", err);
5788 kfree(pbuf);
5789 return err;
5790 }
5791
5792 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5793 list = (struct brcmf_chanspec_list *)pbuf;
5794 num_chan = le32_to_cpu(list->count);
5795 for (i = 0; i < num_chan; i++) {
5796 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5797 cfg->d11inf.decchspec(&ch);
5798 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5799 continue;
5800 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5801 continue;
5802 for (j = 0; j < band->n_channels; j++) {
5803 if (band->channels[j].hw_value == ch.chnum)
5804 break;
5805 }
5806 if (WARN_ON(j == band->n_channels))
5807 continue;
5808
5809 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5810 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005811 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005812 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005813 return err;
5814}
5815
Arend van Spriel2375d972014-01-06 12:40:41 +01005816static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5817{
5818 u32 band, mimo_bwcap;
5819 int err;
5820
5821 band = WLC_BAND_2G;
5822 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5823 if (!err) {
5824 bw_cap[IEEE80211_BAND_2GHZ] = band;
5825 band = WLC_BAND_5G;
5826 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5827 if (!err) {
5828 bw_cap[IEEE80211_BAND_5GHZ] = band;
5829 return;
5830 }
5831 WARN_ON(1);
5832 return;
5833 }
5834 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5835 mimo_bwcap = 0;
5836 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5837 if (err)
5838 /* assume 20MHz if firmware does not give a clue */
5839 mimo_bwcap = WLC_N_BW_20ALL;
5840
5841 switch (mimo_bwcap) {
5842 case WLC_N_BW_40ALL:
5843 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5844 /* fall-thru */
5845 case WLC_N_BW_20IN2G_40IN5G:
5846 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5847 /* fall-thru */
5848 case WLC_N_BW_20ALL:
5849 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5850 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5851 break;
5852 default:
5853 brcmf_err("invalid mimo_bw_cap value\n");
5854 }
5855}
Hante Meulemand48200b2013-04-03 12:40:29 +02005856
Arend van Spriel18d6c532014-05-12 10:47:35 +02005857static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5858 u32 bw_cap[2], u32 nchain)
5859{
5860 band->ht_cap.ht_supported = true;
5861 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5862 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5863 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5864 }
5865 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5866 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5867 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5868 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5869 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5870 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5871}
5872
5873static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5874{
5875 u16 mcs_map;
5876 int i;
5877
5878 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5879 mcs_map = (mcs_map << 2) | supp;
5880
5881 return cpu_to_le16(mcs_map);
5882}
5883
5884static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005885 u32 bw_cap[2], u32 nchain, u32 txstreams,
5886 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02005887{
5888 __le16 mcs_map;
5889
5890 /* not allowed in 2.4G band */
5891 if (band->band == IEEE80211_BAND_2GHZ)
5892 return;
5893
5894 band->vht_cap.vht_supported = true;
5895 /* 80MHz is mandatory */
5896 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5897 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5898 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5899 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5900 }
5901 /* all support 256-QAM */
5902 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5903 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5904 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005905
5906 /* Beamforming support information */
5907 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
5908 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
5909 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
5910 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
5911 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
5912 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
5913 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
5914 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
5915
5916 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
5917 band->vht_cap.cap |=
5918 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
5919 band->vht_cap.cap |= ((txstreams - 1) <<
5920 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
5921 band->vht_cap.cap |=
5922 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
5923 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005924}
5925
Arend van Sprielb48d8912014-07-12 08:49:41 +02005926static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005927{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005928 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07005929 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02005930 u32 nmode = 0;
5931 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005932 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005933 u32 rxchain;
5934 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005935 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005936 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005937 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005938 u32 txstreams = 0;
5939 u32 txbf_bfe_cap = 0;
5940 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005941
Arend van Spriel18d6c532014-05-12 10:47:35 +02005942 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02005943 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5944 if (err) {
5945 brcmf_err("nmode error (%d)\n", err);
5946 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005947 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005948 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005949 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5950 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5951 bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005952
Daniel Kim4aca7a12014-02-25 20:30:36 +01005953 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5954 if (err) {
5955 brcmf_err("rxchain error (%d)\n", err);
5956 nchain = 1;
5957 } else {
5958 for (nchain = 0; rxchain; nchain++)
5959 rxchain = rxchain & (rxchain - 1);
5960 }
5961 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5962
Arend van Sprielb48d8912014-07-12 08:49:41 +02005963 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005964 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005965 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02005966 return err;
5967 }
5968
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005969 if (vhtmode) {
5970 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
5971 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
5972 &txbf_bfe_cap);
5973 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
5974 &txbf_bfr_cap);
5975 }
5976
Arend van Sprielb48d8912014-07-12 08:49:41 +02005977 wiphy = cfg_to_wiphy(cfg);
5978 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5979 band = wiphy->bands[i];
5980 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01005981 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005982
Arend van Spriel18d6c532014-05-12 10:47:35 +02005983 if (nmode)
5984 brcmf_update_ht_cap(band, bw_cap, nchain);
5985 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005986 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
5987 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005988 }
5989
Arend van Sprielb48d8912014-07-12 08:49:41 +02005990 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005991}
5992
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005993static const struct ieee80211_txrx_stypes
5994brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5995 [NL80211_IFTYPE_STATION] = {
5996 .tx = 0xffff,
5997 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5998 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5999 },
6000 [NL80211_IFTYPE_P2P_CLIENT] = {
6001 .tx = 0xffff,
6002 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6003 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6004 },
6005 [NL80211_IFTYPE_P2P_GO] = {
6006 .tx = 0xffff,
6007 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6008 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6009 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6010 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6011 BIT(IEEE80211_STYPE_AUTH >> 4) |
6012 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6013 BIT(IEEE80211_STYPE_ACTION >> 4)
6014 },
6015 [NL80211_IFTYPE_P2P_DEVICE] = {
6016 .tx = 0xffff,
6017 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6018 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6019 }
6020};
6021
Arend van Spriel0882dda2015-08-20 22:06:03 +02006022/**
6023 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6024 *
6025 * @wiphy: wiphy object.
6026 * @ifp: interface object needed for feat module api.
6027 *
6028 * The interface modes and combinations are determined dynamically here
6029 * based on firmware functionality.
6030 *
6031 * no p2p and no mbss:
6032 *
6033 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6034 *
6035 * no p2p and mbss:
6036 *
6037 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6038 * #AP <= 4, matching BI, channels = 1, 4 total
6039 *
6040 * p2p, no mchan, and mbss:
6041 *
6042 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6043 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6044 * #AP <= 4, matching BI, channels = 1, 4 total
6045 *
6046 * p2p, mchan, and mbss:
6047 *
6048 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6049 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6050 * #AP <= 4, matching BI, channels = 1, 4 total
6051 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006052static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6053{
6054 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006055 struct ieee80211_iface_limit *c0_limits = NULL;
6056 struct ieee80211_iface_limit *p2p_limits = NULL;
6057 struct ieee80211_iface_limit *mbss_limits = NULL;
6058 bool mbss, p2p;
6059 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006060
Arend van Spriel0882dda2015-08-20 22:06:03 +02006061 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6062 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6063
6064 n_combos = 1 + !!p2p + !!mbss;
6065 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006066 if (!combo)
6067 goto err;
6068
Arend van Spriel0882dda2015-08-20 22:06:03 +02006069 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6070 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006071 goto err;
6072
Arend van Spriel0882dda2015-08-20 22:06:03 +02006073 if (p2p) {
6074 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6075 if (!p2p_limits)
6076 goto err;
6077 }
6078
6079 if (mbss) {
6080 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6081 if (!mbss_limits)
6082 goto err;
6083 }
6084
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006085 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6086 BIT(NL80211_IFTYPE_ADHOC) |
6087 BIT(NL80211_IFTYPE_AP);
6088
Arend van Spriel0882dda2015-08-20 22:06:03 +02006089 c = 0;
6090 i = 0;
6091 combo[c].num_different_channels = 1;
6092 c0_limits[i].max = 1;
6093 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6094 if (p2p) {
6095 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6096 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006097 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6098 BIT(NL80211_IFTYPE_P2P_GO) |
6099 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006100 c0_limits[i].max = 1;
6101 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6102 c0_limits[i].max = 1;
6103 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6104 BIT(NL80211_IFTYPE_P2P_GO);
6105 } else {
6106 c0_limits[i].max = 1;
6107 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006108 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006109 combo[c].max_interfaces = i;
6110 combo[c].n_limits = i;
6111 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006112
Arend van Spriel0882dda2015-08-20 22:06:03 +02006113 if (p2p) {
6114 c++;
6115 i = 0;
6116 combo[c].num_different_channels = 1;
6117 p2p_limits[i].max = 1;
6118 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6119 p2p_limits[i].max = 1;
6120 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6121 p2p_limits[i].max = 1;
6122 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6123 p2p_limits[i].max = 1;
6124 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6125 combo[c].max_interfaces = i;
6126 combo[c].n_limits = i;
6127 combo[c].limits = p2p_limits;
6128 }
6129
6130 if (mbss) {
6131 c++;
6132 combo[c].beacon_int_infra_match = true;
6133 combo[c].num_different_channels = 1;
6134 mbss_limits[0].max = 4;
6135 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
6136 combo[c].max_interfaces = 4;
6137 combo[c].n_limits = 1;
6138 combo[c].limits = mbss_limits;
6139 }
6140 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006141 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006142 return 0;
6143
6144err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006145 kfree(c0_limits);
6146 kfree(p2p_limits);
6147 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006148 kfree(combo);
6149 return -ENOMEM;
6150}
6151
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006152static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6153{
6154 /* scheduled scan settings */
6155 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6156 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6157 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6158 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6159}
6160
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006161#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006162static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006163 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006164 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6165 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6166 .pattern_min_len = 1,
6167 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006168};
6169#endif
6170
Hante Meuleman3021ad92016-01-05 11:05:45 +01006171static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006172{
6173#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006174 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006175
6176 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006177 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6178 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6179 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006180 }
6181 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006182 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6183 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6184 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6185 }
6186
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006187 wiphy->wowlan = &brcmf_wowlan_support;
6188#endif
6189}
6190
Arend van Sprielb48d8912014-07-12 08:49:41 +02006191static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006192{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006193 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006194 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006195 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006196 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006197 __le32 bandlist[3];
6198 u32 n_bands;
6199 int err, i;
6200
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006201 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6202 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006203 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006204
6205 err = brcmf_setup_ifmodes(wiphy, ifp);
6206 if (err)
6207 return err;
6208
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006209 for (i = 0, combo = wiphy->iface_combinations;
6210 i < wiphy->n_iface_combinations; i++, combo++) {
6211 max_interfaces = max(max_interfaces, combo->max_interfaces);
6212 }
6213
6214 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6215 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006216 u8 *addr = drvr->addresses[i].addr;
6217
6218 memcpy(addr, drvr->mac, ETH_ALEN);
6219 if (i) {
6220 addr[0] |= BIT(1);
6221 addr[ETH_ALEN - 1] ^= i;
6222 }
6223 }
6224 wiphy->addresses = drvr->addresses;
6225 wiphy->n_addresses = i;
6226
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006227 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
6228 wiphy->cipher_suites = __wl_cipher_suites;
6229 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
6230 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6231 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006232 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6233 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6234 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006235 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006236 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6237 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6238 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006239 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6240 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006241
6242 /* vendor commands/events support */
6243 wiphy->vendor_commands = brcmf_vendor_cmds;
6244 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6245
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006246 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006247 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006248 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6249 sizeof(bandlist));
6250 if (err) {
6251 brcmf_err("could not obtain band info: err=%d\n", err);
6252 return err;
6253 }
6254 /* first entry in bandlist is number of bands */
6255 n_bands = le32_to_cpu(bandlist[0]);
6256 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6257 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6258 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6259 GFP_KERNEL);
6260 if (!band)
6261 return -ENOMEM;
6262
6263 band->channels = kmemdup(&__wl_2ghz_channels,
6264 sizeof(__wl_2ghz_channels),
6265 GFP_KERNEL);
6266 if (!band->channels) {
6267 kfree(band);
6268 return -ENOMEM;
6269 }
6270
6271 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
6272 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
6273 }
6274 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6275 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6276 GFP_KERNEL);
6277 if (!band)
6278 return -ENOMEM;
6279
6280 band->channels = kmemdup(&__wl_5ghz_channels,
6281 sizeof(__wl_5ghz_channels),
6282 GFP_KERNEL);
6283 if (!band->channels) {
6284 kfree(band);
6285 return -ENOMEM;
6286 }
6287
6288 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
6289 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
6290 }
6291 }
6292 err = brcmf_setup_wiphybands(wiphy);
6293 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006294}
6295
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006296static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006297{
6298 struct net_device *ndev;
6299 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006300 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006301 s32 power_mode;
6302 s32 err = 0;
6303
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006304 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006305 return err;
6306
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006307 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006308 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006309 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006310
Hante Meuleman40a23292013-01-02 15:22:51 +01006311 /* make sure RF is ready for work */
6312 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6313
Hante Meuleman1678ba82015-12-10 13:43:00 +01006314 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006315
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006316 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006317 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006318 if (err)
6319 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006320 brcmf_dbg(INFO, "power save set to %s\n",
6321 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006322
Hante Meuleman1119e232015-11-25 11:32:42 +01006323 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006324 if (err)
6325 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006326 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6327 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006328 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006329 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006330
Franky Lin52f22fb2016-02-17 11:26:55 +01006331 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006332
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006333 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006334default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006335
6336 return err;
6337
6338}
6339
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006340static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006341{
Arend van Sprielc1179032012-10-22 13:55:33 -07006342 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006343
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006344 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006345}
6346
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006347static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006348{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006349 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006350
Arend van Spriel5b435de2011-10-05 13:19:03 +02006351 /*
6352 * While going down, if associated with AP disassociate
6353 * from AP to save power
6354 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006355 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006356 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006357
6358 /* Make sure WPA_Supplicant receives all the event
6359 generated due to DISASSOC call to the fw to keep
6360 the state fw and WPA_Supplicant state consistent
6361 */
6362 brcmf_delay(500);
6363 }
6364
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006365 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006366 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006367
Arend van Spriel5b435de2011-10-05 13:19:03 +02006368 return 0;
6369}
6370
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006371s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006372{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006373 struct brcmf_if *ifp = netdev_priv(ndev);
6374 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006375 s32 err = 0;
6376
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006377 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006378 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006379 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006380
6381 return err;
6382}
6383
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006384s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006385{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006386 struct brcmf_if *ifp = netdev_priv(ndev);
6387 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006388 s32 err = 0;
6389
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006390 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006391 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006392 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006393
6394 return err;
6395}
6396
Arend van Spriela7965fb2013-04-11 17:08:37 +02006397enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6398{
6399 struct wireless_dev *wdev = &ifp->vif->wdev;
6400
6401 return wdev->iftype;
6402}
6403
Hante Meulemanbfe81972014-10-28 14:56:16 +01006404bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6405 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006406{
6407 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006408
6409 list_for_each_entry(vif, &cfg->vif_list, list) {
6410 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006411 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006412 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006413 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006414}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006415
6416static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6417 u8 action)
6418{
6419 u8 evt_action;
6420
6421 mutex_lock(&event->vif_event_lock);
6422 evt_action = event->action;
6423 mutex_unlock(&event->vif_event_lock);
6424 return evt_action == action;
6425}
6426
6427void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6428 struct brcmf_cfg80211_vif *vif)
6429{
6430 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6431
6432 mutex_lock(&event->vif_event_lock);
6433 event->vif = vif;
6434 event->action = 0;
6435 mutex_unlock(&event->vif_event_lock);
6436}
6437
6438bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6439{
6440 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6441 bool armed;
6442
6443 mutex_lock(&event->vif_event_lock);
6444 armed = event->vif != NULL;
6445 mutex_unlock(&event->vif_event_lock);
6446
6447 return armed;
6448}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006449
6450int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6451 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006452{
6453 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6454
6455 return wait_event_timeout(event->vif_wq,
6456 vif_event_equals(event, action), timeout);
6457}
6458
Hante Meuleman73345fd2016-02-17 11:26:53 +01006459static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6460 struct brcmf_fil_country_le *ccreq)
6461{
Hante Meuleman4d792892016-02-17 11:27:07 +01006462 struct brcmfmac_pd_cc *country_codes;
6463 struct brcmfmac_pd_cc_entry *cc;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006464 s32 found_index;
6465 int i;
6466
6467 country_codes = drvr->settings->country_codes;
6468 if (!country_codes) {
6469 brcmf_dbg(TRACE, "No country codes configured for device\n");
6470 return -EINVAL;
6471 }
6472
6473 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6474 (alpha2[1] == ccreq->country_abbrev[1])) {
6475 brcmf_dbg(TRACE, "Country code already set\n");
6476 return -EAGAIN;
6477 }
6478
6479 found_index = -1;
6480 for (i = 0; i < country_codes->table_size; i++) {
6481 cc = &country_codes->table[i];
6482 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6483 found_index = i;
6484 if ((cc->iso3166[0] == alpha2[0]) &&
6485 (cc->iso3166[1] == alpha2[1])) {
6486 found_index = i;
6487 break;
6488 }
6489 }
6490 if (found_index == -1) {
6491 brcmf_dbg(TRACE, "No country code match found\n");
6492 return -EINVAL;
6493 }
6494 memset(ccreq, 0, sizeof(*ccreq));
6495 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6496 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6497 BRCMF_COUNTRY_BUF_SZ);
6498 ccreq->country_abbrev[0] = alpha2[0];
6499 ccreq->country_abbrev[1] = alpha2[1];
6500 ccreq->country_abbrev[2] = 0;
6501
6502 return 0;
6503}
6504
Arend van Spriel63db1a42014-12-21 12:43:51 +01006505static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6506 struct regulatory_request *req)
6507{
6508 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6509 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6510 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006511 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006512 int i;
6513
Arend van Spriel63db1a42014-12-21 12:43:51 +01006514 /* ignore non-ISO3166 country codes */
6515 for (i = 0; i < sizeof(req->alpha2); i++)
6516 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006517 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6518 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006519 return;
6520 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006521
6522 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6523 req->alpha2[0], req->alpha2[1]);
6524
6525 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6526 if (err) {
6527 brcmf_err("Country code iovar returned err = %d\n", err);
6528 return;
6529 }
6530
6531 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6532 if (err)
6533 return;
6534
6535 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6536 if (err) {
6537 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006538 return;
6539 }
6540 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006541}
6542
Arend van Sprielb48d8912014-07-12 08:49:41 +02006543static void brcmf_free_wiphy(struct wiphy *wiphy)
6544{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006545 int i;
6546
Arend van Spriel58de92d2015-04-14 20:10:24 +02006547 if (!wiphy)
6548 return;
6549
Arend van Spriel0882dda2015-08-20 22:06:03 +02006550 if (wiphy->iface_combinations) {
6551 for (i = 0; i < wiphy->n_iface_combinations; i++)
6552 kfree(wiphy->iface_combinations[i].limits);
6553 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006554 kfree(wiphy->iface_combinations);
6555 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6556 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6557 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6558 }
6559 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6560 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6561 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6562 }
6563 wiphy_free(wiphy);
6564}
6565
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006566struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006567 struct device *busdev,
6568 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006569{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006570 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006571 struct brcmf_cfg80211_info *cfg;
6572 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006573 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006574 struct brcmf_cfg80211_vif *vif;
6575 struct brcmf_if *ifp;
6576 s32 err = 0;
6577 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006578 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006579
6580 if (!ndev) {
6581 brcmf_err("ndev is invalid\n");
6582 return NULL;
6583 }
6584
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006585 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
6586 if (!ops)
6587 return NULL;
6588
6589 memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006590 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006591#ifdef CONFIG_PM
6592 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6593 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6594#endif
6595 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006596 if (!wiphy) {
6597 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006598 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006599 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006600 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006601 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006602
6603 cfg = wiphy_priv(wiphy);
6604 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006605 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006606 cfg->pub = drvr;
6607 init_vif_event(&cfg->vif_event);
6608 INIT_LIST_HEAD(&cfg->vif_list);
6609
6610 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006611 if (IS_ERR(vif))
6612 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006613
6614 vif->ifp = ifp;
6615 vif->wdev.netdev = ndev;
6616 ndev->ieee80211_ptr = &vif->wdev;
6617 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6618
6619 err = wl_init_priv(cfg);
6620 if (err) {
6621 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006622 brcmf_free_vif(vif);
6623 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006624 }
6625 ifp->vif = vif;
6626
Arend van Sprielb48d8912014-07-12 08:49:41 +02006627 /* determine d11 io type before wiphy setup */
6628 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006629 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006630 brcmf_err("Failed to get D11 version (%d)\n", err);
6631 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006632 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006633 cfg->d11inf.io_type = (u8)io_type;
6634 brcmu_d11_attach(&cfg->d11inf);
6635
6636 err = brcmf_setup_wiphy(wiphy, ifp);
6637 if (err < 0)
6638 goto priv_out;
6639
6640 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006641 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006642 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6643 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6644
6645 /* firmware defaults to 40MHz disabled in 2G band. We signal
6646 * cfg80211 here that we do and have it decide we can enable
6647 * it. But first check if device does support 2G operation.
6648 */
6649 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6650 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6651 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6652 }
6653 err = wiphy_register(wiphy);
6654 if (err < 0) {
6655 brcmf_err("Could not register wiphy device (%d)\n", err);
6656 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006657 }
6658
6659 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6660 * setup 40MHz in 2GHz band and enable OBSS scanning.
6661 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006662 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6663 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006664 if (!err)
6665 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6666 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006667 else
6668 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006669 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006670 /* p2p might require that "if-events" get processed by fweh. So
6671 * activate the already registered event handlers now and activate
6672 * the rest when initialization has completed. drvr->config needs to
6673 * be assigned before activating events.
6674 */
6675 drvr->config = cfg;
6676 err = brcmf_fweh_activate_events(ifp);
6677 if (err) {
6678 brcmf_err("FWEH activation failed (%d)\n", err);
6679 goto wiphy_unreg_out;
6680 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006681
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006682 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006683 if (err) {
6684 brcmf_err("P2P initilisation failed (%d)\n", err);
6685 goto wiphy_unreg_out;
6686 }
6687 err = brcmf_btcoex_attach(cfg);
6688 if (err) {
6689 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6690 brcmf_p2p_detach(&cfg->p2p);
6691 goto wiphy_unreg_out;
6692 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006693
Hante Meulemana7b82d42015-12-10 13:43:04 +01006694 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6695 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6696 if (err) {
6697 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6698 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6699 } else {
6700 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6701 brcmf_notify_tdls_peer_event);
6702 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006703 }
6704
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006705 /* (re-) activate FWEH event handling */
6706 err = brcmf_fweh_activate_events(ifp);
6707 if (err) {
6708 brcmf_err("FWEH activation failed (%d)\n", err);
6709 goto wiphy_unreg_out;
6710 }
6711
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006712 /* Fill in some of the advertised nl80211 supported features */
6713 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6714 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6715#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006716 if (wiphy->wowlan &&
6717 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006718 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6719#endif
6720 }
6721
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006722 return cfg;
6723
Arend van Sprielb48d8912014-07-12 08:49:41 +02006724wiphy_unreg_out:
6725 wiphy_unregister(cfg->wiphy);
6726priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006727 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006728 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006729 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006730wiphy_out:
6731 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006732 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006733 return NULL;
6734}
6735
6736void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6737{
6738 if (!cfg)
6739 return;
6740
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006741 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006742 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006743 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006744 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006745 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006746}