blob: 6d849bb2e27c9b21029f9185424762d2e41b21a4 [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);
Franky Lin52f22fb2016-02-17 11:26:55 +01003559 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003560 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
Hante Meuleman3021ad92016-01-05 11:05:45 +01003561 cfg->wowl.pre_pmmode);
3562 cfg->wowl.active = false;
3563 if (cfg->wowl.nd_enabled) {
3564 brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
3565 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3566 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3567 brcmf_notify_sched_scan_results);
3568 cfg->wowl.nd_enabled = false;
3569 }
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003570 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003571 return 0;
3572}
3573
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003574static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
3575 struct brcmf_if *ifp,
3576 struct cfg80211_wowlan *wowl)
3577{
3578 u32 wowl_config;
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003579 u32 i;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003580
3581 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
3582
Franky Lin52f22fb2016-02-17 11:26:55 +01003583 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003584 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003585 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
3586
3587 wowl_config = 0;
3588 if (wowl->disconnect)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003589 wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003590 if (wowl->magic_pkt)
Hante Meulemanb9a82f82014-10-28 14:56:06 +01003591 wowl_config |= BRCMF_WOWL_MAGIC;
3592 if ((wowl->patterns) && (wowl->n_patterns)) {
3593 wowl_config |= BRCMF_WOWL_NET;
3594 for (i = 0; i < wowl->n_patterns; i++) {
3595 brcmf_config_wowl_pattern(ifp, "add",
3596 (u8 *)wowl->patterns[i].pattern,
3597 wowl->patterns[i].pattern_len,
3598 (u8 *)wowl->patterns[i].mask,
3599 wowl->patterns[i].pkt_offset);
3600 }
3601 }
Hante Meuleman3021ad92016-01-05 11:05:45 +01003602 if (wowl->nd_config) {
3603 brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
3604 wowl->nd_config);
3605 wowl_config |= BRCMF_WOWL_PFN_FOUND;
3606
3607 cfg->wowl.nd_data_completed = false;
3608 cfg->wowl.nd_enabled = true;
3609 /* Now reroute the event for PFN to the wowl function. */
3610 brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
3611 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
3612 brcmf_wowl_nd_results);
3613 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01003614 if (wowl->gtk_rekey_failure)
3615 wowl_config |= BRCMF_WOWL_GTK_FAILURE;
Hante Meuleman3021ad92016-01-05 11:05:45 +01003616 if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
3617 wowl_config |= BRCMF_WOWL_UNASSOC;
3618
Hante Meulemanaeb64222015-10-29 20:33:19 +01003619 brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003620 brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
3621 brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
3622 brcmf_bus_wowl_config(cfg->pub->bus_if, true);
Hante Meuleman3021ad92016-01-05 11:05:45 +01003623 cfg->wowl.active = true;
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003624}
3625
Arend van Spriel5b435de2011-10-05 13:19:03 +02003626static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003627 struct cfg80211_wowlan *wowl)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003628{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003629 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3630 struct net_device *ndev = cfg_to_ndev(cfg);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003631 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel7d641072012-10-22 13:55:39 -07003632 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003633
Arend van Sprield96b8012012-12-05 15:26:02 +01003634 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003635
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003636 /* if the primary net_device is not READY there is nothing
Arend van Spriel7d641072012-10-22 13:55:39 -07003637 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003638 */
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003639 if (!check_vif_up(ifp->vif))
Arend van Spriel7d641072012-10-22 13:55:39 -07003640 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003641
Hante Meuleman3021ad92016-01-05 11:05:45 +01003642 /* Stop scheduled scan */
3643 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
3644 brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
3645
Arend van Spriel7d641072012-10-22 13:55:39 -07003646 /* end any scanning */
3647 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003648 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003649
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003650 if (wowl == NULL) {
3651 brcmf_bus_wowl_config(cfg->pub->bus_if, false);
3652 list_for_each_entry(vif, &cfg->vif_list, list) {
3653 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3654 continue;
3655 /* While going to suspend if associated with AP
3656 * disassociate from AP to save power while system is
3657 * in suspended state
3658 */
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01003659 brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
Hante Meuleman4eb3af72014-09-30 10:23:18 +02003660 /* Make sure WPA_Supplicant receives all the event
3661 * generated due to DISASSOC call to the fw to keep
3662 * the state fw and WPA_Supplicant state consistent
3663 */
3664 brcmf_delay(500);
3665 }
3666 /* Configure MPC */
3667 brcmf_set_mpc(ifp, 1);
3668
3669 } else {
3670 /* Configure WOWL paramaters */
3671 brcmf_configure_wowl(cfg, ifp, wowl);
3672 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003673
Arend van Spriel7d641072012-10-22 13:55:39 -07003674exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01003675 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003676 /* clear any scanning activity */
3677 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003678 return 0;
3679}
3680
3681static __used s32
Hante Meuleman6c404f32015-12-10 13:43:03 +01003682brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003683{
Hante Meuleman6c404f32015-12-10 13:43:03 +01003684 struct brcmf_pmk_list_le *pmk_list;
3685 int i;
3686 u32 npmk;
3687 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003688
Hante Meuleman6c404f32015-12-10 13:43:03 +01003689 pmk_list = &cfg->pmk_list;
3690 npmk = le32_to_cpu(pmk_list->npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003691
Hante Meuleman6c404f32015-12-10 13:43:03 +01003692 brcmf_dbg(CONN, "No of elements %d\n", npmk);
3693 for (i = 0; i < npmk; i++)
3694 brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003695
Hante Meuleman6c404f32015-12-10 13:43:03 +01003696 err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
3697 sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003698
3699 return err;
3700}
3701
3702static s32
3703brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3704 struct cfg80211_pmksa *pmksa)
3705{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003706 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003707 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003708 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3709 s32 err;
3710 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003711
Arend van Sprield96b8012012-12-05 15:26:02 +01003712 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003713 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003714 return -EIO;
3715
Hante Meuleman6c404f32015-12-10 13:43:03 +01003716 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3717 for (i = 0; i < npmk; i++)
3718 if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003719 break;
Hante Meuleman6c404f32015-12-10 13:43:03 +01003720 if (i < BRCMF_MAXPMKID) {
3721 memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
3722 memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
3723 if (i == npmk) {
3724 npmk++;
3725 cfg->pmk_list.npmk = cpu_to_le32(npmk);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003726 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003727 } else {
3728 brcmf_err("Too many PMKSA entries cached %d\n", npmk);
3729 return -EINVAL;
3730 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003731
Hante Meuleman6c404f32015-12-10 13:43:03 +01003732 brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
3733 for (i = 0; i < WLAN_PMKID_LEN; i += 4)
3734 brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
3735 pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
3736 pmk[npmk].pmkid[i + 3]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003737
Hante Meuleman6c404f32015-12-10 13:43:03 +01003738 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003739
Arend van Sprield96b8012012-12-05 15:26:02 +01003740 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003741 return err;
3742}
3743
3744static s32
3745brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman6c404f32015-12-10 13:43:03 +01003746 struct cfg80211_pmksa *pmksa)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003747{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003748 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003749 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003750 struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
3751 s32 err;
3752 u32 npmk, i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003753
Arend van Sprield96b8012012-12-05 15:26:02 +01003754 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003755 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003756 return -EIO;
3757
Hante Meuleman6c404f32015-12-10 13:43:03 +01003758 brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003759
Hante Meuleman6c404f32015-12-10 13:43:03 +01003760 npmk = le32_to_cpu(cfg->pmk_list.npmk);
3761 for (i = 0; i < npmk; i++)
3762 if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003763 break;
3764
Hante Meuleman6c404f32015-12-10 13:43:03 +01003765 if ((npmk > 0) && (i < npmk)) {
3766 for (; i < (npmk - 1); i++) {
3767 memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
3768 memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003769 WLAN_PMKID_LEN);
3770 }
Hante Meuleman6c404f32015-12-10 13:43:03 +01003771 memset(&pmk[i], 0, sizeof(*pmk));
3772 cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
3773 } else {
3774 brcmf_err("Cache entry not found\n");
3775 return -EINVAL;
3776 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777
Hante Meuleman6c404f32015-12-10 13:43:03 +01003778 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003779
Arend van Sprield96b8012012-12-05 15:26:02 +01003780 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003781 return err;
3782
3783}
3784
3785static s32
3786brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3787{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003788 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003789 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman6c404f32015-12-10 13:43:03 +01003790 s32 err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003791
Arend van Sprield96b8012012-12-05 15:26:02 +01003792 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003793 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003794 return -EIO;
3795
Hante Meuleman6c404f32015-12-10 13:43:03 +01003796 memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
3797 err = brcmf_update_pmklist(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003798
Arend van Sprield96b8012012-12-05 15:26:02 +01003799 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003800 return err;
3801
3802}
3803
Hante Meuleman1f170112013-02-06 18:40:38 +01003804static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003805{
3806 s32 err;
3807
3808 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003809 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003810 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003811 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003812 return err;
3813 }
3814 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003815 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003816 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003817 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003818 return err;
3819 }
3820 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003821 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003822 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003823 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003824 return err;
3825 }
3826
3827 return 0;
3828}
3829
3830static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3831{
3832 if (is_rsn_ie)
3833 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3834
3835 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3836}
3837
3838static s32
Hante Meulemana44aa402014-12-03 21:05:33 +01003839brcmf_configure_wpaie(struct brcmf_if *ifp,
Johannes Berg4b5800f2014-01-15 14:55:59 +01003840 const struct brcmf_vs_tlv *wpa_ie,
3841 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003842{
3843 u32 auth = 0; /* d11 open authentication */
3844 u16 count;
3845 s32 err = 0;
3846 s32 len = 0;
3847 u32 i;
3848 u32 wsec;
3849 u32 pval = 0;
3850 u32 gval = 0;
3851 u32 wpa_auth = 0;
3852 u32 offset;
3853 u8 *data;
3854 u16 rsn_cap;
3855 u32 wme_bss_disable;
3856
Arend van Sprield96b8012012-12-05 15:26:02 +01003857 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003858 if (wpa_ie == NULL)
3859 goto exit;
3860
3861 len = wpa_ie->len + TLV_HDR_LEN;
3862 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003863 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003864 if (!is_rsn_ie)
3865 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003866 else
3867 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003868
3869 /* check for multicast cipher suite */
3870 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3871 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003872 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003873 goto exit;
3874 }
3875
3876 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3877 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003878 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003879 goto exit;
3880 }
3881 offset += TLV_OUI_LEN;
3882
3883 /* pick up multicast cipher */
3884 switch (data[offset]) {
3885 case WPA_CIPHER_NONE:
3886 gval = 0;
3887 break;
3888 case WPA_CIPHER_WEP_40:
3889 case WPA_CIPHER_WEP_104:
3890 gval = WEP_ENABLED;
3891 break;
3892 case WPA_CIPHER_TKIP:
3893 gval = TKIP_ENABLED;
3894 break;
3895 case WPA_CIPHER_AES_CCM:
3896 gval = AES_ENABLED;
3897 break;
3898 default:
3899 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003900 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003901 goto exit;
3902 }
3903
3904 offset++;
3905 /* walk thru unicast cipher list and pick up what we recognize */
3906 count = data[offset] + (data[offset + 1] << 8);
3907 offset += WPA_IE_SUITE_COUNT_LEN;
3908 /* Check for unicast suite(s) */
3909 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3910 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003911 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003912 goto exit;
3913 }
3914 for (i = 0; i < count; i++) {
3915 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3916 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003917 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003918 goto exit;
3919 }
3920 offset += TLV_OUI_LEN;
3921 switch (data[offset]) {
3922 case WPA_CIPHER_NONE:
3923 break;
3924 case WPA_CIPHER_WEP_40:
3925 case WPA_CIPHER_WEP_104:
3926 pval |= WEP_ENABLED;
3927 break;
3928 case WPA_CIPHER_TKIP:
3929 pval |= TKIP_ENABLED;
3930 break;
3931 case WPA_CIPHER_AES_CCM:
3932 pval |= AES_ENABLED;
3933 break;
3934 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003935 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003936 }
3937 offset++;
3938 }
3939 /* walk thru auth management suite list and pick up what we recognize */
3940 count = data[offset] + (data[offset + 1] << 8);
3941 offset += WPA_IE_SUITE_COUNT_LEN;
3942 /* Check for auth key management suite(s) */
3943 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3944 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003945 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003946 goto exit;
3947 }
3948 for (i = 0; i < count; i++) {
3949 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3950 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003951 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003952 goto exit;
3953 }
3954 offset += TLV_OUI_LEN;
3955 switch (data[offset]) {
3956 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003957 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003958 wpa_auth |= WPA_AUTH_NONE;
3959 break;
3960 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003961 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003962 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3963 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3964 break;
3965 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003966 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003967 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3968 (wpa_auth |= WPA_AUTH_PSK);
3969 break;
3970 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003971 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003972 }
3973 offset++;
3974 }
3975
3976 if (is_rsn_ie) {
3977 wme_bss_disable = 1;
3978 if ((offset + RSN_CAP_LEN) <= len) {
3979 rsn_cap = data[offset] + (data[offset + 1] << 8);
3980 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3981 wme_bss_disable = 0;
3982 }
3983 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003984 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003985 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003986 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003987 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003988 goto exit;
3989 }
3990 }
3991 /* FOR WPS , set SES_OW_ENABLED */
3992 wsec = (pval | gval | SES_OW_ENABLED);
3993
3994 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003995 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003996 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003997 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003998 goto exit;
3999 }
4000 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07004001 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004002 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004003 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004004 goto exit;
4005 }
4006 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07004007 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02004008 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004009 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004010 goto exit;
4011 }
4012
4013exit:
4014 return err;
4015}
4016
4017static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08004018brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02004019 struct parsed_vndr_ies *vndr_ies)
4020{
Hante Meuleman1a873342012-09-27 14:17:54 +02004021 struct brcmf_vs_tlv *vndrie;
4022 struct brcmf_tlv *ie;
4023 struct parsed_vndr_ie_info *parsed_info;
4024 s32 remaining_len;
4025
4026 remaining_len = (s32)vndr_ie_len;
4027 memset(vndr_ies, 0, sizeof(*vndr_ies));
4028
4029 ie = (struct brcmf_tlv *)vndr_ie_buf;
4030 while (ie) {
4031 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
4032 goto next;
4033 vndrie = (struct brcmf_vs_tlv *)ie;
4034 /* len should be bigger than OUI length + one */
4035 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004036 brcmf_err("invalid vndr ie. length is too small %d\n",
4037 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004038 goto next;
4039 }
4040 /* if wpa or wme ie, do not add ie */
4041 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
4042 ((vndrie->oui_type == WPA_OUI_TYPE) ||
4043 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004044 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004045 goto next;
4046 }
4047
4048 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
4049
4050 /* save vndr ie information */
4051 parsed_info->ie_ptr = (char *)vndrie;
4052 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
4053 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
4054
4055 vndr_ies->count++;
4056
Arend van Sprield96b8012012-12-05 15:26:02 +01004057 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
4058 parsed_info->vndrie.oui[0],
4059 parsed_info->vndrie.oui[1],
4060 parsed_info->vndrie.oui[2],
4061 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02004062
Arend van Spriel9f440b72013-02-08 15:53:36 +01004063 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02004064 break;
4065next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004066 remaining_len -= (ie->len + TLV_HDR_LEN);
4067 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02004068 ie = NULL;
4069 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004070 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
4071 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02004072 }
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03004073 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004074}
4075
4076static u32
4077brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
4078{
4079
Hante Meuleman1a873342012-09-27 14:17:54 +02004080 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
4081 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
4082
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304083 put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004084
Vaishali Thakkar362126c2015-01-16 21:36:14 +05304085 put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004086
4087 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
4088
4089 return ie_len + VNDR_IE_HDR_SIZE;
4090}
4091
Arend van Spriel1332e262012-11-05 16:22:18 -08004092s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
4093 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02004094{
Arend van Spriel1332e262012-11-05 16:22:18 -08004095 struct brcmf_if *ifp;
4096 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004097 s32 err = 0;
4098 u8 *iovar_ie_buf;
4099 u8 *curr_ie_buf;
4100 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004101 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07004102 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004103 u32 del_add_ie_buf_len = 0;
4104 u32 total_ie_buf_len = 0;
4105 u32 parsed_ie_buf_len = 0;
4106 struct parsed_vndr_ies old_vndr_ies;
4107 struct parsed_vndr_ies new_vndr_ies;
4108 struct parsed_vndr_ie_info *vndrie_info;
4109 s32 i;
4110 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07004111 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02004112
Arend van Spriel1332e262012-11-05 16:22:18 -08004113 if (!vif)
4114 return -ENODEV;
4115 ifp = vif->ifp;
4116 saved_ie = &vif->saved_ie;
4117
Hante Meuleman37a869e2015-10-29 20:33:17 +01004118 brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
4119 pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02004120 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4121 if (!iovar_ie_buf)
4122 return -ENOMEM;
4123 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01004124 switch (pktflag) {
4125 case BRCMF_VNDR_IE_PRBREQ_FLAG:
4126 mgmt_ie_buf = saved_ie->probe_req_ie;
4127 mgmt_ie_len = &saved_ie->probe_req_ie_len;
4128 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
4129 break;
4130 case BRCMF_VNDR_IE_PRBRSP_FLAG:
4131 mgmt_ie_buf = saved_ie->probe_res_ie;
4132 mgmt_ie_len = &saved_ie->probe_res_ie_len;
4133 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
4134 break;
4135 case BRCMF_VNDR_IE_BEACON_FLAG:
4136 mgmt_ie_buf = saved_ie->beacon_ie;
4137 mgmt_ie_len = &saved_ie->beacon_ie_len;
4138 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
4139 break;
4140 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
4141 mgmt_ie_buf = saved_ie->assoc_req_ie;
4142 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
4143 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
4144 break;
4145 default:
4146 err = -EPERM;
4147 brcmf_err("not suitable type\n");
4148 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004149 }
4150
4151 if (vndr_ie_len > mgmt_ie_buf_len) {
4152 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01004153 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004154 goto exit;
4155 }
4156
4157 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
4158 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
4159 ptr = curr_ie_buf;
4160 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
4161 for (i = 0; i < new_vndr_ies.count; i++) {
4162 vndrie_info = &new_vndr_ies.ie_info[i];
4163 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
4164 vndrie_info->ie_len);
4165 parsed_ie_buf_len += vndrie_info->ie_len;
4166 }
4167 }
4168
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004169 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004170 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
4171 (memcmp(mgmt_ie_buf, curr_ie_buf,
4172 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004173 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004174 goto exit;
4175 }
4176
4177 /* parse old vndr_ie */
4178 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
4179
4180 /* make a command to delete old ie */
4181 for (i = 0; i < old_vndr_ies.count; i++) {
4182 vndrie_info = &old_vndr_ies.ie_info[i];
4183
Arend van Sprield96b8012012-12-05 15:26:02 +01004184 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
4185 vndrie_info->vndrie.id,
4186 vndrie_info->vndrie.len,
4187 vndrie_info->vndrie.oui[0],
4188 vndrie_info->vndrie.oui[1],
4189 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004190
4191 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4192 vndrie_info->ie_ptr,
4193 vndrie_info->ie_len,
4194 "del");
4195 curr_ie_buf += del_add_ie_buf_len;
4196 total_ie_buf_len += del_add_ie_buf_len;
4197 }
4198 }
4199
4200 *mgmt_ie_len = 0;
4201 /* Add if there is any extra IE */
4202 if (mgmt_ie_buf && parsed_ie_buf_len) {
4203 ptr = mgmt_ie_buf;
4204
4205 remained_buf_len = mgmt_ie_buf_len;
4206
4207 /* make a command to add new ie */
4208 for (i = 0; i < new_vndr_ies.count; i++) {
4209 vndrie_info = &new_vndr_ies.ie_info[i];
4210
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004211 /* verify remained buf size before copy data */
4212 if (remained_buf_len < (vndrie_info->vndrie.len +
4213 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004214 brcmf_err("no space in mgmt_ie_buf: len left %d",
4215 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01004216 break;
4217 }
4218 remained_buf_len -= (vndrie_info->ie_len +
4219 VNDR_IE_VSIE_OFFSET);
4220
Arend van Sprield96b8012012-12-05 15:26:02 +01004221 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
4222 vndrie_info->vndrie.id,
4223 vndrie_info->vndrie.len,
4224 vndrie_info->vndrie.oui[0],
4225 vndrie_info->vndrie.oui[1],
4226 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02004227
4228 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
4229 vndrie_info->ie_ptr,
4230 vndrie_info->ie_len,
4231 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02004232
4233 /* save the parsed IE in wl struct */
4234 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
4235 vndrie_info->ie_len);
4236 *mgmt_ie_len += vndrie_info->ie_len;
4237
4238 curr_ie_buf += del_add_ie_buf_len;
4239 total_ie_buf_len += del_add_ie_buf_len;
4240 }
4241 }
4242 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004243 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004244 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02004245 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004246 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004247 }
4248
4249exit:
4250 kfree(iovar_ie_buf);
4251 return err;
4252}
4253
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004254s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
4255{
4256 s32 pktflags[] = {
4257 BRCMF_VNDR_IE_PRBREQ_FLAG,
4258 BRCMF_VNDR_IE_PRBRSP_FLAG,
4259 BRCMF_VNDR_IE_BEACON_FLAG
4260 };
4261 int i;
4262
4263 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
4264 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
4265
4266 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
4267 return 0;
4268}
4269
Hante Meuleman1a873342012-09-27 14:17:54 +02004270static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01004271brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
4272 struct cfg80211_beacon_data *beacon)
4273{
4274 s32 err;
4275
4276 /* Set Beacon IEs to FW */
4277 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
4278 beacon->tail, beacon->tail_len);
4279 if (err) {
4280 brcmf_err("Set Beacon IE Failed\n");
4281 return err;
4282 }
4283 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
4284
4285 /* Set Probe Response IEs to FW */
4286 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
4287 beacon->proberesp_ies,
4288 beacon->proberesp_ies_len);
4289 if (err)
4290 brcmf_err("Set Probe Resp IE Failed\n");
4291 else
4292 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
4293
4294 return err;
4295}
4296
4297static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02004298brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
4299 struct cfg80211_ap_settings *settings)
4300{
4301 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004302 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07004303 struct brcmf_if *ifp = netdev_priv(ndev);
Johannes Berg4b5800f2014-01-15 14:55:59 +01004304 const struct brcmf_tlv *ssid_ie;
Arend van Spriel98027762014-12-21 12:43:53 +01004305 const struct brcmf_tlv *country_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004306 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02004307 s32 err = -EPERM;
Johannes Berg4b5800f2014-01-15 14:55:59 +01004308 const struct brcmf_tlv *rsn_ie;
4309 const struct brcmf_vs_tlv *wpa_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02004310 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01004311 enum nl80211_iftype dev_role;
4312 struct brcmf_fil_bss_enable_le bss_enable;
Arend van Spriel06c01582014-05-12 10:47:37 +02004313 u16 chanspec;
Hante Meulemana44aa402014-12-03 21:05:33 +01004314 bool mbss;
Arend van Spriel98027762014-12-21 12:43:53 +01004315 int is_11d;
Hante Meuleman1a873342012-09-27 14:17:54 +02004316
Arend van Spriel06c01582014-05-12 10:47:37 +02004317 brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
4318 settings->chandef.chan->hw_value,
4319 settings->chandef.center_freq1, settings->chandef.width,
Arend van Spriela9a56872014-05-12 10:47:33 +02004320 settings->beacon_interval, settings->dtim_period);
Arend van Sprield96b8012012-12-05 15:26:02 +01004321 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
4322 settings->ssid, settings->ssid_len, settings->auth_type,
4323 settings->inactivity_timeout);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004324 dev_role = ifp->vif->wdev.iftype;
Hante Meulemana44aa402014-12-03 21:05:33 +01004325 mbss = ifp->vif->mbss;
Hante Meuleman1a873342012-09-27 14:17:54 +02004326
Arend van Spriel98027762014-12-21 12:43:53 +01004327 /* store current 11d setting */
4328 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
4329 country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4330 settings->beacon.tail_len,
4331 WLAN_EID_COUNTRY);
4332 is_11d = country_ie ? 1 : 0;
4333
Hante Meuleman1a873342012-09-27 14:17:54 +02004334 memset(&ssid_le, 0, sizeof(ssid_le));
4335 if (settings->ssid == NULL || settings->ssid_len == 0) {
4336 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4337 ssid_ie = brcmf_parse_tlvs(
4338 (u8 *)&settings->beacon.head[ie_offset],
4339 settings->beacon.head_len - ie_offset,
4340 WLAN_EID_SSID);
4341 if (!ssid_ie)
4342 return -EINVAL;
4343
4344 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
4345 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01004346 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02004347 } else {
4348 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
4349 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
4350 }
4351
Hante Meulemana44aa402014-12-03 21:05:33 +01004352 if (!mbss) {
4353 brcmf_set_mpc(ifp, 0);
Franky Lin52f22fb2016-02-17 11:26:55 +01004354 brcmf_configure_arp_nd_offload(ifp, false);
Hante Meulemana44aa402014-12-03 21:05:33 +01004355 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004356
4357 /* find the RSN_IE */
4358 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
4359 settings->beacon.tail_len, WLAN_EID_RSN);
4360
4361 /* find the WPA_IE */
4362 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
4363 settings->beacon.tail_len);
4364
Hante Meuleman1a873342012-09-27 14:17:54 +02004365 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01004366 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004367 if (wpa_ie != NULL) {
4368 /* WPA IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004369 err = brcmf_configure_wpaie(ifp, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02004370 if (err < 0)
4371 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004372 } else {
Hante Meulemana44aa402014-12-03 21:05:33 +01004373 struct brcmf_vs_tlv *tmp_ie;
4374
4375 tmp_ie = (struct brcmf_vs_tlv *)rsn_ie;
4376
Hante Meuleman1a873342012-09-27 14:17:54 +02004377 /* RSN IE */
Hante Meulemana44aa402014-12-03 21:05:33 +01004378 err = brcmf_configure_wpaie(ifp, tmp_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004379 if (err < 0)
4380 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004381 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004382 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01004383 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01004384 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02004385 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004386
Hante Meulemana0f07952013-02-08 15:53:47 +01004387 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02004388
Hante Meulemana44aa402014-12-03 21:05:33 +01004389 if (!mbss) {
4390 chanspec = chandef_to_chanspec(&cfg->d11inf,
4391 &settings->chandef);
4392 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
Hante Meuleman1a873342012-09-27 14:17:54 +02004393 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004394 brcmf_err("Set Channel failed: chspec=%d, %d\n",
4395 chanspec, err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004396 goto exit;
4397 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004398
Arend van Spriel98027762014-12-21 12:43:53 +01004399 if (is_11d != ifp->vif->is_11d) {
4400 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4401 is_11d);
4402 if (err < 0) {
4403 brcmf_err("Regulatory Set Error, %d\n", err);
4404 goto exit;
4405 }
4406 }
Hante Meulemana44aa402014-12-03 21:05:33 +01004407 if (settings->beacon_interval) {
4408 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
4409 settings->beacon_interval);
4410 if (err < 0) {
4411 brcmf_err("Beacon Interval Set Error, %d\n",
4412 err);
4413 goto exit;
4414 }
4415 }
4416 if (settings->dtim_period) {
4417 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
4418 settings->dtim_period);
4419 if (err < 0) {
4420 brcmf_err("DTIM Interval Set Error, %d\n", err);
4421 goto exit;
4422 }
4423 }
4424
Hante Meuleman8abffd82015-10-29 20:33:16 +01004425 if ((dev_role == NL80211_IFTYPE_AP) &&
4426 ((ifp->ifidx == 0) ||
4427 !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004428 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4429 if (err < 0) {
4430 brcmf_err("BRCMF_C_DOWN error %d\n", err);
4431 goto exit;
4432 }
4433 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
4434 }
4435
4436 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004437 if (err < 0) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004438 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004439 goto exit;
4440 }
Arend van Spriel98027762014-12-21 12:43:53 +01004441 } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
4442 /* Multiple-BSS should use same 11d configuration */
4443 err = -EINVAL;
4444 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02004445 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004446 if (dev_role == NL80211_IFTYPE_AP) {
Hante Meulemana44aa402014-12-03 21:05:33 +01004447 if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
4448 brcmf_fil_iovar_int_set(ifp, "mbss", 1);
4449
Hante Meulemana0f07952013-02-08 15:53:47 +01004450 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
4451 if (err < 0) {
4452 brcmf_err("setting AP mode failed %d\n", err);
4453 goto exit;
4454 }
4455 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4456 if (err < 0) {
4457 brcmf_err("BRCMF_C_UP error (%d)\n", err);
4458 goto exit;
4459 }
Hante Meuleman118eb302014-12-21 12:43:49 +01004460 /* On DOWN the firmware removes the WEP keys, reconfigure
4461 * them if they were set.
4462 */
4463 brcmf_cfg80211_reconfigure_wep(ifp);
Hante Meulemana0f07952013-02-08 15:53:47 +01004464
4465 memset(&join_params, 0, sizeof(join_params));
4466 /* join parameters starts with ssid */
4467 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4468 /* create softap */
4469 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4470 &join_params, sizeof(join_params));
4471 if (err < 0) {
4472 brcmf_err("SET SSID error (%d)\n", err);
4473 goto exit;
4474 }
4475 brcmf_dbg(TRACE, "AP mode configuration complete\n");
4476 } else {
4477 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
4478 sizeof(ssid_le));
4479 if (err < 0) {
4480 brcmf_err("setting ssid failed %d\n", err);
4481 goto exit;
4482 }
Hante Meuleman37a869e2015-10-29 20:33:17 +01004483 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meulemana0f07952013-02-08 15:53:47 +01004484 bss_enable.enable = cpu_to_le32(1);
4485 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4486 sizeof(bss_enable));
4487 if (err < 0) {
4488 brcmf_err("bss_enable config failed %d\n", err);
4489 goto exit;
4490 }
4491
4492 brcmf_dbg(TRACE, "GO mode configuration complete\n");
4493 }
Arend van Sprielc1179032012-10-22 13:55:33 -07004494 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004495 brcmf_net_setcarrier(ifp, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02004496
4497exit:
Hante Meulemana44aa402014-12-03 21:05:33 +01004498 if ((err) && (!mbss)) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02004499 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004500 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02004501 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004502 return err;
4503}
4504
4505static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4506{
Arend van Sprielc1179032012-10-22 13:55:33 -07004507 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004508 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01004509 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02004510 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02004511
Arend van Sprield96b8012012-12-05 15:26:02 +01004512 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004513
Hante Meuleman426d0a52013-02-08 15:53:53 +01004514 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004515 /* Due to most likely deauths outstanding we sleep */
4516 /* first to make sure they get processed by fw. */
4517 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004518
Hante Meulemana44aa402014-12-03 21:05:33 +01004519 if (ifp->vif->mbss) {
4520 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
4521 return err;
4522 }
4523
Hante Meuleman5c33a942013-04-02 21:06:18 +02004524 memset(&join_params, 0, sizeof(join_params));
4525 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4526 &join_params, sizeof(join_params));
4527 if (err < 0)
4528 brcmf_err("SET SSID error (%d)\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004529 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004530 if (err < 0)
Hante Meulemana44aa402014-12-03 21:05:33 +01004531 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02004532 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
4533 if (err < 0)
4534 brcmf_err("setting AP mode failed %d\n", err);
4535 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
4536 if (err < 0)
4537 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004538 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
4539 brcmf_fil_iovar_int_set(ifp, "mbss", 0);
Arend van Spriel98027762014-12-21 12:43:53 +01004540 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
4541 ifp->vif->is_11d);
4542 if (err < 0)
4543 brcmf_err("restoring REGULATORY setting failed %d\n",
4544 err);
Hante Meulemana44aa402014-12-03 21:05:33 +01004545 /* Bring device back up so it can be used again */
4546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
4547 if (err < 0)
4548 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004549 } else {
Hante Meuleman37a869e2015-10-29 20:33:17 +01004550 bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004551 bss_enable.enable = cpu_to_le32(0);
4552 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
4553 sizeof(bss_enable));
4554 if (err < 0)
4555 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02004556 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02004557 brcmf_set_mpc(ifp, 1);
Franky Lin52f22fb2016-02-17 11:26:55 +01004558 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004559 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman92121e62015-10-08 20:33:21 +02004560 brcmf_net_setcarrier(ifp, false);
Hante Meuleman426d0a52013-02-08 15:53:53 +01004561
Hante Meuleman1a873342012-09-27 14:17:54 +02004562 return err;
4563}
4564
Hante Meulemana0f07952013-02-08 15:53:47 +01004565static s32
4566brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
4567 struct cfg80211_beacon_data *info)
4568{
Hante Meulemana0f07952013-02-08 15:53:47 +01004569 struct brcmf_if *ifp = netdev_priv(ndev);
4570 s32 err;
4571
4572 brcmf_dbg(TRACE, "Enter\n");
4573
Hante Meulemana0f07952013-02-08 15:53:47 +01004574 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
4575
4576 return err;
4577}
4578
Hante Meuleman1a873342012-09-27 14:17:54 +02004579static int
4580brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
Jouni Malinen89c771e2014-10-10 20:52:40 +03004581 struct station_del_parameters *params)
Hante Meuleman1a873342012-09-27 14:17:54 +02004582{
Hante Meulemana0f07952013-02-08 15:53:47 +01004583 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004584 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004585 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004586 s32 err;
4587
Jouni Malinen89c771e2014-10-10 20:52:40 +03004588 if (!params->mac)
Hante Meuleman1a873342012-09-27 14:17:54 +02004589 return -EFAULT;
4590
Jouni Malinen89c771e2014-10-10 20:52:40 +03004591 brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02004592
Hante Meulemana0f07952013-02-08 15:53:47 +01004593 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
4594 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07004595 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004596 return -EIO;
4597
Jouni Malinen89c771e2014-10-10 20:52:40 +03004598 memcpy(&scbval.ea, params->mac, ETH_ALEN);
Rafał Miłeckiba8b6ae2015-02-08 11:51:47 +01004599 scbval.val = cpu_to_le32(params->reason_code);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004600 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004601 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004602 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01004603 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01004604
Arend van Sprield96b8012012-12-05 15:26:02 +01004605 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02004606 return err;
4607}
4608
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004609static int
4610brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
4611 const u8 *mac, struct station_parameters *params)
4612{
4613 struct brcmf_if *ifp = netdev_priv(ndev);
4614 s32 err;
4615
4616 brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
4617 params->sta_flags_mask, params->sta_flags_set);
4618
4619 /* Ignore all 00 MAC */
4620 if (is_zero_ether_addr(mac))
4621 return 0;
4622
4623 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4624 return 0;
4625
4626 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4627 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
4628 (void *)mac, ETH_ALEN);
4629 else
4630 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
4631 (void *)mac, ETH_ALEN);
4632 if (err < 0)
4633 brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
4634
4635 return err;
4636}
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004637
4638static void
4639brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
4640 struct wireless_dev *wdev,
4641 u16 frame_type, bool reg)
4642{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004643 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004644 u16 mgmt_type;
4645
4646 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
4647
4648 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004649 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004650 if (reg)
4651 vif->mgmt_rx_reg |= BIT(mgmt_type);
4652 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01004653 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004654}
4655
4656
4657static int
4658brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004659 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004660{
4661 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02004662 struct ieee80211_channel *chan = params->chan;
4663 const u8 *buf = params->buf;
4664 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004665 const struct ieee80211_mgmt *mgmt;
4666 struct brcmf_cfg80211_vif *vif;
4667 s32 err = 0;
4668 s32 ie_offset;
4669 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01004670 struct brcmf_fil_action_frame_le *action_frame;
4671 struct brcmf_fil_af_params_le *af_params;
4672 bool ack;
4673 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004674 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004675
4676 brcmf_dbg(TRACE, "Enter\n");
4677
4678 *cookie = 0;
4679
4680 mgmt = (const struct ieee80211_mgmt *)buf;
4681
Hante Meulemana0f07952013-02-08 15:53:47 +01004682 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4683 brcmf_err("Driver only allows MGMT packet type\n");
4684 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004685 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004686
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004687 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4688
Hante Meulemana0f07952013-02-08 15:53:47 +01004689 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4690 /* Right now the only reason to get a probe response */
4691 /* is for p2p listen response or for p2p GO from */
4692 /* wpa_supplicant. Unfortunately the probe is send */
4693 /* on primary ndev, while dongle wants it on the p2p */
4694 /* vif. Since this is only reason for a probe */
4695 /* response to be sent, the vif is taken from cfg. */
4696 /* If ever desired to send proberesp for non p2p */
4697 /* response then data should be checked for */
4698 /* "DIRECT-". Note in future supplicant will take */
4699 /* dedicated p2p wdev to do this and then this 'hack'*/
4700 /* is not needed anymore. */
4701 ie_offset = DOT11_MGMT_HDR_LEN +
4702 DOT11_BCN_PRB_FIXED_LEN;
4703 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004704 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4705 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4706 err = brcmf_vif_set_mgmt_ie(vif,
4707 BRCMF_VNDR_IE_PRBRSP_FLAG,
4708 &buf[ie_offset],
4709 ie_len);
4710 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4711 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004712 } else if (ieee80211_is_action(mgmt->frame_control)) {
4713 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4714 if (af_params == NULL) {
4715 brcmf_err("unable to allocate frame\n");
4716 err = -ENOMEM;
4717 goto exit;
4718 }
4719 action_frame = &af_params->action_frame;
4720 /* Add the packet Id */
4721 action_frame->packet_id = cpu_to_le32(*cookie);
4722 /* Add BSSID */
4723 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4724 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4725 /* Add the length exepted for 802.11 header */
4726 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004727 /* Add the channel. Use the one specified as parameter if any or
4728 * the current one (got from the firmware) otherwise
4729 */
4730 if (chan)
4731 freq = chan->center_freq;
4732 else
4733 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4734 &freq);
4735 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004736 af_params->channel = cpu_to_le32(chan_nr);
4737
4738 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4739 le16_to_cpu(action_frame->len));
4740
4741 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004742 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004743
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004744 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004745 af_params);
4746
4747 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4748 GFP_KERNEL);
4749 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004750 } else {
4751 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4752 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4753 }
4754
Hante Meuleman18e2f612013-02-08 15:53:49 +01004755exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004756 return err;
4757}
4758
4759
4760static int
4761brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4762 struct wireless_dev *wdev,
4763 u64 cookie)
4764{
4765 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4766 struct brcmf_cfg80211_vif *vif;
4767 int err = 0;
4768
4769 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4770
4771 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4772 if (vif == NULL) {
4773 brcmf_err("No p2p device available for probe response\n");
4774 err = -ENODEV;
4775 goto exit;
4776 }
4777 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4778exit:
4779 return err;
4780}
4781
Piotr Haber61730d42013-04-23 12:53:12 +02004782static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4783 struct wireless_dev *wdev,
4784 enum nl80211_crit_proto_id proto,
4785 u16 duration)
4786{
4787 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4788 struct brcmf_cfg80211_vif *vif;
4789
4790 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4791
4792 /* only DHCP support for now */
4793 if (proto != NL80211_CRIT_PROTO_DHCP)
4794 return -EINVAL;
4795
4796 /* suppress and abort scanning */
4797 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4798 brcmf_abort_scanning(cfg);
4799
4800 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4801}
4802
4803static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4804 struct wireless_dev *wdev)
4805{
4806 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4807 struct brcmf_cfg80211_vif *vif;
4808
4809 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4810
4811 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4812 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4813}
4814
Hante Meuleman70b7d942014-07-30 13:20:07 +02004815static s32
4816brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
4817 const struct brcmf_event_msg *e, void *data)
4818{
4819 switch (e->reason) {
4820 case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
4821 brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
4822 break;
4823 case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
4824 brcmf_dbg(TRACE, "TDLS Peer Connected\n");
4825 brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4826 break;
4827 case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
4828 brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
4829 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
4830 break;
4831 }
4832
4833 return 0;
4834}
4835
Arend van Spriel89c2f382013-08-10 12:27:25 +02004836static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4837{
4838 int ret;
4839
4840 switch (oper) {
4841 case NL80211_TDLS_DISCOVERY_REQ:
4842 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4843 break;
4844 case NL80211_TDLS_SETUP:
4845 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4846 break;
4847 case NL80211_TDLS_TEARDOWN:
4848 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4849 break;
4850 default:
4851 brcmf_err("unsupported operation: %d\n", oper);
4852 ret = -EOPNOTSUPP;
4853 }
4854 return ret;
4855}
4856
4857static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
Johannes Berg3b3a0162014-05-19 17:19:31 +02004858 struct net_device *ndev, const u8 *peer,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004859 enum nl80211_tdls_operation oper)
4860{
4861 struct brcmf_if *ifp;
4862 struct brcmf_tdls_iovar_le info;
4863 int ret = 0;
4864
4865 ret = brcmf_convert_nl80211_tdls_oper(oper);
4866 if (ret < 0)
4867 return ret;
4868
4869 ifp = netdev_priv(ndev);
4870 memset(&info, 0, sizeof(info));
4871 info.mode = (u8)ret;
4872 if (peer)
4873 memcpy(info.ea, peer, ETH_ALEN);
4874
4875 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4876 &info, sizeof(info));
4877 if (ret < 0)
4878 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4879
4880 return ret;
4881}
4882
Hante Meuleman5c22fb82016-02-17 11:27:03 +01004883#ifdef CONFIG_PM
4884static int
4885brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
4886 struct cfg80211_gtk_rekey_data *gtk)
4887{
4888 struct brcmf_if *ifp = netdev_priv(ndev);
4889 struct brcmf_gtk_keyinfo_le gtk_le;
4890 int ret;
4891
4892 brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
4893
4894 memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
4895 memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
4896 memcpy(gtk_le.replay_counter, gtk->replay_ctr,
4897 sizeof(gtk_le.replay_counter));
4898
4899 ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
4900 sizeof(gtk_le));
4901 if (ret < 0)
4902 brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
4903
4904 return ret;
4905}
4906#endif
4907
4908static struct cfg80211_ops brcmf_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004909 .add_virtual_intf = brcmf_cfg80211_add_iface,
4910 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004911 .change_virtual_intf = brcmf_cfg80211_change_iface,
4912 .scan = brcmf_cfg80211_scan,
4913 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4914 .join_ibss = brcmf_cfg80211_join_ibss,
4915 .leave_ibss = brcmf_cfg80211_leave_ibss,
4916 .get_station = brcmf_cfg80211_get_station,
Hante Meulemanbf2a7e02015-10-08 20:33:18 +02004917 .dump_station = brcmf_cfg80211_dump_station,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004918 .set_tx_power = brcmf_cfg80211_set_tx_power,
4919 .get_tx_power = brcmf_cfg80211_get_tx_power,
4920 .add_key = brcmf_cfg80211_add_key,
4921 .del_key = brcmf_cfg80211_del_key,
4922 .get_key = brcmf_cfg80211_get_key,
4923 .set_default_key = brcmf_cfg80211_config_default_key,
4924 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4925 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004926 .connect = brcmf_cfg80211_connect,
4927 .disconnect = brcmf_cfg80211_disconnect,
4928 .suspend = brcmf_cfg80211_suspend,
4929 .resume = brcmf_cfg80211_resume,
4930 .set_pmksa = brcmf_cfg80211_set_pmksa,
4931 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004932 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004933 .start_ap = brcmf_cfg80211_start_ap,
4934 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004935 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004936 .del_station = brcmf_cfg80211_del_station,
Hante Meuleman6b89dcb2014-12-21 12:43:52 +01004937 .change_station = brcmf_cfg80211_change_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004938 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4939 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004940 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4941 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4942 .remain_on_channel = brcmf_p2p_remain_on_channel,
4943 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004944 .start_p2p_device = brcmf_p2p_start_device,
4945 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004946 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4947 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004948 .tdls_oper = brcmf_cfg80211_tdls_oper,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004949};
4950
Arend van Spriel3eacf862012-10-22 13:55:30 -07004951struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004952 enum nl80211_iftype type,
4953 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004954{
Hante Meulemana44aa402014-12-03 21:05:33 +01004955 struct brcmf_cfg80211_vif *vif_walk;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004956 struct brcmf_cfg80211_vif *vif;
Hante Meulemana44aa402014-12-03 21:05:33 +01004957 bool mbss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004958
Arend van Spriel33a6b152013-02-08 15:53:39 +01004959 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004960 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004961 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4962 if (!vif)
4963 return ERR_PTR(-ENOMEM);
4964
4965 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004966 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004967
Arend van Spriel3eacf862012-10-22 13:55:30 -07004968 vif->pm_block = pm_block;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004969
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004970 brcmf_init_prof(&vif->profile);
4971
Hante Meulemana44aa402014-12-03 21:05:33 +01004972 if (type == NL80211_IFTYPE_AP) {
4973 mbss = false;
4974 list_for_each_entry(vif_walk, &cfg->vif_list, list) {
4975 if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
4976 mbss = true;
4977 break;
4978 }
4979 }
4980 vif->mbss = mbss;
4981 }
4982
Arend van Spriel3eacf862012-10-22 13:55:30 -07004983 list_add_tail(&vif->list, &cfg->vif_list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004984 return vif;
4985}
4986
Arend van Spriel427dec52014-01-06 12:40:47 +01004987void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004988{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004989 list_del(&vif->list);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004990 kfree(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004991}
4992
Arend van Spriel9df4d542014-01-06 12:40:49 +01004993void brcmf_cfg80211_free_netdev(struct net_device *ndev)
4994{
4995 struct brcmf_cfg80211_vif *vif;
4996 struct brcmf_if *ifp;
4997
4998 ifp = netdev_priv(ndev);
4999 vif = ifp->vif;
5000
Arend van Spriel95ef1232015-08-26 22:15:04 +02005001 if (vif)
5002 brcmf_free_vif(vif);
Arend van Spriel9df4d542014-01-06 12:40:49 +01005003 free_netdev(ndev);
5004}
5005
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005006static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005007{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005008 u32 event = e->event_code;
5009 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005010
5011 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005012 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005013 return true;
5014 }
5015
5016 return false;
5017}
5018
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005019static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005020{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005021 u32 event = e->event_code;
5022 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005023
Hante Meuleman68ca3952014-02-25 20:30:26 +01005024 if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
5025 (event == BRCMF_E_DISASSOC_IND) ||
5026 ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
Arend van Spriel16886732012-12-05 15:26:04 +01005027 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005028 return true;
5029 }
5030 return false;
5031}
5032
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005033static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005034 const struct brcmf_event_msg *e)
5035{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005036 u32 event = e->event_code;
5037 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005038
5039 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005040 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
5041 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005042 return true;
5043 }
5044
5045 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01005046 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005047 return true;
5048 }
5049
5050 return false;
5051}
5052
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005053static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005054{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005055 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005056
5057 kfree(conn_info->req_ie);
5058 conn_info->req_ie = NULL;
5059 conn_info->req_ie_len = 0;
5060 kfree(conn_info->resp_ie);
5061 conn_info->resp_ie = NULL;
5062 conn_info->resp_ie_len = 0;
5063}
5064
Hante Meuleman89286dc2013-02-08 15:53:46 +01005065static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
5066 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005067{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005068 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005069 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005070 u32 req_len;
5071 u32 resp_len;
5072 s32 err = 0;
5073
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005074 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005075
Arend van Sprielac24be62012-10-22 10:36:23 -07005076 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
5077 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005078 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005079 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005080 return err;
5081 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005082 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005083 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02005084 req_len = le32_to_cpu(assoc_info->req_len);
5085 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005086 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005087 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005088 cfg->extra_buf,
5089 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005090 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005091 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005092 return err;
5093 }
5094 conn_info->req_ie_len = req_len;
5095 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005096 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005097 GFP_KERNEL);
5098 } else {
5099 conn_info->req_ie_len = 0;
5100 conn_info->req_ie = NULL;
5101 }
5102 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005103 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005104 cfg->extra_buf,
5105 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005106 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005107 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005108 return err;
5109 }
5110 conn_info->resp_ie_len = resp_len;
5111 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005112 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005113 GFP_KERNEL);
5114 } else {
5115 conn_info->resp_ie_len = 0;
5116 conn_info->resp_ie = NULL;
5117 }
Arend van Spriel16886732012-12-05 15:26:04 +01005118 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
5119 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005120
5121 return err;
5122}
5123
5124static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005125brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005126 struct net_device *ndev,
5127 const struct brcmf_event_msg *e)
5128{
Arend van Sprielc1179032012-10-22 13:55:33 -07005129 struct brcmf_if *ifp = netdev_priv(ndev);
5130 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005131 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
5132 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07005133 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005134 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07005135 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02005136 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005137 u32 freq;
5138 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07005139 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005140
Arend van Sprield96b8012012-12-05 15:26:02 +01005141 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005142
Hante Meuleman89286dc2013-02-08 15:53:46 +01005143 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005144 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005145 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005146
Franky Lina180b832012-10-10 11:13:09 -07005147 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
5148 if (buf == NULL) {
5149 err = -ENOMEM;
5150 goto done;
5151 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005152
Franky Lina180b832012-10-10 11:13:09 -07005153 /* data sent to dongle has to be little endian */
5154 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07005155 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07005156 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07005157
5158 if (err)
5159 goto done;
5160
5161 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02005162 ch.chspec = le16_to_cpu(bi->chanspec);
5163 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005164
Franky Lin83cf17a2013-04-11 13:28:50 +02005165 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005166 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5167 else
5168 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5169
Franky Lin83cf17a2013-04-11 13:28:50 +02005170 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005171 notify_channel = ieee80211_get_channel(wiphy, freq);
5172
Franky Lina180b832012-10-10 11:13:09 -07005173done:
5174 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02005175 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005176 conn_info->req_ie, conn_info->req_ie_len,
5177 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005178 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005179
Arend van Sprielc1179032012-10-22 13:55:33 -07005180 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01005181 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005182 return err;
5183}
5184
5185static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005186brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005187 struct net_device *ndev, const struct brcmf_event_msg *e,
5188 bool completed)
5189{
Arend van Sprielc1179032012-10-22 13:55:33 -07005190 struct brcmf_if *ifp = netdev_priv(ndev);
5191 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005192 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005193
Arend van Sprield96b8012012-12-05 15:26:02 +01005194 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005195
Arend van Sprielc1179032012-10-22 13:55:33 -07005196 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5197 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005198 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01005199 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005200 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01005201 brcmf_update_bss_info(cfg, ifp);
5202 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5203 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005204 }
5205 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02005206 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005207 conn_info->req_ie,
5208 conn_info->req_ie_len,
5209 conn_info->resp_ie,
5210 conn_info->resp_ie_len,
5211 completed ? WLAN_STATUS_SUCCESS :
5212 WLAN_STATUS_AUTH_TIMEOUT,
5213 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01005214 brcmf_dbg(CONN, "Report connect result - connection %s\n",
5215 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005216 }
Arend van Sprield96b8012012-12-05 15:26:02 +01005217 brcmf_dbg(TRACE, "Exit\n");
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005218 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005219}
5220
5221static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005222brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02005223 struct net_device *ndev,
5224 const struct brcmf_event_msg *e, void *data)
5225{
Hante Meulemana44aa402014-12-03 21:05:33 +01005226 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman7ee29602013-02-06 18:40:43 +01005227 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005228 u32 event = e->event_code;
5229 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02005230 struct station_info sinfo;
5231
Arend van Spriel16886732012-12-05 15:26:04 +01005232 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005233 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
5234 ndev != cfg_to_ndev(cfg)) {
5235 brcmf_dbg(CONN, "AP mode link down\n");
5236 complete(&cfg->vif_disabled);
Hante Meulemana44aa402014-12-03 21:05:33 +01005237 if (ifp->vif->mbss)
Arend van Sprielee6e3a32015-08-26 22:14:55 +02005238 brcmf_remove_interface(ifp);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005239 return 0;
5240 }
Hante Meuleman1a873342012-09-27 14:17:54 +02005241
Hante Meuleman1a873342012-09-27 14:17:54 +02005242 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01005243 (reason == BRCMF_E_STATUS_SUCCESS)) {
5244 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02005245 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005246 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02005247 return -EINVAL;
5248 }
5249 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005250 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02005251 generation++;
5252 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01005253 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005254 } else if ((event == BRCMF_E_DISASSOC_IND) ||
5255 (event == BRCMF_E_DEAUTH_IND) ||
5256 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01005257 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02005258 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01005259 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02005260}
5261
5262static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005263brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005264 const struct brcmf_event_msg *e, void *data)
5265{
Arend van Spriel19937322012-11-05 16:22:32 -08005266 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5267 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07005268 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005269 struct ieee80211_channel *chan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005270 s32 err = 0;
5271
Hante Meuleman8851cce2014-07-30 13:20:02 +02005272 if ((e->event_code == BRCMF_E_DEAUTH) ||
5273 (e->event_code == BRCMF_E_DEAUTH_IND) ||
5274 (e->event_code == BRCMF_E_DISASSOC_IND) ||
5275 ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
5276 brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
5277 }
5278
Arend van Spriel967fe2c2014-03-15 17:18:21 +01005279 if (brcmf_is_apmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005280 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005281 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005282 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005283 if (brcmf_is_ibssmode(ifp->vif)) {
Hante Meulemanb0a79082015-12-10 13:43:07 +01005284 brcmf_inform_ibss(cfg, ndev, e->addr);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005285 chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02005286 memcpy(profile->bssid, e->addr, ETH_ALEN);
Antonio Quartullife94f3a2014-01-29 17:53:43 +01005287 cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07005288 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5289 &ifp->vif->sme_state);
5290 set_bit(BRCMF_VIF_STATUS_CONNECTED,
5291 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005292 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005293 brcmf_bss_connect_done(cfg, ndev, e, true);
Hante Meuleman92121e62015-10-08 20:33:21 +02005294 brcmf_net_setcarrier(ifp, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005295 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01005296 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005297 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005298 brcmf_bss_connect_done(cfg, ndev, e, false);
Hante Meuleman42e0ed02016-01-05 11:05:50 +01005299 brcmf_link_down(ifp->vif,
5300 brcmf_map_fw_linkdown_reason(e));
5301 brcmf_init_prof(ndev_to_prof(ndev));
5302 if (ndev != cfg_to_ndev(cfg))
5303 complete(&cfg->vif_disabled);
5304 brcmf_net_setcarrier(ifp, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005305 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005306 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01005307 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07005308 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
5309 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005310 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005311 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005312 }
5313
5314 return err;
5315}
5316
5317static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005318brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005319 const struct brcmf_event_msg *e, void *data)
5320{
Arend van Spriel19937322012-11-05 16:22:32 -08005321 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005322 u32 event = e->event_code;
5323 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005324
5325 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07005326 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08005327 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328 else
Arend van Spriel19937322012-11-05 16:22:32 -08005329 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005330 }
5331
Peter Senna Tschudin12f32372014-05-31 10:14:06 -03005332 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005333}
5334
5335static s32
Arend van Spriel19937322012-11-05 16:22:32 -08005336brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005337 const struct brcmf_event_msg *e, void *data)
5338{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005339 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005340 enum nl80211_key_type key_type;
5341
5342 if (flags & BRCMF_EVENT_MSG_GROUP)
5343 key_type = NL80211_KEYTYPE_GROUP;
5344 else
5345 key_type = NL80211_KEYTYPE_PAIRWISE;
5346
Arend van Spriel19937322012-11-05 16:22:32 -08005347 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348 NULL, GFP_KERNEL);
5349
5350 return 0;
5351}
5352
Arend van Sprield3c0b632013-02-08 15:53:37 +01005353static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
5354 const struct brcmf_event_msg *e, void *data)
5355{
5356 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5357 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
5358 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5359 struct brcmf_cfg80211_vif *vif;
5360
Hante Meuleman37a869e2015-10-29 20:33:17 +01005361 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
Arend van Sprield3c0b632013-02-08 15:53:37 +01005362 ifevent->action, ifevent->flags, ifevent->ifidx,
Hante Meuleman37a869e2015-10-29 20:33:17 +01005363 ifevent->bsscfgidx);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005364
Arend van Sprield3c0b632013-02-08 15:53:37 +01005365 mutex_lock(&event->vif_event_lock);
5366 event->action = ifevent->action;
5367 vif = event->vif;
5368
5369 switch (ifevent->action) {
5370 case BRCMF_E_IF_ADD:
5371 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08005372 if (!cfg->vif_event.vif) {
5373 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005374 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08005375 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005376
5377 ifp->vif = vif;
5378 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02005379 if (ifp->ndev) {
5380 vif->wdev.netdev = ifp->ndev;
5381 ifp->ndev->ieee80211_ptr = &vif->wdev;
5382 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
5383 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01005384 mutex_unlock(&event->vif_event_lock);
5385 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01005386 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01005387
5388 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01005389 mutex_unlock(&event->vif_event_lock);
5390 /* event may not be upon user request */
5391 if (brcmf_cfg80211_vif_event_armed(cfg))
5392 wake_up(&event->vif_wq);
5393 return 0;
5394
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01005395 case BRCMF_E_IF_CHANGE:
5396 mutex_unlock(&event->vif_event_lock);
5397 wake_up(&event->vif_wq);
5398 return 0;
5399
Arend van Sprield3c0b632013-02-08 15:53:37 +01005400 default:
5401 mutex_unlock(&event->vif_event_lock);
5402 break;
5403 }
5404 return -EINVAL;
5405}
5406
Arend van Spriel5b435de2011-10-05 13:19:03 +02005407static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
5408{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005409 conf->frag_threshold = (u32)-1;
5410 conf->rts_threshold = (u32)-1;
5411 conf->retry_short = (u32)-1;
5412 conf->retry_long = (u32)-1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005413}
5414
Arend van Spriel5c36b992012-11-14 18:46:05 -08005415static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005416{
Arend van Spriel5c36b992012-11-14 18:46:05 -08005417 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
5418 brcmf_notify_connect_status);
5419 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
5420 brcmf_notify_connect_status);
5421 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
5422 brcmf_notify_connect_status);
5423 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
5424 brcmf_notify_connect_status);
5425 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
5426 brcmf_notify_connect_status);
5427 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
5428 brcmf_notify_connect_status);
5429 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
5430 brcmf_notify_roaming_status);
5431 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
5432 brcmf_notify_mic_status);
5433 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
5434 brcmf_notify_connect_status);
5435 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
5436 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005437 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
5438 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005439 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005440 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01005441 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
5442 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01005443 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
5444 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01005445 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
5446 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01005447 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
5448 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005449}
5450
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005451static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005452{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005453 kfree(cfg->conf);
5454 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005455 kfree(cfg->extra_buf);
5456 cfg->extra_buf = NULL;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005457 kfree(cfg->wowl.nd);
5458 cfg->wowl.nd = NULL;
5459 kfree(cfg->wowl.nd_info);
5460 cfg->wowl.nd_info = NULL;
Hante Meulemand5367332016-02-17 11:26:51 +01005461 kfree(cfg->escan_info.escan_buf);
5462 cfg->escan_info.escan_buf = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005463}
5464
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005465static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005466{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005467 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
5468 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005469 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005470 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5471 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005472 goto init_priv_mem_out;
Hante Meuleman3021ad92016-01-05 11:05:45 +01005473 cfg->wowl.nd = kzalloc(sizeof(*cfg->wowl.nd) + sizeof(u32), GFP_KERNEL);
5474 if (!cfg->wowl.nd)
5475 goto init_priv_mem_out;
5476 cfg->wowl.nd_info = kzalloc(sizeof(*cfg->wowl.nd_info) +
5477 sizeof(struct cfg80211_wowlan_nd_match *),
5478 GFP_KERNEL);
5479 if (!cfg->wowl.nd_info)
5480 goto init_priv_mem_out;
Hante Meulemand5367332016-02-17 11:26:51 +01005481 cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
5482 if (!cfg->escan_info.escan_buf)
5483 goto init_priv_mem_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005484
5485 return 0;
5486
5487init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005488 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005489
5490 return -ENOMEM;
5491}
5492
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005493static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005494{
5495 s32 err = 0;
5496
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005497 cfg->scan_request = NULL;
5498 cfg->pwr_save = true;
Hante Meuleman68ca3952014-02-25 20:30:26 +01005499 cfg->active_scan = true; /* we do active scan per default */
5500 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005501 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005502 if (err)
5503 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08005504 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005505 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005506 brcmf_init_escan(cfg);
5507 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01005508 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005509 return err;
5510}
5511
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005512static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005513{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005514 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005515 brcmf_abort_scanning(cfg);
5516 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005517}
5518
Arend van Sprield3c0b632013-02-08 15:53:37 +01005519static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
5520{
5521 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01005522 mutex_init(&event->vif_event_lock);
5523}
5524
Hante Meuleman1119e232015-11-25 11:32:42 +01005525static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005526{
Hante Meuleman1119e232015-11-25 11:32:42 +01005527 s32 err;
5528 u32 bcn_timeout;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005529 __le32 roamtrigger[2];
5530 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005531
Hante Meuleman1119e232015-11-25 11:32:42 +01005532 /* Configure beacon timeout value based upon roaming setting */
Hante Meuleman7d34b052016-01-02 09:41:41 +01005533 if (ifp->drvr->settings->roamoff)
Hante Meuleman1119e232015-11-25 11:32:42 +01005534 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF;
5535 else
5536 bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
5537 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
5538 if (err) {
5539 brcmf_err("bcn_timeout error (%d)\n", err);
5540 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005541 }
5542
Hante Meuleman1119e232015-11-25 11:32:42 +01005543 /* Enable/Disable built-in roaming to allow supplicant to take care of
5544 * roaming.
Arend van Spriel5b435de2011-10-05 13:19:03 +02005545 */
Hante Meuleman68ca3952014-02-25 20:30:26 +01005546 brcmf_dbg(INFO, "Internal Roaming = %s\n",
Hante Meuleman7d34b052016-01-02 09:41:41 +01005547 ifp->drvr->settings->roamoff ? "Off" : "On");
5548 err = brcmf_fil_iovar_int_set(ifp, "roam_off",
5549 ifp->drvr->settings->roamoff);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005550 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005551 brcmf_err("roam_off error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005552 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005553 }
5554
Arend van Sprielf588bc02011-10-12 20:51:22 +02005555 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5556 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005557 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005558 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005559 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005560 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005561 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005562 }
5563
Arend van Sprielf588bc02011-10-12 20:51:22 +02005564 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5565 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005566 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005567 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005568 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005569 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Hante Meuleman1119e232015-11-25 11:32:42 +01005570 goto roam_setup_done;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005571 }
5572
Hante Meuleman1119e232015-11-25 11:32:42 +01005573roam_setup_done:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005574 return err;
5575}
5576
5577static s32
Hante Meuleman1678ba82015-12-10 13:43:00 +01005578brcmf_dongle_scantime(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005579{
5580 s32 err = 0;
5581
Arend van Sprielac24be62012-10-22 10:36:23 -07005582 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005583 BRCMF_SCAN_CHANNEL_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005584 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005585 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005586 goto dongle_scantime_out;
5587 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005588 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005589 BRCMF_SCAN_UNASSOC_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005590 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005591 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005592 goto dongle_scantime_out;
5593 }
5594
Arend van Sprielac24be62012-10-22 10:36:23 -07005595 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman1678ba82015-12-10 13:43:00 +01005596 BRCMF_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005597 if (err) {
Hante Meuleman1678ba82015-12-10 13:43:00 +01005598 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005599 goto dongle_scantime_out;
5600 }
5601
5602dongle_scantime_out:
5603 return err;
5604}
5605
Arend van Sprielb48d8912014-07-12 08:49:41 +02005606static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
5607 struct brcmu_chan *ch)
5608{
5609 u32 ht40_flag;
5610
5611 ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
5612 if (ch->sb == BRCMU_CHAN_SB_U) {
5613 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5614 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5615 channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
5616 } else {
5617 /* It should be one of
5618 * IEEE80211_CHAN_NO_HT40 or
5619 * IEEE80211_CHAN_NO_HT40PLUS
5620 */
5621 channel->flags &= ~IEEE80211_CHAN_NO_HT40;
5622 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5623 channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
5624 }
5625}
5626
5627static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
5628 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005629{
5630 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielb48d8912014-07-12 08:49:41 +02005631 struct ieee80211_supported_band *band;
5632 struct ieee80211_channel *channel;
5633 struct wiphy *wiphy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005634 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005635 struct brcmu_chan ch;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005636 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005637 u8 *pbuf;
5638 u32 i, j;
5639 u32 total;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005640 u32 chaninfo;
Hante Meulemand48200b2013-04-03 12:40:29 +02005641 u32 index;
Hante Meulemand48200b2013-04-03 12:40:29 +02005642
5643 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5644
5645 if (pbuf == NULL)
5646 return -ENOMEM;
5647
5648 list = (struct brcmf_chanspec_list *)pbuf;
5649
5650 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5651 BRCMF_DCMD_MEDLEN);
5652 if (err) {
5653 brcmf_err("get chanspecs error (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005654 goto fail_pbuf;
Hante Meulemand48200b2013-04-03 12:40:29 +02005655 }
5656
Arend van Sprielb48d8912014-07-12 08:49:41 +02005657 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel58de92d2015-04-14 20:10:24 +02005658 band = wiphy->bands[IEEE80211_BAND_2GHZ];
5659 if (band)
5660 for (i = 0; i < band->n_channels; i++)
5661 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
5662 band = wiphy->bands[IEEE80211_BAND_5GHZ];
5663 if (band)
5664 for (i = 0; i < band->n_channels; i++)
5665 band->channels[i].flags = IEEE80211_CHAN_DISABLED;
Hante Meulemand48200b2013-04-03 12:40:29 +02005666
5667 total = le32_to_cpu(list->count);
5668 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005669 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5670 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005671
Franky Lin83cf17a2013-04-11 13:28:50 +02005672 if (ch.band == BRCMU_CHAN_BAND_2G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005673 band = wiphy->bands[IEEE80211_BAND_2GHZ];
Franky Lin83cf17a2013-04-11 13:28:50 +02005674 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005675 band = wiphy->bands[IEEE80211_BAND_5GHZ];
Hante Meulemand48200b2013-04-03 12:40:29 +02005676 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005677 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005678 continue;
5679 }
Arend van Spriel58de92d2015-04-14 20:10:24 +02005680 if (!band)
5681 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005682 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005683 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005684 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005685 if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
Arend van Sprielee942ec2014-05-12 10:47:38 +02005686 ch.bw == BRCMU_CHAN_BW_80)
5687 continue;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005688
5689 channel = band->channels;
5690 index = band->n_channels;
5691 for (j = 0; j < band->n_channels; j++) {
5692 if (channel[j].hw_value == ch.chnum) {
5693 index = j;
Hante Meulemand48200b2013-04-03 12:40:29 +02005694 break;
5695 }
5696 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005697 channel[index].center_freq =
5698 ieee80211_channel_to_frequency(ch.chnum, band->band);
5699 channel[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005700
Arend van Sprielb48d8912014-07-12 08:49:41 +02005701 /* assuming the chanspecs order is HT20,
5702 * HT40 upper, HT40 lower, and VHT80.
5703 */
5704 if (ch.bw == BRCMU_CHAN_BW_80) {
5705 channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
5706 } else if (ch.bw == BRCMU_CHAN_BW_40) {
5707 brcmf_update_bw40_channel_flag(&channel[index], &ch);
5708 } else {
Arend van Spriel58de92d2015-04-14 20:10:24 +02005709 /* enable the channel and disable other bandwidths
5710 * for now as mentioned order assure they are enabled
5711 * for subsequent chanspecs.
Arend van Sprielee942ec2014-05-12 10:47:38 +02005712 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02005713 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
5714 IEEE80211_CHAN_NO_80MHZ;
5715 ch.bw = BRCMU_CHAN_BW_20;
5716 cfg->d11inf.encchspec(&ch);
5717 chaninfo = ch.chspec;
5718 err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
5719 &chaninfo);
5720 if (!err) {
5721 if (chaninfo & WL_CHAN_RADAR)
5722 channel[index].flags |=
5723 (IEEE80211_CHAN_RADAR |
5724 IEEE80211_CHAN_NO_IR);
5725 if (chaninfo & WL_CHAN_PASSIVE)
5726 channel[index].flags |=
5727 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005728 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005729 }
5730 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005731
Arend van Sprielb48d8912014-07-12 08:49:41 +02005732fail_pbuf:
Hante Meulemand48200b2013-04-03 12:40:29 +02005733 kfree(pbuf);
5734 return err;
5735}
5736
Arend van Sprielb48d8912014-07-12 08:49:41 +02005737static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005738{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005739 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5740 struct ieee80211_supported_band *band;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005741 struct brcmf_fil_bwcap_le band_bwcap;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005742 struct brcmf_chanspec_list *list;
5743 u8 *pbuf;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005744 u32 val;
5745 int err;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005746 struct brcmu_chan ch;
5747 u32 num_chan;
5748 int i, j;
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005749
5750 /* verify support for bw_cap command */
5751 val = WLC_BAND_5G;
5752 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
5753
5754 if (!err) {
5755 /* only set 2G bandwidth using bw_cap command */
5756 band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
5757 band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
5758 err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
5759 sizeof(band_bwcap));
5760 } else {
5761 brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
5762 val = WLC_N_BW_40ALL;
5763 err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
5764 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02005765
5766 if (!err) {
5767 /* update channel info in 2G band */
5768 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5769
5770 if (pbuf == NULL)
5771 return -ENOMEM;
5772
5773 ch.band = BRCMU_CHAN_BAND_2G;
5774 ch.bw = BRCMU_CHAN_BW_40;
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005775 ch.sb = BRCMU_CHAN_SB_NONE;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005776 ch.chnum = 0;
5777 cfg->d11inf.encchspec(&ch);
5778
5779 /* pass encoded chanspec in query */
5780 *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
5781
5782 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5783 BRCMF_DCMD_MEDLEN);
5784 if (err) {
5785 brcmf_err("get chanspecs error (%d)\n", err);
5786 kfree(pbuf);
5787 return err;
5788 }
5789
5790 band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
5791 list = (struct brcmf_chanspec_list *)pbuf;
5792 num_chan = le32_to_cpu(list->count);
5793 for (i = 0; i < num_chan; i++) {
5794 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5795 cfg->d11inf.decchspec(&ch);
5796 if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
5797 continue;
5798 if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
5799 continue;
5800 for (j = 0; j < band->n_channels; j++) {
5801 if (band->channels[j].hw_value == ch.chnum)
5802 break;
5803 }
5804 if (WARN_ON(j == band->n_channels))
5805 continue;
5806
5807 brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
5808 }
Hante Meulemanfac7d2a2014-09-11 22:51:30 +02005809 kfree(pbuf);
Arend van Sprielb48d8912014-07-12 08:49:41 +02005810 }
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005811 return err;
5812}
5813
Arend van Spriel2375d972014-01-06 12:40:41 +01005814static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5815{
5816 u32 band, mimo_bwcap;
5817 int err;
5818
5819 band = WLC_BAND_2G;
5820 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5821 if (!err) {
5822 bw_cap[IEEE80211_BAND_2GHZ] = band;
5823 band = WLC_BAND_5G;
5824 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5825 if (!err) {
5826 bw_cap[IEEE80211_BAND_5GHZ] = band;
5827 return;
5828 }
5829 WARN_ON(1);
5830 return;
5831 }
5832 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5833 mimo_bwcap = 0;
5834 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5835 if (err)
5836 /* assume 20MHz if firmware does not give a clue */
5837 mimo_bwcap = WLC_N_BW_20ALL;
5838
5839 switch (mimo_bwcap) {
5840 case WLC_N_BW_40ALL:
5841 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5842 /* fall-thru */
5843 case WLC_N_BW_20IN2G_40IN5G:
5844 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5845 /* fall-thru */
5846 case WLC_N_BW_20ALL:
5847 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5848 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5849 break;
5850 default:
5851 brcmf_err("invalid mimo_bw_cap value\n");
5852 }
5853}
Hante Meulemand48200b2013-04-03 12:40:29 +02005854
Arend van Spriel18d6c532014-05-12 10:47:35 +02005855static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
5856 u32 bw_cap[2], u32 nchain)
5857{
5858 band->ht_cap.ht_supported = true;
5859 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5860 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5861 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5862 }
5863 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5864 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5865 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5866 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5867 memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
5868 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5869}
5870
5871static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
5872{
5873 u16 mcs_map;
5874 int i;
5875
5876 for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
5877 mcs_map = (mcs_map << 2) | supp;
5878
5879 return cpu_to_le16(mcs_map);
5880}
5881
5882static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005883 u32 bw_cap[2], u32 nchain, u32 txstreams,
5884 u32 txbf_bfe_cap, u32 txbf_bfr_cap)
Arend van Spriel18d6c532014-05-12 10:47:35 +02005885{
5886 __le16 mcs_map;
5887
5888 /* not allowed in 2.4G band */
5889 if (band->band == IEEE80211_BAND_2GHZ)
5890 return;
5891
5892 band->vht_cap.vht_supported = true;
5893 /* 80MHz is mandatory */
5894 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
5895 if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
5896 band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
5897 band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
5898 }
5899 /* all support 256-QAM */
5900 mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
5901 band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
5902 band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005903
5904 /* Beamforming support information */
5905 if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP)
5906 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
5907 if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP)
5908 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
5909 if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP)
5910 band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
5911 if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP)
5912 band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
5913
5914 if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) {
5915 band->vht_cap.cap |=
5916 (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
5917 band->vht_cap.cap |= ((txstreams - 1) <<
5918 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
5919 band->vht_cap.cap |=
5920 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
5921 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005922}
5923
Arend van Sprielb48d8912014-07-12 08:49:41 +02005924static int brcmf_setup_wiphybands(struct wiphy *wiphy)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005925{
Arend van Sprielb48d8912014-07-12 08:49:41 +02005926 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07005927 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel18d6c532014-05-12 10:47:35 +02005928 u32 nmode = 0;
5929 u32 vhtmode = 0;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005930 u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
Daniel Kim4aca7a12014-02-25 20:30:36 +01005931 u32 rxchain;
5932 u32 nchain;
Arend van Sprielb48d8912014-07-12 08:49:41 +02005933 int err;
Hante Meulemand48200b2013-04-03 12:40:29 +02005934 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005935 struct ieee80211_supported_band *band;
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005936 u32 txstreams = 0;
5937 u32 txbf_bfe_cap = 0;
5938 u32 txbf_bfr_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005939
Arend van Spriel18d6c532014-05-12 10:47:35 +02005940 (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
Hante Meulemand48200b2013-04-03 12:40:29 +02005941 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5942 if (err) {
5943 brcmf_err("nmode error (%d)\n", err);
5944 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005945 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005946 }
Arend van Spriel18d6c532014-05-12 10:47:35 +02005947 brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
5948 nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
5949 bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005950
Daniel Kim4aca7a12014-02-25 20:30:36 +01005951 err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
5952 if (err) {
5953 brcmf_err("rxchain error (%d)\n", err);
5954 nchain = 1;
5955 } else {
5956 for (nchain = 0; rxchain; nchain++)
5957 rxchain = rxchain & (rxchain - 1);
5958 }
5959 brcmf_dbg(INFO, "nchain=%d\n", nchain);
5960
Arend van Sprielb48d8912014-07-12 08:49:41 +02005961 err = brcmf_construct_chaninfo(cfg, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005962 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02005963 brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
Hante Meulemand48200b2013-04-03 12:40:29 +02005964 return err;
5965 }
5966
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005967 if (vhtmode) {
5968 (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams);
5969 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap",
5970 &txbf_bfe_cap);
5971 (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap",
5972 &txbf_bfr_cap);
5973 }
5974
Arend van Sprielb48d8912014-07-12 08:49:41 +02005975 wiphy = cfg_to_wiphy(cfg);
5976 for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
5977 band = wiphy->bands[i];
5978 if (band == NULL)
Arend van Spriel2375d972014-01-06 12:40:41 +01005979 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005980
Arend van Spriel18d6c532014-05-12 10:47:35 +02005981 if (nmode)
5982 brcmf_update_ht_cap(band, bw_cap, nchain);
5983 if (vhtmode)
Hante Meuleman7bf65aa2015-11-25 11:32:43 +01005984 brcmf_update_vht_cap(band, bw_cap, nchain, txstreams,
5985 txbf_bfe_cap, txbf_bfr_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005986 }
5987
Arend van Sprielb48d8912014-07-12 08:49:41 +02005988 return 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005989}
5990
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02005991static const struct ieee80211_txrx_stypes
5992brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
5993 [NL80211_IFTYPE_STATION] = {
5994 .tx = 0xffff,
5995 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
5996 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
5997 },
5998 [NL80211_IFTYPE_P2P_CLIENT] = {
5999 .tx = 0xffff,
6000 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6001 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6002 },
6003 [NL80211_IFTYPE_P2P_GO] = {
6004 .tx = 0xffff,
6005 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
6006 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
6007 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
6008 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
6009 BIT(IEEE80211_STYPE_AUTH >> 4) |
6010 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
6011 BIT(IEEE80211_STYPE_ACTION >> 4)
6012 },
6013 [NL80211_IFTYPE_P2P_DEVICE] = {
6014 .tx = 0xffff,
6015 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
6016 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
6017 }
6018};
6019
Arend van Spriel0882dda2015-08-20 22:06:03 +02006020/**
6021 * brcmf_setup_ifmodes() - determine interface modes and combinations.
6022 *
6023 * @wiphy: wiphy object.
6024 * @ifp: interface object needed for feat module api.
6025 *
6026 * The interface modes and combinations are determined dynamically here
6027 * based on firmware functionality.
6028 *
6029 * no p2p and no mbss:
6030 *
6031 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6032 *
6033 * no p2p and mbss:
6034 *
6035 * #STA <= 1, #AP <= 1, channels = 1, 2 total
6036 * #AP <= 4, matching BI, channels = 1, 4 total
6037 *
6038 * p2p, no mchan, and mbss:
6039 *
6040 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
6041 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6042 * #AP <= 4, matching BI, channels = 1, 4 total
6043 *
6044 * p2p, mchan, and mbss:
6045 *
6046 * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
6047 * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
6048 * #AP <= 4, matching BI, channels = 1, 4 total
6049 */
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006050static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
6051{
6052 struct ieee80211_iface_combination *combo = NULL;
Arend van Spriel0882dda2015-08-20 22:06:03 +02006053 struct ieee80211_iface_limit *c0_limits = NULL;
6054 struct ieee80211_iface_limit *p2p_limits = NULL;
6055 struct ieee80211_iface_limit *mbss_limits = NULL;
6056 bool mbss, p2p;
6057 int i, c, n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006058
Arend van Spriel0882dda2015-08-20 22:06:03 +02006059 mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
6060 p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
6061
6062 n_combos = 1 + !!p2p + !!mbss;
6063 combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006064 if (!combo)
6065 goto err;
6066
Arend van Spriel0882dda2015-08-20 22:06:03 +02006067 c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
6068 if (!c0_limits)
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006069 goto err;
6070
Arend van Spriel0882dda2015-08-20 22:06:03 +02006071 if (p2p) {
6072 p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
6073 if (!p2p_limits)
6074 goto err;
6075 }
6076
6077 if (mbss) {
6078 mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
6079 if (!mbss_limits)
6080 goto err;
6081 }
6082
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006083 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
6084 BIT(NL80211_IFTYPE_ADHOC) |
6085 BIT(NL80211_IFTYPE_AP);
6086
Arend van Spriel0882dda2015-08-20 22:06:03 +02006087 c = 0;
6088 i = 0;
6089 combo[c].num_different_channels = 1;
6090 c0_limits[i].max = 1;
6091 c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6092 if (p2p) {
6093 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
6094 combo[c].num_different_channels = 2;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006095 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
6096 BIT(NL80211_IFTYPE_P2P_GO) |
6097 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel0882dda2015-08-20 22:06:03 +02006098 c0_limits[i].max = 1;
6099 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6100 c0_limits[i].max = 1;
6101 c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
6102 BIT(NL80211_IFTYPE_P2P_GO);
6103 } else {
6104 c0_limits[i].max = 1;
6105 c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006106 }
Arend van Spriel0882dda2015-08-20 22:06:03 +02006107 combo[c].max_interfaces = i;
6108 combo[c].n_limits = i;
6109 combo[c].limits = c0_limits;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006110
Arend van Spriel0882dda2015-08-20 22:06:03 +02006111 if (p2p) {
6112 c++;
6113 i = 0;
6114 combo[c].num_different_channels = 1;
6115 p2p_limits[i].max = 1;
6116 p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
6117 p2p_limits[i].max = 1;
6118 p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
6119 p2p_limits[i].max = 1;
6120 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
6121 p2p_limits[i].max = 1;
6122 p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
6123 combo[c].max_interfaces = i;
6124 combo[c].n_limits = i;
6125 combo[c].limits = p2p_limits;
6126 }
6127
6128 if (mbss) {
6129 c++;
6130 combo[c].beacon_int_infra_match = true;
6131 combo[c].num_different_channels = 1;
6132 mbss_limits[0].max = 4;
6133 mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
6134 combo[c].max_interfaces = 4;
6135 combo[c].n_limits = 1;
6136 combo[c].limits = mbss_limits;
6137 }
6138 wiphy->n_iface_combinations = n_combos;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006139 wiphy->iface_combinations = combo;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006140 return 0;
6141
6142err:
Arend van Spriel0882dda2015-08-20 22:06:03 +02006143 kfree(c0_limits);
6144 kfree(p2p_limits);
6145 kfree(mbss_limits);
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006146 kfree(combo);
6147 return -ENOMEM;
6148}
6149
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006150static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6151{
6152 /* scheduled scan settings */
6153 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6154 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6155 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6156 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6157}
6158
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006159#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006160static struct wiphy_wowlan_support brcmf_wowlan_support = {
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006161 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
Hante Meulemanb9a82f82014-10-28 14:56:06 +01006162 .n_patterns = BRCMF_WOWL_MAXPATTERNS,
6163 .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
6164 .pattern_min_len = 1,
6165 .max_pkt_offset = 1500,
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006166};
6167#endif
6168
Hante Meuleman3021ad92016-01-05 11:05:45 +01006169static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006170{
6171#ifdef CONFIG_PM
Hante Meuleman3021ad92016-01-05 11:05:45 +01006172 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006173
6174 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006175 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
6176 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
6177 init_waitqueue_head(&cfg->wowl.nd_data_wait);
Hante Meuleman3021ad92016-01-05 11:05:45 +01006178 }
6179 }
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006180 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
6181 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
6182 brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
6183 }
6184
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006185 wiphy->wowlan = &brcmf_wowlan_support;
6186#endif
6187}
6188
Arend van Sprielb48d8912014-07-12 08:49:41 +02006189static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006190{
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006191 struct brcmf_pub *drvr = ifp->drvr;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006192 const struct ieee80211_iface_combination *combo;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006193 struct ieee80211_supported_band *band;
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006194 u16 max_interfaces = 0;
Arend van Spriel58de92d2015-04-14 20:10:24 +02006195 __le32 bandlist[3];
6196 u32 n_bands;
6197 int err, i;
6198
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006199 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
6200 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Hante Meuleman6c404f32015-12-10 13:43:03 +01006201 wiphy->max_num_pmkids = BRCMF_MAXPMKID;
Pontus Fuchs2e5f66f2015-06-11 00:12:18 +02006202
6203 err = brcmf_setup_ifmodes(wiphy, ifp);
6204 if (err)
6205 return err;
6206
Rafał Miłecki50f32e22015-08-20 00:16:42 +02006207 for (i = 0, combo = wiphy->iface_combinations;
6208 i < wiphy->n_iface_combinations; i++, combo++) {
6209 max_interfaces = max(max_interfaces, combo->max_interfaces);
6210 }
6211
6212 for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
6213 i++) {
Rafa? Mi?eckie3faa862015-07-09 17:07:08 +02006214 u8 *addr = drvr->addresses[i].addr;
6215
6216 memcpy(addr, drvr->mac, ETH_ALEN);
6217 if (i) {
6218 addr[0] |= BIT(1);
6219 addr[ETH_ALEN - 1] ^= i;
6220 }
6221 }
6222 wiphy->addresses = drvr->addresses;
6223 wiphy->n_addresses = i;
6224
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006225 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
6226 wiphy->cipher_suites = __wl_cipher_suites;
6227 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
6228 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
6229 WIPHY_FLAG_OFFCHAN_TX |
Hante Meulemana7b82d42015-12-10 13:43:04 +01006230 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
6231 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
6232 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman7d34b052016-01-02 09:41:41 +01006233 if (!ifp->drvr->settings->roamoff)
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006234 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
6235 wiphy->mgmt_stypes = brcmf_txrx_stypes;
6236 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel7a7a87d2015-04-14 20:10:27 +02006237 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
6238 brcmf_wiphy_pno_params(wiphy);
Arend van Sprielaa70b4f2014-07-12 08:49:40 +02006239
6240 /* vendor commands/events support */
6241 wiphy->vendor_commands = brcmf_vendor_cmds;
6242 wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
6243
Hante Meuleman4eb3af72014-09-30 10:23:18 +02006244 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
Hante Meuleman3021ad92016-01-05 11:05:45 +01006245 brcmf_wiphy_wowl_params(wiphy, ifp);
Arend van Spriel58de92d2015-04-14 20:10:24 +02006246 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
6247 sizeof(bandlist));
6248 if (err) {
6249 brcmf_err("could not obtain band info: err=%d\n", err);
6250 return err;
6251 }
6252 /* first entry in bandlist is number of bands */
6253 n_bands = le32_to_cpu(bandlist[0]);
6254 for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
6255 if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
6256 band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
6257 GFP_KERNEL);
6258 if (!band)
6259 return -ENOMEM;
6260
6261 band->channels = kmemdup(&__wl_2ghz_channels,
6262 sizeof(__wl_2ghz_channels),
6263 GFP_KERNEL);
6264 if (!band->channels) {
6265 kfree(band);
6266 return -ENOMEM;
6267 }
6268
6269 band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
6270 wiphy->bands[IEEE80211_BAND_2GHZ] = band;
6271 }
6272 if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
6273 band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
6274 GFP_KERNEL);
6275 if (!band)
6276 return -ENOMEM;
6277
6278 band->channels = kmemdup(&__wl_5ghz_channels,
6279 sizeof(__wl_5ghz_channels),
6280 GFP_KERNEL);
6281 if (!band->channels) {
6282 kfree(band);
6283 return -ENOMEM;
6284 }
6285
6286 band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
6287 wiphy->bands[IEEE80211_BAND_5GHZ] = band;
6288 }
6289 }
6290 err = brcmf_setup_wiphybands(wiphy);
6291 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006292}
6293
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006294static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006295{
6296 struct net_device *ndev;
6297 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01006298 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006299 s32 power_mode;
6300 s32 err = 0;
6301
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006302 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006303 return err;
6304
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006305 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006306 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01006307 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006308
Hante Meuleman40a23292013-01-02 15:22:51 +01006309 /* make sure RF is ready for work */
6310 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
6311
Hante Meuleman1678ba82015-12-10 13:43:00 +01006312 brcmf_dongle_scantime(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006313
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006314 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01006315 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006316 if (err)
6317 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01006318 brcmf_dbg(INFO, "power save set to %s\n",
6319 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02006320
Hante Meuleman1119e232015-11-25 11:32:42 +01006321 err = brcmf_dongle_roam(ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006322 if (err)
6323 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07006324 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
6325 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01006326 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006327 goto default_conf_out;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006328
Franky Lin52f22fb2016-02-17 11:26:55 +01006329 brcmf_configure_arp_nd_offload(ifp, true);
Hante Meulemanb3657452013-05-27 21:09:53 +02006330
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006331 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01006332default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02006333
6334 return err;
6335
6336}
6337
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006338static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006339{
Arend van Sprielc1179032012-10-22 13:55:33 -07006340 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006341
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006342 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006343}
6344
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006345static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006346{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006347 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07006348
Arend van Spriel5b435de2011-10-05 13:19:03 +02006349 /*
6350 * While going down, if associated with AP disassociate
6351 * from AP to save power
6352 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01006353 if (check_vif_up(ifp->vif)) {
Arend van Spriel9b7a0dd2015-01-25 20:31:33 +01006354 brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006355
6356 /* Make sure WPA_Supplicant receives all the event
6357 generated due to DISASSOC call to the fw to keep
6358 the state fw and WPA_Supplicant state consistent
6359 */
6360 brcmf_delay(500);
6361 }
6362
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006363 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07006364 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006365
Arend van Spriel5b435de2011-10-05 13:19:03 +02006366 return 0;
6367}
6368
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006369s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006370{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006371 struct brcmf_if *ifp = netdev_priv(ndev);
6372 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006373 s32 err = 0;
6374
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006375 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006376 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006377 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006378
6379 return err;
6380}
6381
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006382s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02006383{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006384 struct brcmf_if *ifp = netdev_priv(ndev);
6385 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02006386 s32 err = 0;
6387
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006388 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08006389 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02006390 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02006391
6392 return err;
6393}
6394
Arend van Spriela7965fb2013-04-11 17:08:37 +02006395enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
6396{
6397 struct wireless_dev *wdev = &ifp->vif->wdev;
6398
6399 return wdev->iftype;
6400}
6401
Hante Meulemanbfe81972014-10-28 14:56:16 +01006402bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
6403 unsigned long state)
Arend van Spriel9f440b72013-02-08 15:53:36 +01006404{
6405 struct brcmf_cfg80211_vif *vif;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006406
6407 list_for_each_entry(vif, &cfg->vif_list, list) {
6408 if (test_bit(state, &vif->sme_state))
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006409 return true;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006410 }
Rasmus Villemoese843bb12014-06-22 20:50:40 +02006411 return false;
Arend van Spriel9f440b72013-02-08 15:53:36 +01006412}
Arend van Sprield3c0b632013-02-08 15:53:37 +01006413
6414static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
6415 u8 action)
6416{
6417 u8 evt_action;
6418
6419 mutex_lock(&event->vif_event_lock);
6420 evt_action = event->action;
6421 mutex_unlock(&event->vif_event_lock);
6422 return evt_action == action;
6423}
6424
6425void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
6426 struct brcmf_cfg80211_vif *vif)
6427{
6428 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6429
6430 mutex_lock(&event->vif_event_lock);
6431 event->vif = vif;
6432 event->action = 0;
6433 mutex_unlock(&event->vif_event_lock);
6434}
6435
6436bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
6437{
6438 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6439 bool armed;
6440
6441 mutex_lock(&event->vif_event_lock);
6442 armed = event->vif != NULL;
6443 mutex_unlock(&event->vif_event_lock);
6444
6445 return armed;
6446}
Arend van Spriela9eb0c42016-02-17 11:26:50 +01006447
6448int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
6449 u8 action, ulong timeout)
Arend van Sprield3c0b632013-02-08 15:53:37 +01006450{
6451 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
6452
6453 return wait_event_timeout(event->vif_wq,
6454 vif_event_equals(event, action), timeout);
6455}
6456
Hante Meuleman73345fd2016-02-17 11:26:53 +01006457static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
6458 struct brcmf_fil_country_le *ccreq)
6459{
6460 struct cc_translate *country_codes;
6461 struct cc_entry *cc;
6462 s32 found_index;
6463 int i;
6464
6465 country_codes = drvr->settings->country_codes;
6466 if (!country_codes) {
6467 brcmf_dbg(TRACE, "No country codes configured for device\n");
6468 return -EINVAL;
6469 }
6470
6471 if ((alpha2[0] == ccreq->country_abbrev[0]) &&
6472 (alpha2[1] == ccreq->country_abbrev[1])) {
6473 brcmf_dbg(TRACE, "Country code already set\n");
6474 return -EAGAIN;
6475 }
6476
6477 found_index = -1;
6478 for (i = 0; i < country_codes->table_size; i++) {
6479 cc = &country_codes->table[i];
6480 if ((cc->iso3166[0] == '\0') && (found_index == -1))
6481 found_index = i;
6482 if ((cc->iso3166[0] == alpha2[0]) &&
6483 (cc->iso3166[1] == alpha2[1])) {
6484 found_index = i;
6485 break;
6486 }
6487 }
6488 if (found_index == -1) {
6489 brcmf_dbg(TRACE, "No country code match found\n");
6490 return -EINVAL;
6491 }
6492 memset(ccreq, 0, sizeof(*ccreq));
6493 ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
6494 memcpy(ccreq->ccode, country_codes->table[found_index].cc,
6495 BRCMF_COUNTRY_BUF_SZ);
6496 ccreq->country_abbrev[0] = alpha2[0];
6497 ccreq->country_abbrev[1] = alpha2[1];
6498 ccreq->country_abbrev[2] = 0;
6499
6500 return 0;
6501}
6502
Arend van Spriel63db1a42014-12-21 12:43:51 +01006503static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
6504 struct regulatory_request *req)
6505{
6506 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
6507 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
6508 struct brcmf_fil_country_le ccreq;
Hante Meuleman73345fd2016-02-17 11:26:53 +01006509 s32 err;
Arend van Spriel63db1a42014-12-21 12:43:51 +01006510 int i;
6511
Arend van Spriel63db1a42014-12-21 12:43:51 +01006512 /* ignore non-ISO3166 country codes */
6513 for (i = 0; i < sizeof(req->alpha2); i++)
6514 if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
Hante Meuleman73345fd2016-02-17 11:26:53 +01006515 brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
6516 req->alpha2[0], req->alpha2[1]);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006517 return;
6518 }
Hante Meuleman73345fd2016-02-17 11:26:53 +01006519
6520 brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
6521 req->alpha2[0], req->alpha2[1]);
6522
6523 err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
6524 if (err) {
6525 brcmf_err("Country code iovar returned err = %d\n", err);
6526 return;
6527 }
6528
6529 err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
6530 if (err)
6531 return;
6532
6533 err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
6534 if (err) {
6535 brcmf_err("Firmware rejected country setting\n");
Arend van Spriel8afe0ec2015-04-14 20:10:25 +02006536 return;
6537 }
6538 brcmf_setup_wiphybands(wiphy);
Arend van Spriel63db1a42014-12-21 12:43:51 +01006539}
6540
Arend van Sprielb48d8912014-07-12 08:49:41 +02006541static void brcmf_free_wiphy(struct wiphy *wiphy)
6542{
Arend van Spriel0882dda2015-08-20 22:06:03 +02006543 int i;
6544
Arend van Spriel58de92d2015-04-14 20:10:24 +02006545 if (!wiphy)
6546 return;
6547
Arend van Spriel0882dda2015-08-20 22:06:03 +02006548 if (wiphy->iface_combinations) {
6549 for (i = 0; i < wiphy->n_iface_combinations; i++)
6550 kfree(wiphy->iface_combinations[i].limits);
6551 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006552 kfree(wiphy->iface_combinations);
6553 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6554 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
6555 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
6556 }
6557 if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6558 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
6559 kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
6560 }
6561 wiphy_free(wiphy);
6562}
6563
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006564struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006565 struct device *busdev,
6566 bool p2pdev_forced)
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006567{
Arend van Spriel46f3b6e2015-08-26 22:14:58 +02006568 struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006569 struct brcmf_cfg80211_info *cfg;
6570 struct wiphy *wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006571 struct cfg80211_ops *ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006572 struct brcmf_cfg80211_vif *vif;
6573 struct brcmf_if *ifp;
6574 s32 err = 0;
6575 s32 io_type;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006576 u16 *cap = NULL;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006577
6578 if (!ndev) {
6579 brcmf_err("ndev is invalid\n");
6580 return NULL;
6581 }
6582
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006583 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
6584 if (!ops)
6585 return NULL;
6586
6587 memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006588 ifp = netdev_priv(ndev);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006589#ifdef CONFIG_PM
6590 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
6591 ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
6592#endif
6593 wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
Arend van Sprielb48d8912014-07-12 08:49:41 +02006594 if (!wiphy) {
6595 brcmf_err("Could not allocate wiphy device\n");
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006596 return NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006597 }
Rafał Miłecki6896f4f2015-05-31 02:52:26 +02006598 memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006599 set_wiphy_dev(wiphy, busdev);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006600
6601 cfg = wiphy_priv(wiphy);
6602 cfg->wiphy = wiphy;
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006603 cfg->ops = ops;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006604 cfg->pub = drvr;
6605 init_vif_event(&cfg->vif_event);
6606 INIT_LIST_HEAD(&cfg->vif_list);
6607
6608 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006609 if (IS_ERR(vif))
6610 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006611
6612 vif->ifp = ifp;
6613 vif->wdev.netdev = ndev;
6614 ndev->ieee80211_ptr = &vif->wdev;
6615 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
6616
6617 err = wl_init_priv(cfg);
6618 if (err) {
6619 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006620 brcmf_free_vif(vif);
6621 goto wiphy_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006622 }
6623 ifp->vif = vif;
6624
Arend van Sprielb48d8912014-07-12 08:49:41 +02006625 /* determine d11 io type before wiphy setup */
6626 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006627 if (err) {
Arend van Sprielb48d8912014-07-12 08:49:41 +02006628 brcmf_err("Failed to get D11 version (%d)\n", err);
6629 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006630 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006631 cfg->d11inf.io_type = (u8)io_type;
6632 brcmu_d11_attach(&cfg->d11inf);
6633
6634 err = brcmf_setup_wiphy(wiphy, ifp);
6635 if (err < 0)
6636 goto priv_out;
6637
6638 brcmf_dbg(INFO, "Registering custom regulatory\n");
Arend van Spriel63db1a42014-12-21 12:43:51 +01006639 wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006640 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6641 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
6642
6643 /* firmware defaults to 40MHz disabled in 2G band. We signal
6644 * cfg80211 here that we do and have it decide we can enable
6645 * it. But first check if device does support 2G operation.
6646 */
6647 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
6648 cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
6649 *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
6650 }
6651 err = wiphy_register(wiphy);
6652 if (err < 0) {
6653 brcmf_err("Could not register wiphy device (%d)\n", err);
6654 goto priv_out;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006655 }
6656
6657 /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
6658 * setup 40MHz in 2GHz band and enable OBSS scanning.
6659 */
Arend van Sprielb48d8912014-07-12 08:49:41 +02006660 if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
6661 err = brcmf_enable_bw40_2g(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006662 if (!err)
6663 err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
6664 BRCMF_OBSS_COEX_AUTO);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006665 else
6666 *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006667 }
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006668 /* p2p might require that "if-events" get processed by fweh. So
6669 * activate the already registered event handlers now and activate
6670 * the rest when initialization has completed. drvr->config needs to
6671 * be assigned before activating events.
6672 */
6673 drvr->config = cfg;
6674 err = brcmf_fweh_activate_events(ifp);
6675 if (err) {
6676 brcmf_err("FWEH activation failed (%d)\n", err);
6677 goto wiphy_unreg_out;
6678 }
Arend van Sprielb48d8912014-07-12 08:49:41 +02006679
Hante Meulemanae7c03f2015-09-18 22:08:08 +02006680 err = brcmf_p2p_attach(cfg, p2pdev_forced);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006681 if (err) {
6682 brcmf_err("P2P initilisation failed (%d)\n", err);
6683 goto wiphy_unreg_out;
6684 }
6685 err = brcmf_btcoex_attach(cfg);
6686 if (err) {
6687 brcmf_err("BT-coex initialisation failed (%d)\n", err);
6688 brcmf_p2p_detach(&cfg->p2p);
6689 goto wiphy_unreg_out;
6690 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006691
Hante Meulemana7b82d42015-12-10 13:43:04 +01006692 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
6693 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
6694 if (err) {
6695 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
6696 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
6697 } else {
6698 brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
6699 brcmf_notify_tdls_peer_event);
6700 }
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006701 }
6702
Hante Meuleman2b76acd2015-10-08 20:33:15 +02006703 /* (re-) activate FWEH event handling */
6704 err = brcmf_fweh_activate_events(ifp);
6705 if (err) {
6706 brcmf_err("FWEH activation failed (%d)\n", err);
6707 goto wiphy_unreg_out;
6708 }
6709
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006710 /* Fill in some of the advertised nl80211 supported features */
6711 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
6712 wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
6713#ifdef CONFIG_PM
Franky Lin6ea09152016-02-17 11:26:52 +01006714 if (wiphy->wowlan &&
6715 wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
Hante Meuleman48ed16e2016-01-02 09:41:38 +01006716 wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6717#endif
6718 }
6719
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006720 return cfg;
6721
Arend van Sprielb48d8912014-07-12 08:49:41 +02006722wiphy_unreg_out:
6723 wiphy_unregister(cfg->wiphy);
6724priv_out:
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006725 wl_deinit_priv(cfg);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006726 brcmf_free_vif(vif);
Hante Meuleman2b5d3482015-09-18 22:08:04 +02006727 ifp->vif = NULL;
Arend van Sprielb48d8912014-07-12 08:49:41 +02006728wiphy_out:
6729 brcmf_free_wiphy(wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006730 kfree(ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006731 return NULL;
6732}
6733
6734void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
6735{
6736 if (!cfg)
6737 return;
6738
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006739 brcmf_btcoex_detach(cfg);
Arend van Sprielf7a40872015-06-11 00:12:23 +02006740 wiphy_unregister(cfg->wiphy);
Hante Meuleman5c22fb82016-02-17 11:27:03 +01006741 kfree(cfg->ops);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006742 wl_deinit_priv(cfg);
Arend van Sprielb48d8912014-07-12 08:49:41 +02006743 brcmf_free_wiphy(cfg->wiphy);
Arend van Sprielccfd1e82014-07-12 08:49:38 +02006744}